diff options
author | bubulle <bubulle@alioth.debian.org> | 2010-04-06 18:12:47 +0000 |
---|---|---|
committer | bubulle <bubulle@alioth.debian.org> | 2010-04-06 18:12:47 +0000 |
commit | c038a4e9c09ba4ac77d885ac0afee418f41b8891 (patch) | |
tree | f5b2444727ff995f46dabbbf94863e9926501444 /source3/smbd | |
parent | 9e2f5a6ab663f7a111832217c527508c75ddae8a (diff) | |
download | samba-c038a4e9c09ba4ac77d885ac0afee418f41b8891.tar.gz |
Revert to 3.4.7...for now?
git-svn-id: svn://svn.debian.org/svn/pkg-samba/trunk/samba@3416 fc4039ab-9d04-0410-8cac-899223bdd6b0
Diffstat (limited to 'source3/smbd')
69 files changed, 6338 insertions, 17907 deletions
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c index 751fed168f..406ec1b3e3 100644 --- a/source3/smbd/aio.c +++ b/source3/smbd/aio.c @@ -25,6 +25,9 @@ /* The signal we'll use to signify aio done. */ #ifndef RT_SIGNAL_AIO +#ifndef SIGRTMIN +#define SIGRTMIN NSIG +#endif #define RT_SIGNAL_AIO (SIGRTMIN+3) #endif @@ -189,9 +192,10 @@ bool schedule_aio_read_and_X(connection_struct *conn, DEBUG(10,("schedule_aio_read_and_X: scheduled aio_read for file %s, " "offset %.0f, len = %u (mid = %u)\n", - fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt, + fsp->fsp_name, (double)startpos, (unsigned int)smb_maxcnt, (unsigned int)aio_ex->req->mid )); + srv_defer_sign_response(aio_ex->req->mid); return True; } @@ -241,7 +245,7 @@ bool schedule_aio_write_and_X(connection_struct *conn, DEBUG(10,("schedule_aio_write_and_X: failed to schedule " "aio_write for file %s, offset %.0f, len = %u " "(mid = %u)\n", - fsp_str_dbg(fsp), (double)startpos, + fsp->fsp_name, (double)startpos, (unsigned int)numtowrite, (unsigned int)req->mid )); return False; @@ -294,20 +298,21 @@ bool schedule_aio_write_and_X(connection_struct *conn, SSVAL(aio_ex->outbuf,smb_vwv4,(numtowrite>>16)&1); show_msg(aio_ex->outbuf); if (!srv_send_smb(smbd_server_fd(),aio_ex->outbuf, - true, aio_ex->req->seqnum+1, IS_CONN_ENCRYPTED(fsp->conn), &aio_ex->req->pcd)) { exit_server_cleanly("handle_aio_write: srv_send_smb " "failed."); } DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write " - "behind for file %s\n", fsp_str_dbg(fsp))); + "behind for file %s\n", fsp->fsp_name )); + } else { + srv_defer_sign_response(aio_ex->req->mid); } DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write for file " "%s, offset %.0f, len = %u (mid = %u) " "outstanding_aio_calls = %d\n", - fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite, + fsp->fsp_name, (double)startpos, (unsigned int)numtowrite, (unsigned int)aio_ex->req->mid, outstanding_aio_calls )); return True; @@ -321,6 +326,7 @@ bool schedule_aio_write_and_X(connection_struct *conn, static int handle_aio_read_complete(struct aio_extra *aio_ex, int errcode) { + int ret = 0; int outsize; char *outbuf = aio_ex->outbuf; char *data = smb_buf(outbuf); @@ -332,11 +338,12 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex, int errcode) will return an error. Hopefully this is true.... JRA. */ - DEBUG( 3,( "handle_aio_read_complete: file %s nread == %d. " + DEBUG( 3,( "handle_aio_read_complete: file %s nread == %d " "Error = %s\n", - fsp_str_dbg(aio_ex->fsp), (int)nread, strerror(errcode))); + aio_ex->fsp->fsp_name, (int)nread, strerror(errcode) )); - ERROR_NT(map_nt_error_from_unix(errcode)); + ret = errcode; + ERROR_NT(map_nt_error_from_unix( ret)); outsize = srv_set_message(outbuf,0,0,true); } else { outsize = srv_set_message(outbuf,12,nread,False); @@ -351,14 +358,13 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex, int errcode) DEBUG( 3, ( "handle_aio_read_complete file %s max=%d " "nread=%d\n", - fsp_str_dbg(aio_ex->fsp), + aio_ex->fsp->fsp_name, (int)aio_ex->acb.aio_nbytes, (int)nread ) ); } smb_setlen(outbuf,outsize - 4); show_msg(outbuf); if (!srv_send_smb(smbd_server_fd(),outbuf, - true, aio_ex->req->seqnum+1, IS_CONN_ENCRYPTED(aio_ex->fsp->conn), NULL)) { exit_server_cleanly("handle_aio_read_complete: srv_send_smb " "failed."); @@ -366,10 +372,10 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex, int errcode) DEBUG(10,("handle_aio_read_complete: scheduled aio_read completed " "for file %s, offset %.0f, len = %u\n", - fsp_str_dbg(aio_ex->fsp), (double)aio_ex->acb.aio_offset, + aio_ex->fsp->fsp_name, (double)aio_ex->acb.aio_offset, (unsigned int)nread )); - return errcode; + return ret; } /**************************************************************************** @@ -379,6 +385,7 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex, int errcode) static int handle_aio_write_complete(struct aio_extra *aio_ex, int errcode) { + int ret = 0; files_struct *fsp = aio_ex->fsp; char *outbuf = aio_ex->outbuf; ssize_t numtowrite = aio_ex->acb.aio_nbytes; @@ -390,20 +397,21 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex, int errcode) DEBUG(5,("handle_aio_write_complete: " "aio_write_behind failed ! File %s " "is corrupt ! Error %s\n", - fsp_str_dbg(fsp), strerror(errcode))); + fsp->fsp_name, strerror(errcode) )); + ret = errcode; } else { DEBUG(0,("handle_aio_write_complete: " "aio_write_behind failed ! File %s " "is corrupt ! Wanted %u bytes but " - "only wrote %d\n", fsp_str_dbg(fsp), + "only wrote %d\n", fsp->fsp_name, (unsigned int)numtowrite, (int)nwritten )); - errcode = EIO; + ret = EIO; } } else { DEBUG(10,("handle_aio_write_complete: " "aio_write_behind completed for file %s\n", - fsp_str_dbg(fsp))); + fsp->fsp_name )); } /* TODO: should no return 0 in case of an error !!! */ return 0; @@ -415,10 +423,11 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex, int errcode) if(nwritten == -1) { DEBUG( 3,( "handle_aio_write: file %s wanted %u bytes. " "nwritten == %d. Error = %s\n", - fsp_str_dbg(fsp), (unsigned int)numtowrite, - (int)nwritten, strerror(errcode) )); + fsp->fsp_name, (unsigned int)numtowrite, + (int)nwritten, strerror(errno) )); - ERROR_NT(map_nt_error_from_unix(errcode)); + ret = errcode; + ERROR_NT(map_nt_error_from_unix(ret)); srv_set_message(outbuf,0,0,true); } else { bool write_through = BITSETW(aio_ex->req->vwv+7,0); @@ -435,31 +444,29 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex, int errcode) fsp->fnum, (int)numtowrite, (int)nwritten)); status = sync_file(fsp->conn,fsp, write_through); if (!NT_STATUS_IS_OK(status)) { - errcode = errno; - ERROR_BOTH(map_nt_error_from_unix(errcode), + ret = errno; + ERROR_BOTH(map_nt_error_from_unix(ret), ERRHRD, ERRdiskfull); srv_set_message(outbuf,0,0,true); DEBUG(5,("handle_aio_write: sync_file for %s returned %s\n", - fsp_str_dbg(fsp), nt_errstr(status))); + fsp->fsp_name, nt_errstr(status) )); } aio_ex->fsp->fh->pos = aio_ex->acb.aio_offset + nwritten; } show_msg(outbuf); - if (!srv_send_smb(smbd_server_fd(),outbuf, - true, aio_ex->req->seqnum+1, - IS_CONN_ENCRYPTED(fsp->conn), + if (!srv_send_smb(smbd_server_fd(),outbuf,IS_CONN_ENCRYPTED(fsp->conn), NULL)) { exit_server_cleanly("handle_aio_write: srv_send_smb failed."); } DEBUG(10,("handle_aio_write_complete: scheduled aio_write completed " "for file %s, offset %.0f, requested %u, written = %u\n", - fsp_str_dbg(fsp), (double)aio_ex->acb.aio_offset, + fsp->fsp_name, (double)aio_ex->acb.aio_offset, (unsigned int)numtowrite, (unsigned int)nwritten )); - return errcode; + return ret; } /**************************************************************************** @@ -481,13 +488,14 @@ static bool handle_aio_completed(struct aio_extra *aio_ex, int *perr) if (err == EINPROGRESS) { DEBUG(10,( "handle_aio_completed: operation mid %u still in " "process for file %s\n", - aio_ex->req->mid, fsp_str_dbg(aio_ex->fsp))); + aio_ex->req->mid, aio_ex->fsp->fsp_name )); return False; } else if (err == ECANCELED) { /* If error is ECANCELED then don't return anything to the * client. */ DEBUG(10,( "handle_aio_completed: operation mid %u" " canceled\n", aio_ex->req->mid)); + srv_cancel_sign_response(aio_ex->req->mid, false); return True; } @@ -516,6 +524,7 @@ void smbd_aio_complete_mid(unsigned int mid) if (!aio_ex) { DEBUG(3,("smbd_aio_complete_mid: Can't find record to " "match mid %u.\n", mid)); + srv_cancel_sign_response(mid, false); return; } @@ -525,6 +534,7 @@ void smbd_aio_complete_mid(unsigned int mid) * ignore. */ DEBUG( 3,( "smbd_aio_complete_mid: file closed whilst " "aio outstanding (mid[%u]).\n", mid)); + srv_cancel_sign_response(mid, false); return; } diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index e33c0b6ae5..0eeb0b5221 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -185,7 +185,7 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck, count, lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK, blr->lock_flav, - True, + lock_timeout ? True : False, /* blocking_lock. */ NULL, blr); @@ -212,7 +212,10 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck, "expiry time (%u sec. %u usec) (+%d msec) for fnum = %d, name = %s\n", (unsigned int)blr->expire_time.tv_sec, (unsigned int)blr->expire_time.tv_usec, lock_timeout, - blr->fsp->fnum, fsp_str_dbg(blr->fsp))); + blr->fsp->fnum, blr->fsp->fsp_name )); + + /* Push the MID of this packet on the signing queue. */ + srv_defer_sign_response(blr->req->mid); return True; } @@ -267,7 +270,6 @@ static void generic_blocking_lock_error(struct blocking_lock_record *blr, NTSTAT 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."); } @@ -351,7 +353,6 @@ static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS 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: " @@ -428,9 +429,8 @@ static bool process_lockingX(struct blocking_lock_record *blr) * Success - we got all the locks. */ - DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d " - "num_locks=%d\n", fsp_str_dbg(fsp), fsp->fnum, - (unsigned int)locktype, num_locks)); + DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n", + fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) ); reply_lockingX_success(blr); return True; @@ -453,7 +453,7 @@ static bool process_lockingX(struct blocking_lock_record *blr) DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \ Waiting....\n", - blr->lock_num, num_locks, fsp_str_dbg(fsp), fsp->fnum)); + blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum)); return False; } @@ -544,7 +544,7 @@ void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lo DEBUG(10, ("remove_pending_lock_requests_by_fid - removing " "request type %d for file %s fnum = %d\n", - blr->req->cmd, fsp_str_dbg(fsp), fsp->fnum)); + blr->req->cmd, fsp->fsp_name, fsp->fnum)); blr_cancelled = blocking_lock_cancel(fsp, blr->lock_pid, @@ -594,7 +594,7 @@ void remove_pending_lock_requests_by_mid(int mid) if (br_lck) { DEBUG(10, ("remove_pending_lock_requests_by_mid - " "removing request type %d for file %s fnum " - "= %d\n", blr->req->cmd, fsp_str_dbg(fsp), + "= %d\n", blr->req->cmd, fsp->fsp_name, fsp->fnum )); brl_lock_cancel(br_lck, @@ -720,7 +720,7 @@ void process_blocking_lock_queue(void) DEBUG(5,("process_blocking_lock_queue: " "pending lock fnum = %d for file %s " "timed out.\n", blr->fsp->fnum, - fsp_str_dbg(blr->fsp))); + blr->fsp->fsp_name )); brl_lock_cancel(br_lck, blr->lock_pid, diff --git a/source3/smbd/change_trust_pw.c b/source3/smbd/change_trust_pw.c index ec3046e0d2..72a72a78b5 100644 --- a/source3/smbd/change_trust_pw.c +++ b/source3/smbd/change_trust_pw.c @@ -92,7 +92,7 @@ NTSTATUS change_trust_account_password( const char *domain, const char *remote_m failed: if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("%s : change_trust_account_password: Failed to change password for domain %s.\n", - current_timestring(talloc_tos(), False), domain)); + current_timestring(debug_ctx(), False), domain)); } else DEBUG(5,("change_trust_account_password: sucess!\n")); diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index 074c51ddf2..61c3afb0dc 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -46,7 +46,6 @@ */ #include "includes.h" -#include "../libcli/auth/libcli_auth.h" static NTSTATUS check_oem_password(const char *user, uchar password_encrypted_with_lm_hash[516], @@ -850,7 +849,7 @@ static NTSTATUS check_oem_password(const char *user, const uint8 *encryption_key; const uint8 *lanman_pw, *nt_pw; uint32 acct_ctrl; - size_t new_pw_len; + uint32 new_pw_len; uchar new_nt_hash[16]; uchar new_lm_hash[16]; uchar verifier[16]; @@ -919,13 +918,13 @@ static NTSTATUS check_oem_password(const char *user, /* * Decrypt the password with the key */ - arcfour_crypt( password_encrypted, encryption_key, 516); + SamOEMhash( password_encrypted, encryption_key, 516); if (!decode_pw_buffer(talloc_tos(), password_encrypted, pp_new_passwd, &new_pw_len, - nt_pass_set ? CH_UTF16 : CH_DOS)) { + nt_pass_set ? STR_UNICODE : STR_ASCII)) { return NT_STATUS_WRONG_PASSWORD; } @@ -1008,59 +1007,6 @@ static NTSTATUS check_oem_password(const char *user, return NT_STATUS_WRONG_PASSWORD; } -bool password_in_history(uint8_t nt_pw[NT_HASH_LEN], - uint32_t pw_history_len, - const uint8_t *pw_history) -{ - static const uint8_t zero_md5_nt_pw[SALTED_MD5_HASH_LEN] = { 0, }; - int i; - - dump_data(100, nt_pw, NT_HASH_LEN); - dump_data(100, pw_history, PW_HISTORY_ENTRY_LEN * pw_history_len); - - for (i=0; i<pw_history_len; i++) { - uint8_t new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN]; - const uint8_t *current_salt; - const uint8_t *old_nt_pw_salted_md5_hash; - - current_salt = &pw_history[i*PW_HISTORY_ENTRY_LEN]; - old_nt_pw_salted_md5_hash = current_salt + PW_HISTORY_SALT_LEN; - - if (memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash, - SALTED_MD5_HASH_LEN) == 0) { - /* Ignore zero valued entries. */ - continue; - } - - if (memcmp(zero_md5_nt_pw, current_salt, - PW_HISTORY_SALT_LEN) == 0) - { - /* - * New format: zero salt and then plain nt hash. - * Directly compare the hashes. - */ - if (memcmp(nt_pw, old_nt_pw_salted_md5_hash, - SALTED_MD5_HASH_LEN) == 0) - { - return true; - } - } else { - /* - * Old format: md5sum of salted nt hash. - * Create salted version of new pw to compare. - */ - E_md5hash(current_salt, nt_pw, new_nt_pw_salted_md5_hash); - - if (memcmp(new_nt_pw_salted_md5_hash, - old_nt_pw_salted_md5_hash, - SALTED_MD5_HASH_LEN) == 0) { - return true; - } - } - } - return false; -} - /*********************************************************** This routine takes the given password and checks it against the password history. Returns True if this password has been @@ -1070,11 +1016,14 @@ bool password_in_history(uint8_t nt_pw[NT_HASH_LEN], static bool check_passwd_history(struct samu *sampass, const char *plaintext) { uchar new_nt_p16[NT_HASH_LEN]; + uchar zero_md5_nt_pw[SALTED_MD5_HASH_LEN]; const uint8 *nt_pw; const uint8 *pwhistory; + bool found = False; + int i; uint32 pwHisLen, curr_pwHisLen; - pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHisLen); + pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen); if (pwHisLen == 0) { return False; } @@ -1098,13 +1047,30 @@ static bool check_passwd_history(struct samu *sampass, const char *plaintext) return True; } - if (password_in_history(new_nt_p16, pwHisLen, pwhistory)) { - DEBUG(1,("check_passwd_history: proposed new password for " - "user %s found in history list !\n", - pdb_get_username(sampass) )); - return true; + dump_data(100, new_nt_p16, NT_HASH_LEN); + dump_data(100, pwhistory, PW_HISTORY_ENTRY_LEN*pwHisLen); + + memset(zero_md5_nt_pw, '\0', SALTED_MD5_HASH_LEN); + for (i=0; i<pwHisLen; i++) { + uchar new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN]; + const uchar *current_salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN]; + const uchar *old_nt_pw_salted_md5_hash = &pwhistory[(i*PW_HISTORY_ENTRY_LEN)+ + PW_HISTORY_SALT_LEN]; + if (!memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) { + /* Ignore zero valued entries. */ + continue; + } + /* Create salted versions of new to compare. */ + E_md5hash(current_salt, new_nt_p16, new_nt_pw_salted_md5_hash); + + if (!memcmp(new_nt_pw_salted_md5_hash, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) { + DEBUG(1,("check_passwd_history: proposed new password for user %s found in history list !\n", + pdb_get_username(sampass) )); + found = True; + break; + } } - return false; + return found; } /*********************************************************** @@ -1118,7 +1084,6 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw { uint32 min_len; uint32 refuse; - TALLOC_CTX *tosctx = talloc_tos(); struct passwd *pass = NULL; const char *username = pdb_get_username(hnd); time_t can_change_time = pdb_get_pass_can_change_time(hnd); @@ -1140,7 +1105,7 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw * denies machines to change the password. * * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */ if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) { - if (pdb_get_account_policy(PDB_POLICY_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) { + if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) { DEBUG(1, ("Machine %s cannot change password now, " "denied by Refuse Machine Password Change policy\n", username)); @@ -1151,19 +1116,19 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw } } - /* removed calculation here, because passdb now calculates + /* removed calculation here, becuase passdb now calculates based on policy. jmcd */ if ((can_change_time != 0) && (time(NULL) < can_change_time)) { DEBUG(1, ("user %s cannot change password now, must " "wait until %s\n", username, - http_timestring(tosctx, can_change_time))); + http_timestring(talloc_tos(), can_change_time))); if (samr_reject_reason) { *samr_reject_reason = SAMR_REJECT_OTHER; } return NT_STATUS_ACCOUNT_RESTRICTION; } - if (pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) { + if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) { DEBUG(1, ("user %s cannot change password - password too short\n", username)); DEBUGADD(1, (" account policy min password len = %d\n", min_len)); @@ -1181,7 +1146,7 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw return NT_STATUS_PASSWORD_RESTRICTION; } - pass = Get_Pwnam_alloc(tosctx, username); + pass = Get_Pwnam_alloc(talloc_tos(), username); if (!pass) { DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username)); return NT_STATUS_ACCESS_DENIED; @@ -1190,16 +1155,9 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw /* Use external script to check password complexity */ if (lp_check_password_script() && *(lp_check_password_script())) { int check_ret; - char *cmd; - - cmd = talloc_string_sub(tosctx, lp_check_password_script(), "%u", username); - if (!cmd) { - return NT_STATUS_PASSWORD_RESTRICTION; - } - check_ret = smbrunsecret(cmd, new_passwd); - DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", cmd, check_ret)); - TALLOC_FREE(cmd); + check_ret = smbrunsecret(lp_check_password_script(), new_passwd); + DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret)); if (check_ret != 0) { DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n")); diff --git a/source3/smbd/close.c b/source3/smbd/close.c index ca1ac47fa0..d23b509af2 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -27,7 +27,7 @@ extern struct current_user current_user; Run a file if it is a magic script. ****************************************************************************/ -static NTSTATUS check_magic(struct files_struct *fsp) +static void check_magic(struct files_struct *fsp) { int ret; const char *magic_output = NULL; @@ -36,99 +36,77 @@ static NTSTATUS check_magic(struct files_struct *fsp) TALLOC_CTX *ctx = NULL; const char *p; struct connection_struct *conn = fsp->conn; - char *fname = NULL; - NTSTATUS status; if (!*lp_magicscript(SNUM(conn))) { - return NT_STATUS_OK; + return; } - DEBUG(5,("checking magic for %s\n", fsp_str_dbg(fsp))); - - ctx = talloc_stackframe(); - - fname = fsp->fsp_name->base_name; + DEBUG(5,("checking magic for %s\n",fsp->fsp_name)); - if (!(p = strrchr_m(fname,'/'))) { - p = fname; + if (!(p = strrchr_m(fsp->fsp_name,'/'))) { + p = fsp->fsp_name; } else { p++; } if (!strequal(lp_magicscript(SNUM(conn)),p)) { - status = NT_STATUS_OK; - goto out; + return; } + ctx = talloc_stackframe(); + if (*lp_magicoutput(SNUM(conn))) { magic_output = lp_magicoutput(SNUM(conn)); } else { magic_output = talloc_asprintf(ctx, "%s.out", - fname); + fsp->fsp_name); } if (!magic_output) { - status = NT_STATUS_NO_MEMORY; - goto out; + TALLOC_FREE(ctx); + return; } /* Ensure we don't depend on user's PATH. */ - p = talloc_asprintf(ctx, "./%s", fname); + p = talloc_asprintf(ctx, "./%s", fsp->fsp_name); if (!p) { - status = NT_STATUS_NO_MEMORY; - goto out; + TALLOC_FREE(ctx); + return; } - if (chmod(fname, 0755) == -1) { - status = map_nt_error_from_unix(errno); - goto out; + if (chmod(fsp->fsp_name,0755) == -1) { + TALLOC_FREE(ctx); + return; } ret = smbrun(p,&tmp_fd); DEBUG(3,("Invoking magic command %s gave %d\n", p,ret)); - unlink(fname); + unlink(fsp->fsp_name); if (ret != 0 || tmp_fd == -1) { if (tmp_fd != -1) { close(tmp_fd); } - status = NT_STATUS_UNSUCCESSFUL; - goto out; + TALLOC_FREE(ctx); + return; } outfd = open(magic_output, O_CREAT|O_EXCL|O_RDWR, 0600); if (outfd == -1) { - int err = errno; close(tmp_fd); - status = map_nt_error_from_unix(err); - goto out; + TALLOC_FREE(ctx); + return; } - if (sys_fstat(tmp_fd, &st, false) == -1) { - int err = errno; + if (sys_fstat(tmp_fd,&st) == -1) { close(tmp_fd); close(outfd); - status = map_nt_error_from_unix(err); - goto out; + return; } - if (transfer_file(tmp_fd,outfd,(SMB_OFF_T)st.st_ex_size) == (SMB_OFF_T)-1) { - int err = errno; - close(tmp_fd); - close(outfd); - status = map_nt_error_from_unix(err); - goto out; - } + transfer_file(tmp_fd,outfd,(SMB_OFF_T)st.st_size); close(tmp_fd); - if (close(outfd) == -1) { - status = map_nt_error_from_unix(errno); - goto out; - } - - status = NT_STATUS_OK; - - out: + close(outfd); TALLOC_FREE(ctx); - return status; } /**************************************************************************** @@ -226,32 +204,31 @@ NTSTATUS delete_all_streams(connection_struct *conn, const char *fname) for (i=0; i<num_streams; i++) { int res; - struct smb_filename *smb_fname_stream = NULL; + char *streamname; if (strequal(stream_info[i].name, "::$DATA")) { continue; } - status = create_synthetic_smb_fname(talloc_tos(), fname, - stream_info[i].name, NULL, - &smb_fname_stream); + streamname = talloc_asprintf(talloc_tos(), "%s%s", fname, + stream_info[i].name); - if (!NT_STATUS_IS_OK(status)) { + if (streamname == NULL) { DEBUG(0, ("talloc_aprintf failed\n")); + status = NT_STATUS_NO_MEMORY; goto fail; } - res = SMB_VFS_UNLINK(conn, smb_fname_stream); + res = SMB_VFS_UNLINK(conn, streamname); + + TALLOC_FREE(streamname); if (res == -1) { status = map_nt_error_from_unix(errno); DEBUG(10, ("Could not delete stream %s: %s\n", - smb_fname_str_dbg(smb_fname_stream), - strerror(errno))); - TALLOC_FREE(smb_fname_stream); + streamname, strerror(errno))); break; } - TALLOC_FREE(smb_fname_stream); } fail: @@ -269,19 +246,12 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, connection_struct *conn = fsp->conn; bool delete_file = false; bool changed_user = false; - struct share_mode_lock *lck = NULL; + struct share_mode_lock *lck; + SMB_STRUCT_STAT sbuf; NTSTATUS status = NT_STATUS_OK; - NTSTATUS tmp_status; + int ret; struct file_id id; - /* Ensure any pending write time updates are done. */ - if (fsp->update_write_time_event) { - update_write_time_handler(smbd_event_context(), - fsp->update_write_time_event, - timeval_current(), - (void *)fsp); - } - /* * Lock the share entries, and determine if we should delete * on close. If so delete whilst the lock is still in effect. @@ -293,37 +263,17 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, if (lck == NULL) { DEBUG(0, ("close_remove_share_mode: Could not get share mode " - "lock for file %s\n", fsp_str_dbg(fsp))); - status = NT_STATUS_INVALID_PARAMETER; - goto done; + "lock for file %s\n", fsp->fsp_name)); + return NT_STATUS_INVALID_PARAMETER; } if (fsp->write_time_forced) { - DEBUG(10,("close_remove_share_mode: write time forced " - "for file %s\n", - fsp_str_dbg(fsp))); set_close_write_time(fsp, lck->changed_write_time); - } else if (fsp->update_write_time_on_close) { - /* Someone had a pending write. */ - if (null_timespec(fsp->close_write_time)) { - DEBUG(10,("close_remove_share_mode: update to current time " - "for file %s\n", - fsp_str_dbg(fsp))); - /* Update to current time due to "normal" write. */ - set_close_write_time(fsp, timespec_current()); - } else { - DEBUG(10,("close_remove_share_mode: write time pending " - "for file %s\n", - fsp_str_dbg(fsp))); - /* Update to time set on close call. */ - set_close_write_time(fsp, fsp->close_write_time); - } } if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_remove_share_mode: Could not delete share " - "entry for file %s\n", - fsp_str_dbg(fsp))); + "entry for file %s\n", fsp->fsp_name)); } if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) { @@ -336,7 +286,6 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, become_user(conn, fsp->vuid); became_user = True; } - fsp->delete_on_close = true; set_delete_on_close_lck(lck, True, ¤t_user.ut); if (became_user) { unbecome_user(); @@ -382,7 +331,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, */ DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set " - "- deleting file.\n", fsp_str_dbg(fsp))); + "- deleting file.\n", fsp->fsp_name)); /* * Don't try to update the write time when we delete the file @@ -394,7 +343,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, DEBUG(5,("close_remove_share_mode: file %s. " "Change user to uid %u\n", - fsp_str_dbg(fsp), + fsp->fsp_name, (unsigned int)lck->delete_token->uid)); if (!push_sec_ctx()) { @@ -414,26 +363,31 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, /* We can only delete the file if the name we have is still valid and hasn't been renamed. */ - tmp_status = vfs_stat_fsp(fsp); - if (!NT_STATUS_IS_OK(tmp_status)) { + if (fsp->posix_open) { + ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf); + } else { + ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf); + } + + if (ret != 0) { DEBUG(5,("close_remove_share_mode: file %s. Delete on close " "was set and stat failed with error %s\n", - fsp_str_dbg(fsp), nt_errstr(tmp_status))); + fsp->fsp_name, strerror(errno) )); /* * Don't save the errno here, we ignore this error */ goto done; } - id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st); + id = vfs_file_id_from_sbuf(conn, &sbuf); if (!file_id_equal(&fsp->file_id, &id)) { DEBUG(5,("close_remove_share_mode: file %s. Delete on close " "was set and dev and/or inode does not match\n", - fsp_str_dbg(fsp))); + fsp->fsp_name )); DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, " "stat file_id %s\n", - fsp_str_dbg(fsp), + fsp->fsp_name, file_id_string_tos(&fsp->file_id), file_id_string_tos(&id))); /* @@ -443,9 +397,9 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, } if ((conn->fs_capabilities & FILE_NAMED_STREAMS) - && !is_ntfs_stream_smb_fname(fsp->fsp_name)) { + && !is_ntfs_stream_name(fsp->fsp_name)) { - status = delete_all_streams(conn, fsp->fsp_name->base_name); + status = delete_all_streams(conn, fsp->fsp_name); if (!NT_STATUS_IS_OK(status)) { DEBUG(5, ("delete_all_streams failed: %s\n", @@ -455,7 +409,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, } - if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) { + if (SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) { /* * This call can potentially fail as another smbd may * have had the file open with delete on close set and @@ -466,14 +420,14 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, DEBUG(5,("close_remove_share_mode: file %s. Delete on close " "was set and unlink failed with error %s\n", - fsp_str_dbg(fsp), strerror(errno))); + fsp->fsp_name, strerror(errno) )); status = map_nt_error_from_unix(errno); } notify_fname(conn, NOTIFY_ACTION_REMOVED, FILE_NOTIFY_CHANGE_FILE_NAME, - fsp->fsp_name->base_name); + fsp->fsp_name); /* As we now have POSIX opens which can unlink * with other open files we may have taken @@ -482,7 +436,6 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, * the delete on close flag. JRA. */ - fsp->delete_on_close = false; set_delete_on_close_lck(lck, False, NULL); done: @@ -503,17 +456,24 @@ void set_close_write_time(struct files_struct *fsp, struct timespec ts) if (null_timespec(ts)) { return; } + /* + * if the write time on close is explict set, then don't + * need to fix it up to the value in the locking db + */ fsp->write_time_forced = false; + fsp->update_write_time_on_close = true; fsp->close_write_time = ts; } static NTSTATUS update_write_time_on_close(struct files_struct *fsp) { + SMB_STRUCT_STAT sbuf; struct smb_file_time ft; NTSTATUS status; - struct share_mode_lock *lck = NULL; + int ret = -1; + ZERO_STRUCT(sbuf); ZERO_STRUCT(ft); if (!fsp->update_write_time_on_close) { @@ -525,45 +485,33 @@ static NTSTATUS update_write_time_on_close(struct files_struct *fsp) } /* Ensure we have a valid stat struct for the source. */ - status = vfs_stat_fsp(fsp); - if (!NT_STATUS_IS_OK(status)) { - return status; + if (fsp->fh->fd != -1) { + ret = SMB_VFS_FSTAT(fsp, &sbuf); + } else { + if (fsp->posix_open) { + ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name,&sbuf); + } else { + ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name,&sbuf); + } } - if (!VALID_STAT(fsp->fsp_name->st)) { - /* if it doesn't seem to be a real file */ - return NT_STATUS_OK; + if (ret == -1) { + return map_nt_error_from_unix(errno); } - /* On close if we're changing the real file time we - * must update it in the open file db too. */ - (void)set_write_time(fsp->file_id, fsp->close_write_time); - - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, NULL); - if (lck) { - /* Close write times overwrite sticky write times - so we must replace any sticky write time here. */ - if (!null_timespec(lck->changed_write_time)) { - (void)set_sticky_write_time(fsp->file_id, fsp->close_write_time); - } - TALLOC_FREE(lck); + if (!VALID_STAT(sbuf)) { + /* if it doesn't seem to be a real file */ + return NT_STATUS_OK; } ft.mtime = fsp->close_write_time; - status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false); + status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, + &sbuf, &ft, true); if (!NT_STATUS_IS_OK(status)) { return status; } - return status; -} - -static NTSTATUS ntstatus_keeperror(NTSTATUS s1, NTSTATUS s2) -{ - if (!NT_STATUS_IS_OK(s1)) { - return s1; - } - return s2; + return NT_STATUS_OK; } /**************************************************************************** @@ -578,7 +526,10 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp, enum file_close_type close_type) { NTSTATUS status = NT_STATUS_OK; - NTSTATUS tmp; + NTSTATUS saved_status1 = NT_STATUS_OK; + NTSTATUS saved_status2 = NT_STATUS_OK; + NTSTATUS saved_status3 = NT_STATUS_OK; + NTSTATUS saved_status4 = NT_STATUS_OK; connection_struct *conn = fsp->conn; if (fsp->aio_write_behind) { @@ -588,8 +539,7 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp, */ int ret = wait_for_aio_completion(fsp); if (ret) { - status = ntstatus_keeperror( - status, map_nt_error_from_unix(ret)); + saved_status1 = map_nt_error_from_unix(ret); } } else { cancel_aio_by_fsp(fsp); @@ -600,8 +550,7 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp, * error here, we must remember this. */ - tmp = close_filestruct(fsp); - status = ntstatus_keeperror(status, tmp); + saved_status2 = close_filestruct(fsp); if (fsp->print_file) { print_fsp_end(fsp, close_type); @@ -620,301 +569,51 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp, if (fsp->fh->ref_count == 1) { /* Should we return on error here... ? */ - tmp = close_remove_share_mode(fsp, close_type); - status = ntstatus_keeperror(status, tmp); + saved_status3 = close_remove_share_mode(fsp, close_type); } locking_close_file(smbd_messaging_context(), fsp); - tmp = fd_close(fsp); - status = ntstatus_keeperror(status, tmp); + status = fd_close(fsp); /* check for magic scripts */ if (close_type == NORMAL_CLOSE) { - tmp = check_magic(fsp); - status = ntstatus_keeperror(status, tmp); + check_magic(fsp); } /* * Ensure pending modtime is set after close. */ - tmp = update_write_time_on_close(fsp); - if (NT_STATUS_EQUAL(tmp, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + saved_status4 = update_write_time_on_close(fsp); + if (NT_STATUS_EQUAL(saved_status4, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { /* Someone renamed the file or a parent directory containing * this file. We can't do anything about this, we don't have * an "update timestamp by fd" call in POSIX. Eat the error. */ - tmp = NT_STATUS_OK; + saved_status4 = NT_STATUS_OK; } - status = ntstatus_keeperror(status, tmp); + if (NT_STATUS_IS_OK(status)) { + if (!NT_STATUS_IS_OK(saved_status1)) { + status = saved_status1; + } else if (!NT_STATUS_IS_OK(saved_status2)) { + status = saved_status2; + } else if (!NT_STATUS_IS_OK(saved_status3)) { + status = saved_status3; + } else if (!NT_STATUS_IS_OK(saved_status4)) { + status = saved_status4; + } + } DEBUG(2,("%s closed file %s (numopen=%d) %s\n", - conn->server_info->unix_name, fsp_str_dbg(fsp), + conn->server_info->unix_name,fsp->fsp_name, conn->num_files_open - 1, nt_errstr(status) )); file_free(req, fsp); return status; } -/**************************************************************************** - Static function used by reply_rmdir to delete an entire directory - tree recursively. Return True on ok, False on fail. -****************************************************************************/ - -static bool recursive_rmdir(TALLOC_CTX *ctx, - connection_struct *conn, - struct smb_filename *smb_dname) -{ - const char *dname = NULL; - char *talloced = NULL; - bool ret = True; - long offset = 0; - SMB_STRUCT_STAT st; - struct smb_Dir *dir_hnd; - - SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname)); - - dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0); - if(dir_hnd == NULL) - return False; - - while((dname = ReadDirName(dir_hnd, &offset, &st, &talloced))) { - struct smb_filename *smb_dname_full = NULL; - char *fullname = NULL; - bool do_break = true; - NTSTATUS status; - - if (ISDOT(dname) || ISDOTDOT(dname)) { - TALLOC_FREE(talloced); - continue; - } - - if (!is_visible_file(conn, smb_dname->base_name, dname, &st, - false)) { - TALLOC_FREE(talloced); - continue; - } - - /* Construct the full name. */ - fullname = talloc_asprintf(ctx, - "%s/%s", - smb_dname->base_name, - dname); - if (!fullname) { - errno = ENOMEM; - goto err_break; - } - - status = create_synthetic_smb_fname(talloc_tos(), fullname, - NULL, NULL, - &smb_dname_full); - if (!NT_STATUS_IS_OK(status)) { - goto err_break; - } - - if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) { - goto err_break; - } - - if(smb_dname_full->st.st_ex_mode & S_IFDIR) { - if(!recursive_rmdir(ctx, conn, smb_dname_full)) { - goto err_break; - } - if(SMB_VFS_RMDIR(conn, - smb_dname_full->base_name) != 0) { - goto err_break; - } - } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) { - goto err_break; - } - - /* Successful iteration. */ - do_break = false; - - err_break: - TALLOC_FREE(smb_dname_full); - TALLOC_FREE(fullname); - TALLOC_FREE(talloced); - if (do_break) { - ret = false; - break; - } - } - TALLOC_FREE(dir_hnd); - return ret; -} - -/**************************************************************************** - The internals of the rmdir code - called elsewhere. -****************************************************************************/ - -static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp) -{ - connection_struct *conn = fsp->conn; - struct smb_filename *smb_dname = fsp->fsp_name; - int ret; - - SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname)); - - /* Might be a symlink. */ - if(SMB_VFS_LSTAT(conn, smb_dname) != 0) { - return map_nt_error_from_unix(errno); - } - - if (S_ISLNK(smb_dname->st.st_ex_mode)) { - /* Is what it points to a directory ? */ - if(SMB_VFS_STAT(conn, smb_dname) != 0) { - return map_nt_error_from_unix(errno); - } - if (!(S_ISDIR(smb_dname->st.st_ex_mode))) { - return NT_STATUS_NOT_A_DIRECTORY; - } - ret = SMB_VFS_UNLINK(conn, smb_dname); - } else { - ret = SMB_VFS_RMDIR(conn, smb_dname->base_name); - } - if (ret == 0) { - notify_fname(conn, NOTIFY_ACTION_REMOVED, - FILE_NOTIFY_CHANGE_DIR_NAME, - smb_dname->base_name); - return NT_STATUS_OK; - } - - if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) { - /* - * Check to see if the only thing in this directory are - * vetoed files/directories. If so then delete them and - * retry. If we fail to delete any of them (and we *don't* - * do a recursive delete) then fail the rmdir. - */ - SMB_STRUCT_STAT st; - const char *dname = NULL; - char *talloced = NULL; - long dirpos = 0; - struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, - smb_dname->base_name, NULL, - 0); - - if(dir_hnd == NULL) { - errno = ENOTEMPTY; - goto err; - } - - while ((dname = ReadDirName(dir_hnd, &dirpos, &st, - &talloced)) != NULL) { - if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) { - TALLOC_FREE(talloced); - continue; - } - if (!is_visible_file(conn, smb_dname->base_name, dname, - &st, false)) { - TALLOC_FREE(talloced); - continue; - } - if(!IS_VETO_PATH(conn, dname)) { - TALLOC_FREE(dir_hnd); - TALLOC_FREE(talloced); - errno = ENOTEMPTY; - goto err; - } - TALLOC_FREE(talloced); - } - - /* We only have veto files/directories. - * Are we allowed to delete them ? */ - - if(!lp_recursive_veto_delete(SNUM(conn))) { - TALLOC_FREE(dir_hnd); - errno = ENOTEMPTY; - goto err; - } - - /* Do a recursive delete. */ - RewindDir(dir_hnd,&dirpos); - while ((dname = ReadDirName(dir_hnd, &dirpos, &st, - &talloced)) != NULL) { - struct smb_filename *smb_dname_full = NULL; - char *fullname = NULL; - bool do_break = true; - NTSTATUS status; - - if (ISDOT(dname) || ISDOTDOT(dname)) { - TALLOC_FREE(talloced); - continue; - } - if (!is_visible_file(conn, smb_dname->base_name, dname, - &st, false)) { - TALLOC_FREE(talloced); - continue; - } - - fullname = talloc_asprintf(ctx, - "%s/%s", - smb_dname->base_name, - dname); - - if(!fullname) { - errno = ENOMEM; - goto err_break; - } - - status = create_synthetic_smb_fname(talloc_tos(), - fullname, NULL, - NULL, - &smb_dname_full); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - goto err_break; - } - - if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) { - goto err_break; - } - if(smb_dname_full->st.st_ex_mode & S_IFDIR) { - if(!recursive_rmdir(ctx, conn, - smb_dname_full)) { - goto err_break; - } - if(SMB_VFS_RMDIR(conn, - smb_dname_full->base_name) != 0) { - goto err_break; - } - } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) { - goto err_break; - } - - /* Successful iteration. */ - do_break = false; - - err_break: - TALLOC_FREE(fullname); - TALLOC_FREE(smb_dname_full); - TALLOC_FREE(talloced); - if (do_break) - break; - } - TALLOC_FREE(dir_hnd); - /* Retry the rmdir */ - ret = SMB_VFS_RMDIR(conn, smb_dname->base_name); - } - - err: - - if (ret != 0) { - DEBUG(3,("rmdir_internals: couldn't remove directory %s : " - "%s\n", smb_fname_str_dbg(smb_dname), - strerror(errno))); - return map_nt_error_from_unix(errno); - } - - notify_fname(conn, NOTIFY_ACTION_REMOVED, - FILE_NOTIFY_CHANGE_DIR_NAME, - smb_dname->base_name); - - return NT_STATUS_OK; -} /**************************************************************************** Close a directory opened by an NT SMB call. @@ -923,10 +622,9 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp) static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, enum file_close_type close_type) { - struct share_mode_lock *lck = NULL; + struct share_mode_lock *lck = 0; bool delete_dir = False; NTSTATUS status = NT_STATUS_OK; - NTSTATUS status1 = NT_STATUS_OK; /* * NT can set delete_on_close of the last open @@ -937,15 +635,12 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, NULL); if (lck == NULL) { - DEBUG(0, ("close_directory: Could not get share mode lock for " - "%s\n", fsp_str_dbg(fsp))); - status = NT_STATUS_INVALID_PARAMETER; - goto out; + DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name)); + return NT_STATUS_INVALID_PARAMETER; } if (!del_share_mode(lck, fsp)) { - DEBUG(0, ("close_directory: Could not delete share entry for " - "%s\n", fsp_str_dbg(fsp))); + DEBUG(0, ("close_directory: Could not delete share entry for %s\n", fsp->fsp_name)); } if (fsp->initial_delete_on_close) { @@ -959,9 +654,8 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, become_user(fsp->conn, fsp->vuid); became_user = True; } - send_stat_cache_delete_message(fsp->fsp_name->base_name); + send_stat_cache_delete_message(fsp->fsp_name); set_delete_on_close_lck(lck, True, ¤t_user.ut); - fsp->delete_on_close = true; if (became_user) { unbecome_user(); } @@ -1003,11 +697,12 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, TALLOC_FREE(lck); - status = rmdir_internals(talloc_tos(), fsp); + status = rmdir_internals(talloc_tos(), + fsp->conn, fsp->fsp_name); DEBUG(5,("close_directory: %s. Delete on close was set - " "deleting directory returned %s.\n", - fsp_str_dbg(fsp), nt_errstr(status))); + fsp->fsp_name, nt_errstr(status))); /* unbecome user. */ pop_sec_ctx(); @@ -1026,16 +721,11 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, fsp, NT_STATUS_OK); } - status1 = fd_close(fsp); + status = fd_close(fsp); - if (!NT_STATUS_IS_OK(status1)) { + if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n", - fsp_str_dbg(fsp), fsp->fh->fd, errno, - strerror(errno))); - } - - if (fsp->dptr) { - dptr_CloseDir(fsp->dptr); + fsp->fsp_name, fsp->fh->fd, errno, strerror(errno))); } /* @@ -1043,12 +733,6 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, */ close_filestruct(fsp); file_free(req, fsp); - - out: - TALLOC_FREE(lck); - if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) { - status = status1; - } return status; } diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c index 959fcd7754..a52f2d2e96 100644 --- a/source3/smbd/conn.c +++ b/source3/smbd/conn.c @@ -30,19 +30,17 @@ /**************************************************************************** init the conn structures ****************************************************************************/ -void conn_init(struct smbd_server_connection *sconn) +void conn_init(void) { - sconn->smb1.tcons.Connections = NULL; - sconn->smb1.tcons.num_open = 0; - sconn->smb1.tcons.bmap = bitmap_allocate(BITMAP_BLOCK_SZ); + bmap = bitmap_allocate(BITMAP_BLOCK_SZ); } /**************************************************************************** return the number of open connections ****************************************************************************/ -int conn_num_open(struct smbd_server_connection *sconn) +int conn_num_open(void) { - return sconn->smb1.tcons.num_open; + return num_open; } @@ -51,9 +49,8 @@ check if a snum is in use ****************************************************************************/ bool conn_snum_used(int snum) { - struct smbd_server_connection *sconn = smbd_server_conn; connection_struct *conn; - for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next) { + for (conn=Connections;conn;conn=conn->next) { if (conn->params->service == snum) { return(True); } @@ -65,16 +62,15 @@ bool conn_snum_used(int snum) Find a conn given a cnum. ****************************************************************************/ -connection_struct *conn_find(struct smbd_server_connection *sconn,unsigned cnum) +connection_struct *conn_find(unsigned cnum) { int count=0; connection_struct *conn; - for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next,count++) { + for (conn=Connections;conn;conn=conn->next,count++) { if (conn->cnum == cnum) { if (count > 10) { - DLIST_PROMOTE(sconn->smb1.tcons.Connections, - conn); + DLIST_PROMOTE(Connections, conn); } return conn; } @@ -88,31 +84,19 @@ connection_struct *conn_find(struct smbd_server_connection *sconn,unsigned cnum) The randomisation stops problems with the server dieing and clients thinking the server is still available. ****************************************************************************/ -connection_struct *conn_new(struct smbd_server_connection *sconn) +connection_struct *conn_new(void) { connection_struct *conn; int i; int find_offset = 1; - if (sconn->allow_smb2) { - if (!(conn=TALLOC_ZERO_P(NULL, connection_struct)) || - !(conn->params = TALLOC_P(conn, struct share_params))) { - DEBUG(0,("TALLOC_ZERO() failed!\n")); - TALLOC_FREE(conn); - return NULL; - } - conn->sconn = sconn; - return conn; - } - find_again: - i = bitmap_find(sconn->smb1.tcons.bmap, find_offset); + i = bitmap_find(bmap, find_offset); if (i == -1) { /* Expand the connections bitmap. */ - int oldsz = sconn->smb1.tcons.bmap->n; - int newsz = sconn->smb1.tcons.bmap->n + - BITMAP_BLOCK_SZ; + int oldsz = bmap->n; + int newsz = bmap->n + BITMAP_BLOCK_SZ; struct bitmap * nbmap; if (newsz <= oldsz) { @@ -130,10 +114,10 @@ find_again: return NULL; } - bitmap_copy(nbmap, sconn->smb1.tcons.bmap); - bitmap_free(sconn->smb1.tcons.bmap); + bitmap_copy(nbmap, bmap); + bitmap_free(bmap); - sconn->smb1.tcons.bmap = nbmap; + bmap = nbmap; find_offset = oldsz; /* Start next search in the new portion. */ goto find_again; @@ -155,18 +139,18 @@ find_again: TALLOC_FREE(conn); return NULL; } - conn->sconn = sconn; conn->cnum = i; conn->force_group_gid = (gid_t)-1; - bitmap_set(sconn->smb1.tcons.bmap, i); + bitmap_set(bmap, i); - sconn->smb1.tcons.num_open++; + num_open++; + string_set(&conn->dirpath,""); string_set(&conn->connectpath,""); string_set(&conn->origpath,""); - DLIST_ADD(sconn->smb1.tcons.Connections, conn); + DLIST_ADD(Connections, conn); return conn; } @@ -175,11 +159,11 @@ find_again: Close all conn structures. return true if any were closed ****************************************************************************/ -bool conn_close_all(struct smbd_server_connection *sconn) +bool conn_close_all(void) { connection_struct *conn, *next; bool ret = false; - for (conn=sconn->smb1.tcons.Connections;conn;conn=next) { + for (conn=Connections;conn;conn=next) { next=conn->next; set_current_service(conn, 0, True); close_cnum(conn, conn->vuid); @@ -192,7 +176,7 @@ bool conn_close_all(struct smbd_server_connection *sconn) Idle inactive connections. ****************************************************************************/ -bool conn_idle_all(struct smbd_server_connection *sconn,time_t t) +bool conn_idle_all(time_t t) { int deadtime = lp_deadtime()*60; pipes_struct *plist = NULL; @@ -201,7 +185,7 @@ bool conn_idle_all(struct smbd_server_connection *sconn,time_t t) if (deadtime <= 0) deadtime = DEFAULT_SMBD_TIMEOUT; - for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next) { + for (conn=Connections;conn;conn=conn->next) { time_t age = t - conn->lastused; @@ -228,7 +212,7 @@ bool conn_idle_all(struct smbd_server_connection *sconn,time_t t) for (plist = get_first_internal_pipe(); plist; plist = get_next_internal_pipe(plist)) { - if (num_pipe_handles(plist->pipe_handles) != 0) { + if (plist->pipe_handles && plist->pipe_handles->count) { return False; } } @@ -240,11 +224,11 @@ bool conn_idle_all(struct smbd_server_connection *sconn,time_t t) Clear a vuid out of the validity cache, and as the 'owner' of a connection. ****************************************************************************/ -void conn_clear_vuid_caches(struct smbd_server_connection *sconn,uint16_t vuid) +void conn_clear_vuid_caches(uint16_t vuid) { connection_struct *conn; - for (conn=sconn->smb1.tcons.Connections;conn;conn=conn->next) { + for (conn=Connections;conn;conn=conn->next) { if (conn->vuid == vuid) { conn->vuid = UID_FIELD_INVALID; } @@ -256,9 +240,9 @@ void conn_clear_vuid_caches(struct smbd_server_connection *sconn,uint16_t vuid) Free a conn structure - internal part. ****************************************************************************/ -static void conn_free_internal(connection_struct *conn) +void conn_free_internal(connection_struct *conn) { - vfs_handle_struct *handle = NULL, *thandle = NULL; + vfs_handle_struct *handle = NULL, *thandle = NULL; struct trans_state *state = NULL; /* Free vfs_connection_struct */ @@ -283,6 +267,7 @@ static void conn_free_internal(connection_struct *conn) free_namearray(conn->veto_oplock_list); free_namearray(conn->aio_write_behind_list); + string_free(&conn->dirpath); string_free(&conn->connectpath); string_free(&conn->origpath); @@ -296,22 +281,12 @@ static void conn_free_internal(connection_struct *conn) void conn_free(connection_struct *conn) { - if (conn->sconn == NULL) { - conn_free_internal(conn); - return; - } - - if (conn->sconn->allow_smb2) { - conn_free_internal(conn); - return; - } - - DLIST_REMOVE(conn->sconn->smb1.tcons.Connections, conn); + DLIST_REMOVE(Connections, conn); - bitmap_clear(conn->sconn->smb1.tcons.bmap, conn->cnum); + bitmap_clear(bmap, conn->cnum); - SMB_ASSERT(conn->sconn->smb1.tcons.num_open > 0); - conn->sconn->smb1.tcons.num_open--; + SMB_ASSERT(num_open > 0); + num_open--; conn_free_internal(conn); } @@ -328,7 +303,6 @@ void msg_force_tdis(struct messaging_context *msg, struct server_id server_id, DATA_BLOB *data) { - struct smbd_server_connection *sconn = smbd_server_conn; connection_struct *conn, *next; fstring sharename; @@ -336,11 +310,11 @@ void msg_force_tdis(struct messaging_context *msg, if (strcmp(sharename, "*") == 0) { DEBUG(1,("Forcing close of all shares\n")); - conn_close_all(sconn); + conn_close_all(); return; } - for (conn=sconn->smb1.tcons.Connections;conn;conn=next) { + for (conn=Connections;conn;conn=next) { next=conn->next; if (strequal(lp_servicename(SNUM(conn)), sharename)) { DEBUG(1,("Forcing close of share %s cnum=%d\n", diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 5ce4a7b099..ab4a0d27e3 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -115,19 +115,15 @@ bool make_dir_struct(TALLOC_CTX *ctx, Initialise the dir bitmap. ****************************************************************************/ -bool init_dptrs(struct smbd_server_connection *sconn) +void init_dptrs(void) { - if (sconn->smb1.searches.dptr_bmap) { - return true; - } - - sconn->smb1.searches.dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES); + if (dptr_bmap) + return; - if (sconn->smb1.searches.dptr_bmap == NULL) { - return false; - } + dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES); - return true; + if (!dptr_bmap) + exit_server("out of memory in init_dptrs"); } /**************************************************************************** @@ -146,14 +142,14 @@ static void dptr_idle(struct dptr_struct *dptr) Idle the oldest dptr. ****************************************************************************/ -static void dptr_idleoldest(struct smbd_server_connection *sconn) +static void dptr_idleoldest(void) { struct dptr_struct *dptr; /* * Go to the end of the list. */ - for(dptr = sconn->smb1.searches.dirptrs; dptr && dptr->next; dptr = dptr->next) + for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next) ; if(!dptr) { @@ -177,16 +173,15 @@ static void dptr_idleoldest(struct smbd_server_connection *sconn) Get the struct dptr_struct for a dir index. ****************************************************************************/ -static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn, - int key, bool forclose) +static struct dptr_struct *dptr_get(int key, bool forclose) { struct dptr_struct *dptr; - for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = dptr->next) { + for(dptr = dirptrs; dptr; dptr = dptr->next) { if(dptr->dnum == key) { if (!forclose && !dptr->dir_hnd) { - if (sconn->smb1.searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) - dptr_idleoldest(sconn); + if (dirhandles_open >= MAX_OPEN_DIRECTORIES) + dptr_idleoldest(); DEBUG(4,("dptr_get: Reopening dptr key %d\n",key)); if (!(dptr->dir_hnd = OpenDir( NULL, dptr->conn, dptr->path, @@ -196,7 +191,7 @@ static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn, return False; } } - DLIST_PROMOTE(sconn->smb1.searches.dirptrs,dptr); + DLIST_PROMOTE(dirptrs,dptr); return dptr; } } @@ -207,9 +202,9 @@ static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn, Get the dir path for a dir index. ****************************************************************************/ -char *dptr_path(struct smbd_server_connection *sconn, int key) +char *dptr_path(int key) { - struct dptr_struct *dptr = dptr_get(sconn, key, false); + struct dptr_struct *dptr = dptr_get(key, False); if (dptr) return(dptr->path); return(NULL); @@ -219,9 +214,9 @@ char *dptr_path(struct smbd_server_connection *sconn, int key) Get the dir wcard for a dir index. ****************************************************************************/ -char *dptr_wcard(struct smbd_server_connection *sconn, int key) +char *dptr_wcard(int key) { - struct dptr_struct *dptr = dptr_get(sconn, key, false); + struct dptr_struct *dptr = dptr_get(key, False); if (dptr) return(dptr->wcard); return(NULL); @@ -231,9 +226,9 @@ char *dptr_wcard(struct smbd_server_connection *sconn, int key) Get the dir attrib for a dir index. ****************************************************************************/ -uint16 dptr_attr(struct smbd_server_connection *sconn, int key) +uint16 dptr_attr(int key) { - struct dptr_struct *dptr = dptr_get(sconn, key, false); + struct dptr_struct *dptr = dptr_get(key, False); if (dptr) return(dptr->attr); return(0); @@ -245,29 +240,22 @@ uint16 dptr_attr(struct smbd_server_connection *sconn, int key) static void dptr_close_internal(struct dptr_struct *dptr) { - struct smbd_server_connection *sconn = dptr->conn->sconn; - DEBUG(4,("closing dptr key %d\n",dptr->dnum)); - if (sconn == NULL) { - goto done; - } - - DLIST_REMOVE(sconn->smb1.searches.dirptrs, dptr); + DLIST_REMOVE(dirptrs, dptr); /* * Free the dnum in the bitmap. Remember the dnum value is always * biased by one with respect to the bitmap. */ - if(bitmap_query(sconn->smb1.searches.dptr_bmap, dptr->dnum - 1) != true) { + if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) { DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n", dptr->dnum )); } - bitmap_clear(sconn->smb1.searches.dptr_bmap, dptr->dnum - 1); + bitmap_clear(dptr_bmap, dptr->dnum - 1); -done: TALLOC_FREE(dptr->dir_hnd); /* Lanman 2 specific code */ @@ -280,7 +268,7 @@ done: Close a dptr given a key. ****************************************************************************/ -void dptr_close(struct smbd_server_connection *sconn, int *key) +void dptr_close(int *key) { struct dptr_struct *dptr; @@ -290,7 +278,7 @@ void dptr_close(struct smbd_server_connection *sconn, int *key) /* OS/2 seems to use -1 to indicate "close all directories" */ if (*key == -1) { struct dptr_struct *next; - for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = next) { + for(dptr = dirptrs; dptr; dptr = next) { next = dptr->next; dptr_close_internal(dptr); } @@ -298,7 +286,7 @@ void dptr_close(struct smbd_server_connection *sconn, int *key) return; } - dptr = dptr_get(sconn, *key, true); + dptr = dptr_get(*key, True); if (!dptr) { DEBUG(0,("Invalid key %d given to dptr_close\n", *key)); @@ -317,17 +305,10 @@ void dptr_close(struct smbd_server_connection *sconn, int *key) void dptr_closecnum(connection_struct *conn) { struct dptr_struct *dptr, *next; - struct smbd_server_connection *sconn = conn->sconn; - - if (sconn == NULL) { - return; - } - - for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = next) { + for(dptr = dirptrs; dptr; dptr = next) { next = dptr->next; - if (dptr->conn == conn) { + if (dptr->conn == conn) dptr_close_internal(dptr); - } } } @@ -338,16 +319,9 @@ void dptr_closecnum(connection_struct *conn) void dptr_idlecnum(connection_struct *conn) { struct dptr_struct *dptr; - struct smbd_server_connection *sconn = conn->sconn; - - if (sconn == NULL) { - return; - } - - for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = dptr->next) { - if (dptr->conn == conn && dptr->dir_hnd) { + for(dptr = dirptrs; dptr; dptr = dptr->next) { + if (dptr->conn == conn && dptr->dir_hnd) dptr_idle(dptr); - } } } @@ -355,11 +329,10 @@ void dptr_idlecnum(connection_struct *conn) Close a dptr that matches a given path, only if it matches the spid also. ****************************************************************************/ -void dptr_closepath(struct smbd_server_connection *sconn, - char *path,uint16 spid) +void dptr_closepath(char *path,uint16 spid) { struct dptr_struct *dptr, *next; - for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = next) { + for(dptr = dirptrs; dptr; dptr = next) { next = dptr->next; if (spid == dptr->spid && strequal(dptr->path,path)) dptr_close_internal(dptr); @@ -372,15 +345,14 @@ void dptr_closepath(struct smbd_server_connection *sconn, finished with that one. ****************************************************************************/ -static void dptr_close_oldest(struct smbd_server_connection *sconn, - bool old) +static void dptr_close_oldest(bool old) { struct dptr_struct *dptr; /* * Go to the end of the list. */ - for(dptr = sconn->smb1.searches.dirptrs; dptr && dptr->next; dptr = dptr->next) + for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next) ; if(!dptr) { @@ -415,18 +387,12 @@ static void dptr_close_oldest(struct smbd_server_connection *sconn, NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, bool expect_close,uint16 spid, const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret) { - struct smbd_server_connection *sconn = conn->sconn; struct dptr_struct *dptr = NULL; struct smb_Dir *dir_hnd; NTSTATUS status; DEBUG(5,("dptr_create dir=%s\n", path)); - if (sconn == NULL) { - DEBUG(0,("dptr_create: called with fake connection_struct\n")); - return NT_STATUS_INTERNAL_ERROR; - } - if (!wcard) { return NT_STATUS_INVALID_PARAMETER; } @@ -441,8 +407,10 @@ NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, return map_nt_error_from_unix(errno); } - if (sconn->smb1.searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) { - dptr_idleoldest(sconn); + string_set(&conn->dirpath,path); + + if (dirhandles_open >= MAX_OPEN_DIRECTORIES) { + dptr_idleoldest(); } dptr = SMB_MALLOC_P(struct dptr_struct); @@ -461,7 +429,7 @@ NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, * value we return will fit in the range 1-255. */ - dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 0); + dptr->dnum = bitmap_find(dptr_bmap, 0); if(dptr->dnum == -1 || dptr->dnum > 254) { @@ -471,10 +439,10 @@ NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, * finished with that one. */ - dptr_close_oldest(sconn, true); + dptr_close_oldest(True); /* Now try again... */ - dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 0); + dptr->dnum = bitmap_find(dptr_bmap, 0); if(dptr->dnum == -1 || dptr->dnum > 254) { DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum)); SAFE_FREE(dptr); @@ -489,7 +457,7 @@ NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, * a range that will return 256 - MAX_DIRECTORY_HANDLES. */ - dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 255); + dptr->dnum = bitmap_find(dptr_bmap, 255); if(dptr->dnum == -1 || dptr->dnum < 255) { @@ -500,10 +468,10 @@ NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, * directory handles. */ - dptr_close_oldest(sconn, false); + dptr_close_oldest(False); /* Now try again... */ - dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 255); + dptr->dnum = bitmap_find(dptr_bmap, 255); if(dptr->dnum == -1 || dptr->dnum < 255) { DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum)); @@ -514,7 +482,7 @@ NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, } } - bitmap_set(sconn->smb1.searches.dptr_bmap, dptr->dnum); + bitmap_set(dptr_bmap, dptr->dnum); dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */ @@ -525,7 +493,7 @@ NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, dptr->expect_close = expect_close; dptr->wcard = SMB_STRDUP(wcard); if (!dptr->wcard) { - bitmap_clear(sconn->smb1.searches.dptr_bmap, dptr->dnum - 1); + bitmap_clear(dptr_bmap, dptr->dnum - 1); SAFE_FREE(dptr); TALLOC_FREE(dir_hnd); return NT_STATUS_NO_MEMORY; @@ -538,7 +506,7 @@ NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, dptr->attr = attr; - DLIST_ADD(sconn->smb1.searches.dirptrs, dptr); + DLIST_ADD(dirptrs, dptr); DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n", dptr->dnum,path,expect_close)); @@ -555,8 +523,7 @@ NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, int dptr_CloseDir(struct dptr_struct *dptr) { - struct smbd_server_connection *sconn = dptr->conn->sconn; - DLIST_REMOVE(sconn->smb1.searches.dirptrs, dptr); + DLIST_REMOVE(dirptrs, dptr); TALLOC_FREE(dptr->dir_hnd); return 0; } @@ -586,20 +553,14 @@ int dptr_dnum(struct dptr_struct *dptr) ****************************************************************************/ static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, - long *poffset, SMB_STRUCT_STAT *pst, - char **ptalloced) + long *poffset, SMB_STRUCT_STAT *pst) { /* Normal search for the next file. */ const char *name; - char *talloced = NULL; - - while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced)) - != NULL) { + while ((name = ReadDirName(dptr->dir_hnd, poffset, pst)) != NULL) { if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) { - *ptalloced = talloced; return name; } - TALLOC_FREE(talloced); } return NULL; } @@ -613,26 +574,18 @@ char *dptr_ReadDirName(TALLOC_CTX *ctx, long *poffset, SMB_STRUCT_STAT *pst) { - struct smb_filename smb_fname_base; char *name = NULL; - const char *name_temp = NULL; - char *talloced = NULL; char *pathreal = NULL; char *found_name = NULL; int ret; + const char *name_temp = NULL; SET_STAT_INVALID(*pst); if (dptr->has_wild || dptr->did_stat) { - name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, - &talloced); - if (name_temp == NULL) { - return NULL; - } - if (talloced != NULL) { - return talloc_move(ctx, &talloced); - } - return talloc_strdup(ctx, name_temp); + name_temp = dptr_normal_ReadDirName(dptr, poffset, pst); + name = talloc_strdup(ctx, name_temp); + return name; } /* If poffset is -1 then we know we returned this name before and we @@ -671,12 +624,7 @@ char *dptr_ReadDirName(TALLOC_CTX *ctx, if (!pathreal) return NULL; - /* Create an smb_filename with stream_name == NULL. */ - ZERO_STRUCT(smb_fname_base); - smb_fname_base.base_name = pathreal; - - if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) { - *pst = smb_fname_base.st; + if (SMB_VFS_STAT(dptr->conn, pathreal, pst) == 0) { name = talloc_strdup(ctx, dptr->wcard); goto clean; } else { @@ -714,14 +662,9 @@ char *dptr_ReadDirName(TALLOC_CTX *ctx, TALLOC_FREE(pathreal); - name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced); - if (name_temp == NULL) { - return NULL; - } - if (talloced != NULL) { - return talloc_move(ctx, &talloced); - } - return talloc_strdup(ctx, name_temp); + name_temp = dptr_normal_ReadDirName(dptr, poffset, pst); + name = talloc_strdup(ctx, name_temp); + return name; clean: TALLOC_FREE(pathreal); @@ -771,11 +714,10 @@ void dptr_init_search_op(struct dptr_struct *dptr) Fill the 5 byte server reserved dptr field. ****************************************************************************/ -bool dptr_fill(struct smbd_server_connection *sconn, - char *buf1,unsigned int key) +bool dptr_fill(char *buf1,unsigned int key) { unsigned char *buf = (unsigned char *)buf1; - struct dptr_struct *dptr = dptr_get(sconn, key, false); + struct dptr_struct *dptr = dptr_get(key, False); uint32 offset; if (!dptr) { DEBUG(1,("filling null dirptr %d\n",key)); @@ -793,11 +735,10 @@ bool dptr_fill(struct smbd_server_connection *sconn, Fetch the dir ptr and seek it given the 5 byte server field. ****************************************************************************/ -struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn, - char *buf, int *num) +struct dptr_struct *dptr_fetch(char *buf,int *num) { unsigned int key = *(unsigned char *)buf; - struct dptr_struct *dptr = dptr_get(sconn, key, false); + struct dptr_struct *dptr = dptr_get(key, False); uint32 offset; long seekoff; @@ -814,7 +755,7 @@ struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn, } SeekDir(dptr->dir_hnd,seekoff); DEBUG(3,("fetching dirptr %d for path %s at offset %d\n", - key, dptr->path, (int)seekoff)); + key,dptr_path(key),(int)seekoff)); return(dptr); } @@ -822,16 +763,15 @@ struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn, Fetch the dir ptr. ****************************************************************************/ -struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn, - int dptr_num) +struct dptr_struct *dptr_fetch_lanman2(int dptr_num) { - struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false); + struct dptr_struct *dptr = dptr_get(dptr_num, False); if (!dptr) { DEBUG(3,("fetched null dirptr %d\n",dptr_num)); return(NULL); } - DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path)); + DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num))); return(dptr); } @@ -873,249 +813,138 @@ static bool mangle_mask_match(connection_struct *conn, return mask_match_search(mname,mask,False); } -bool smbd_dirptr_get_entry(TALLOC_CTX *ctx, - struct dptr_struct *dirptr, - const char *mask, - uint32_t dirtype, - bool dont_descend, - bool ask_sharemode, - bool (*match_fn)(TALLOC_CTX *ctx, - void *private_data, - const char *dname, - const char *mask, - char **_fname), - bool (*mode_fn)(TALLOC_CTX *ctx, - void *private_data, - struct smb_filename *smb_fname, - uint32_t *_mode), - void *private_data, - char **_fname, - struct smb_filename **_smb_fname, - uint32_t *_mode, - long *_prev_offset) +/**************************************************************************** + Get an 8.3 directory entry. +****************************************************************************/ + +bool get_dir_entry(TALLOC_CTX *ctx, + connection_struct *conn, + const char *mask, + uint32 dirtype, + char **pp_fname_out, + SMB_OFF_T *size, + uint32 *mode, + time_t *date, + bool check_descend, + bool ask_sharemode) { - connection_struct *conn = dirptr->conn; + char *dname = NULL; + bool found = False; + SMB_STRUCT_STAT sbuf; + char *pathreal = NULL; + char *filename = NULL; bool needslash; - *_smb_fname = NULL; - *_mode = 0; + *pp_fname_out = NULL; - needslash = ( dirptr->path[strlen(dirptr->path) -1] != '/'); + needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); - while (true) { - long cur_offset; - long prev_offset; - SMB_STRUCT_STAT sbuf; - char *dname = NULL; - bool isdots; - char *fname = NULL; - char *pathreal = NULL; - struct smb_filename smb_fname; - uint32_t mode = 0; - bool ok; - NTSTATUS status; + if (!conn->dirptr) { + return(False); + } - cur_offset = dptr_TellDir(dirptr); - prev_offset = cur_offset; - dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf); + while (!found) { + long curoff = dptr_TellDir(conn->dirptr); + dname = dptr_ReadDirName(ctx, conn->dirptr, &curoff, &sbuf); - DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n", - (long)dirptr, cur_offset)); + DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n", + (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd))); if (dname == NULL) { - return false; - } - - isdots = (ISDOT(dname) || ISDOTDOT(dname)); - if (dont_descend && !isdots) { - TALLOC_FREE(dname); - continue; - } - - /* - * fname may get mangled, dname is never mangled. - * Whenever we're accessing the filesystem we use - * pathreal which is composed from dname. - */ - - ok = match_fn(ctx, private_data, dname, mask, &fname); - if (!ok) { - TALLOC_FREE(dname); - continue; - } - - pathreal = talloc_asprintf(ctx, "%s%s%s", - dirptr->path, - needslash?"/":"", - dname); - if (!pathreal) { - TALLOC_FREE(dname); - TALLOC_FREE(fname); - return false; - } - - /* Create smb_fname with NULL stream_name. */ - ZERO_STRUCT(smb_fname); - smb_fname.base_name = pathreal; - smb_fname.st = sbuf; - - ok = mode_fn(ctx, private_data, &smb_fname, &mode); - if (!ok) { - TALLOC_FREE(dname); - TALLOC_FREE(fname); - TALLOC_FREE(pathreal); - continue; + return(False); } - if (!dir_check_ftype(conn, mode, dirtype)) { - DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n", - fname, (unsigned int)mode, (unsigned int)dirtype)); - TALLOC_FREE(dname); - TALLOC_FREE(fname); - TALLOC_FREE(pathreal); - continue; - } - - if (ask_sharemode) { - struct timespec write_time_ts; - struct file_id fileid; - - fileid = vfs_file_id_from_sbuf(conn, - &smb_fname.st); - get_file_infos(fileid, NULL, &write_time_ts); - if (!null_timespec(write_time_ts)) { - update_stat_ex_mtime(&smb_fname.st, - write_time_ts); + filename = dname; + + /* notice the special *.* handling. This appears to be the only difference + between the wildcard handling in this routine and in the trans2 routines. + see masktest for a demo + */ + if ((strcmp(mask,"*.*") == 0) || + mask_match_search(filename,mask,False) || + mangle_mask_match(conn,filename,mask)) { + char mname[13]; + + if (!mangle_is_8_3(filename, False, conn->params)) { + if (!name_to_8_3(filename,mname,False, + conn->params)) { + TALLOC_FREE(filename); + continue; + } + filename = talloc_strdup(ctx, mname); + if (!filename) { + return False; + } } - } - DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s " - "fname=%s (%s)\n", - mask, smb_fname_str_dbg(&smb_fname), - dname, fname)); + if (needslash) { + pathreal = talloc_asprintf(ctx, + "%s/%s", + conn->dirpath, + dname); + } else { + pathreal = talloc_asprintf(ctx, + "%s%s", + conn->dirpath, + dname); + } + if (!pathreal) { + TALLOC_FREE(filename); + return False; + } - DirCacheAdd(dirptr->dir_hnd, dname, cur_offset); + if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) { + DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n", + pathreal, strerror(errno) )); + TALLOC_FREE(pathreal); + TALLOC_FREE(filename); + continue; + } - TALLOC_FREE(dname); + *mode = dos_mode(conn,pathreal,&sbuf); - status = copy_smb_filename(ctx, &smb_fname, _smb_fname); - TALLOC_FREE(pathreal); - if (!NT_STATUS_IS_OK(status)) { - return false; - } - *_fname = fname; - *_mode = mode; - *_prev_offset = prev_offset; + if (!dir_check_ftype(conn,*mode,dirtype)) { + DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",filename,(unsigned int)*mode,(unsigned int)dirtype)); + TALLOC_FREE(pathreal); + TALLOC_FREE(filename); + continue; + } - return true; - } + *size = sbuf.st_size; + *date = sbuf.st_mtime; - return false; -} - -/**************************************************************************** - Get an 8.3 directory entry. -****************************************************************************/ + if (ask_sharemode) { + struct timespec write_time_ts; + struct file_id fileid; -static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx, - void *private_data, - const char *dname, - const char *mask, - char **_fname) -{ - connection_struct *conn = (connection_struct *)private_data; - - if ((strcmp(mask,"*.*") == 0) || - mask_match_search(dname, mask, false) || - mangle_mask_match(conn, dname, mask)) { - char mname[13]; - const char *fname; - - if (!mangle_is_8_3(dname, false, conn->params)) { - bool ok = name_to_8_3(dname, mname, false, - conn->params); - if (!ok) { - return false; + fileid = vfs_file_id_from_sbuf(conn, &sbuf); + get_file_infos(fileid, NULL, &write_time_ts); + if (!null_timespec(write_time_ts)) { + *date = convert_timespec_to_time_t(write_time_ts); + } } - fname = mname; - } else { - fname = dname; - } - *_fname = talloc_strdup(ctx, fname); - if (*_fname == NULL) { - return false; - } + DEBUG(3,("get_dir_entry mask=[%s] found %s " + "fname=%s (%s)\n", + mask, + pathreal, + dname, + filename)); - return true; - } + found = True; - return false; -} + SMB_ASSERT(filename != NULL); + *pp_fname_out = filename; -static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx, - void *private_data, - struct smb_filename *smb_fname, - uint32_t *_mode) -{ - connection_struct *conn = (connection_struct *)private_data; - - if (!VALID_STAT(smb_fname->st)) { - if ((SMB_VFS_STAT(conn, smb_fname)) != 0) { - DEBUG(5,("smbd_dirptr_8_3_mode_fn: " - "Couldn't stat [%s]. Error " - "= %s\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - return false; + DirCacheAdd(conn->dirptr->dir_hnd, dname, curoff); + TALLOC_FREE(pathreal); } - } - *_mode = dos_mode(conn, smb_fname); - return true; -} - -bool get_dir_entry(TALLOC_CTX *ctx, - struct dptr_struct *dirptr, - const char *mask, - uint32_t dirtype, - char **_fname, - SMB_OFF_T *_size, - uint32_t *_mode, - struct timespec *_date, - bool check_descend, - bool ask_sharemode) -{ - connection_struct *conn = dirptr->conn; - char *fname = NULL; - struct smb_filename *smb_fname = NULL; - uint32_t mode = 0; - long prev_offset; - bool ok; - - ok = smbd_dirptr_get_entry(ctx, - dirptr, - mask, - dirtype, - check_descend, - ask_sharemode, - smbd_dirptr_8_3_match_fn, - smbd_dirptr_8_3_mode_fn, - conn, - &fname, - &smb_fname, - &mode, - &prev_offset); - if (!ok) { - return false; + if (!found) + TALLOC_FREE(filename); } - *_fname = talloc_move(ctx, &fname); - *_size = smb_fname->st.st_ex_size; - *_mode = mode; - *_date = smb_fname->st.st_ex_mtime; - TALLOC_FREE(smb_fname); - return true; + return(found); } /******************************************************************* @@ -1124,8 +953,7 @@ bool get_dir_entry(TALLOC_CTX *ctx, use it for anything security sensitive. ********************************************************************/ -static bool user_can_read_file(connection_struct *conn, - struct smb_filename *smb_fname) +static bool user_can_read_file(connection_struct *conn, char *name) { /* * If user is a member of the Admin group @@ -1136,7 +964,7 @@ static bool user_can_read_file(connection_struct *conn, return True; } - return can_access_file_acl(conn, smb_fname, FILE_READ_DATA); + return can_access_file_acl(conn, name, FILE_READ_DATA); } /******************************************************************* @@ -1146,8 +974,7 @@ static bool user_can_read_file(connection_struct *conn, use it for anything security sensitive. ********************************************************************/ -static bool user_can_write_file(connection_struct *conn, - const struct smb_filename *smb_fname) +static bool user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst) { /* * If user is a member of the Admin group @@ -1158,23 +985,22 @@ static bool user_can_write_file(connection_struct *conn, return True; } - SMB_ASSERT(VALID_STAT(smb_fname->st)); + SMB_ASSERT(VALID_STAT(*pst)); /* Pseudo-open the file */ - if(S_ISDIR(smb_fname->st.st_ex_mode)) { + if(S_ISDIR(pst->st_mode)) { return True; } - return can_write_to_file(conn, smb_fname); + return can_write_to_file(conn, name, pst); } /******************************************************************* Is a file a "special" type ? ********************************************************************/ -static bool file_is_special(connection_struct *conn, - const struct smb_filename *smb_fname) +static bool file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst) { /* * If user is a member of the Admin group @@ -1184,11 +1010,9 @@ static bool file_is_special(connection_struct *conn, if (conn->admin_user) return False; - SMB_ASSERT(VALID_STAT(smb_fname->st)); + SMB_ASSERT(VALID_STAT(*pst)); - if (S_ISREG(smb_fname->st.st_ex_mode) || - S_ISDIR(smb_fname->st.st_ex_mode) || - S_ISLNK(smb_fname->st.st_ex_mode)) + if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode)) return False; return True; @@ -1205,10 +1029,6 @@ bool is_visible_file(connection_struct *conn, const char *dir_path, bool hide_unreadable = lp_hideunreadable(SNUM(conn)); bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn)); bool hide_special = lp_hide_special_files(SNUM(conn)); - char *entry = NULL; - struct smb_filename *smb_fname_base = NULL; - NTSTATUS status; - bool ret = false; if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) { return True; /* . and .. are always visible. */ @@ -1221,71 +1041,54 @@ bool is_visible_file(connection_struct *conn, const char *dir_path, } if (hide_unreadable || hide_unwriteable || hide_special) { - entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name); - if (!entry) { - ret = false; - goto out; + char *entry = NULL; + + if (asprintf(&entry, "%s/%s", dir_path, name) == -1) { + return False; } /* If it's a dfs symlink, ignore _hide xxxx_ options */ if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) && is_msdfs_link(conn, entry, NULL)) { - ret = true; - goto out; - } - - /* Create an smb_filename with stream_name == NULL. */ - status = create_synthetic_smb_fname(talloc_tos(), entry, NULL, - pst, &smb_fname_base); - if (!NT_STATUS_IS_OK(status)) { - ret = false; - goto out; + SAFE_FREE(entry); + return True; } /* If the file name does not exist, there's no point checking * the configuration options. We succeed, on the basis that the * checks *might* have passed if the file was present. */ - if (!VALID_STAT(*pst)) { - if (SMB_VFS_STAT(conn, smb_fname_base) != 0) { - ret = true; - goto out; - } else { - *pst = smb_fname_base->st; - } + if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, entry, pst) != 0)) + { + SAFE_FREE(entry); + return True; } /* Honour _hide unreadable_ option */ - if (hide_unreadable && - !user_can_read_file(conn, smb_fname_base)) { + if (hide_unreadable && !user_can_read_file(conn, entry)) { DEBUG(10,("is_visible_file: file %s is unreadable.\n", entry )); - ret = false; - goto out; + SAFE_FREE(entry); + return False; } /* Honour _hide unwriteable_ option */ - if (hide_unwriteable && !user_can_write_file(conn, - smb_fname_base)) { + if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) { DEBUG(10,("is_visible_file: file %s is unwritable.\n", entry )); - ret = false; - goto out; + SAFE_FREE(entry); + return False; } /* Honour _hide_special_ option */ - if (hide_special && file_is_special(conn, smb_fname_base)) { + if (hide_special && file_is_special(conn, entry, pst)) { DEBUG(10,("is_visible_file: file %s is special.\n", entry )); - ret = false; - goto out; + SAFE_FREE(entry); + return False; } + SAFE_FREE(entry); } - - ret = true; - out: - TALLOC_FREE(smb_fname_base); - TALLOC_FREE(entry); - return ret; + return True; } static int smb_Dir_destructor(struct smb_Dir *dirp) @@ -1293,9 +1096,7 @@ static int smb_Dir_destructor(struct smb_Dir *dirp) if (dirp->dir) { SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir); } - if (dirp->conn->sconn) { - dirp->conn->sconn->smb1.searches.dirhandles_open--; - } + dirhandles_open--; return 0; } @@ -1307,7 +1108,6 @@ struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *name, const char *mask, uint32 attr) { struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir); - struct smbd_server_connection *sconn = conn->sconn; if (!dirp) { return NULL; @@ -1322,9 +1122,7 @@ struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn, goto fail; } - if (sconn) { - sconn->smb1.searches.dirhandles_open++; - } + dirhandles_open++; talloc_set_destructor(dirp, smb_Dir_destructor); dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr); @@ -1348,10 +1146,9 @@ struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn, ********************************************************************/ const char *ReadDirName(struct smb_Dir *dirp, long *poffset, - SMB_STRUCT_STAT *sbuf, char **ptalloced) + SMB_STRUCT_STAT *sbuf) { const char *n; - char *talloced = NULL; connection_struct *conn = dirp->conn; /* Cheat to allow . and .. to be the first entries returned. */ @@ -1362,11 +1159,10 @@ const char *ReadDirName(struct smb_Dir *dirp, long *poffset, n = "."; *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET; } else { - n = ".."; *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET; + n = ".."; } dirp->file_number++; - *ptalloced = NULL; return n; } else if (*poffset == END_OF_DIRECTORY_OFFSET) { *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET; @@ -1376,21 +1172,18 @@ const char *ReadDirName(struct smb_Dir *dirp, long *poffset, SeekDir(dirp, *poffset); } - while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) { + while ((n = vfs_readdirname(conn, dirp->dir, sbuf))) { /* Ignore . and .. - we've already returned them. */ if (*n == '.') { if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) { - TALLOC_FREE(talloced); continue; } } *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir); - *ptalloced = talloced; dirp->file_number++; return n; } *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET; - *ptalloced = NULL; return NULL; } @@ -1485,8 +1278,7 @@ void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset) bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset) { int i; - const char *entry = NULL; - char *talloced = NULL; + const char *entry; connection_struct *conn = dirp->conn; /* Search back in the name cache. */ @@ -1513,12 +1305,10 @@ bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset) SMB_VFS_REWINDDIR(conn, dirp->dir); dirp->file_number = 0; *poffset = START_OF_DIRECTORY_OFFSET; - while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) { + while ((entry = ReadDirName(dirp, poffset, NULL))) { if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) { - TALLOC_FREE(talloced); return True; } - TALLOC_FREE(talloced); } return False; } @@ -1532,8 +1322,7 @@ NTSTATUS can_delete_directory(struct connection_struct *conn, { NTSTATUS status = NT_STATUS_OK; long dirpos = 0; - const char *dname = NULL; - char *talloced = NULL; + const char *dname; SMB_STRUCT_STAT st; struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, dirname, NULL, 0); @@ -1542,17 +1331,15 @@ NTSTATUS can_delete_directory(struct connection_struct *conn, return map_nt_error_from_unix(errno); } - while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) { + while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) { /* Quick check for "." and ".." */ if (dname[0] == '.') { if (!dname[1] || (dname[1] == '.' && !dname[2])) { - TALLOC_FREE(talloced); continue; } } if (!is_visible_file(conn, dirname, dname, &st, True)) { - TALLOC_FREE(talloced); continue; } @@ -1561,7 +1348,6 @@ NTSTATUS can_delete_directory(struct connection_struct *conn, status = NT_STATUS_DIRECTORY_NOT_EMPTY; break; } - TALLOC_FREE(talloced); TALLOC_FREE(dir_hnd); return status; diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index c061b21822..7b47fe6236 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -3,27 +3,28 @@ dos mode handling functions Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) James Peach 2006 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "includes.h" -#include "librpc/gen_ndr/ndr_xattr.h" + +extern enum protocol_types Protocol; static uint32_t filter_mode_by_protocol(uint32_t mode) { - if (get_Protocol() <= PROTOCOL_LANMAN2) { + if (Protocol <= PROTOCOL_LANMAN2) { DEBUG(10,("filter_mode_by_protocol: " "filtering result 0x%x to 0x%x\n", (unsigned int)mode, @@ -36,7 +37,7 @@ static uint32_t filter_mode_by_protocol(uint32_t mode) static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf) { #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) - if (sbuf->st_ex_size > sbuf->st_ex_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) { + if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) { return FILE_ATTRIBUTE_SPARSE; } #endif @@ -77,8 +78,7 @@ static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf) } ****************************************************************************/ -mode_t unix_mode(connection_struct *conn, int dosmode, - const struct smb_filename *smb_fname, +mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname, const char *inherit_from_dir) { mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH); @@ -89,39 +89,23 @@ mode_t unix_mode(connection_struct *conn, int dosmode, result &= ~(S_IWUSR | S_IWGRP | S_IWOTH); } - if ((inherit_from_dir != NULL) && lp_inherit_perms(SNUM(conn))) { - struct smb_filename *smb_fname_parent = NULL; - NTSTATUS status; + if (fname && (inherit_from_dir != NULL) + && lp_inherit_perms(SNUM(conn))) { + SMB_STRUCT_STAT sbuf; - DEBUG(2, ("unix_mode(%s) inheriting from %s\n", - smb_fname_str_dbg(smb_fname), + DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname, inherit_from_dir)); - - status = create_synthetic_smb_fname(talloc_tos(), - inherit_from_dir, NULL, - NULL, &smb_fname_parent); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1,("unix_mode(%s) failed, [dir %s]: %s\n", - smb_fname_str_dbg(smb_fname), - inherit_from_dir, nt_errstr(status))); - return(0); - } - - if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) { - DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", - smb_fname_str_dbg(smb_fname), + if (SMB_VFS_STAT(conn, inherit_from_dir, &sbuf) != 0) { + DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname, inherit_from_dir, strerror(errno))); - TALLOC_FREE(smb_fname_parent); return(0); /* *** shouldn't happen! *** */ } /* Save for later - but explicitly remove setuid bit for safety. */ - dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID; - DEBUG(2,("unix_mode(%s) inherit mode %o\n", - smb_fname_str_dbg(smb_fname), (int)dir_mode)); + dir_mode = sbuf.st_mode & ~S_ISUID; + DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode)); /* Clear "result" */ result = 0; - TALLOC_FREE(smb_fname_parent); } if (IS_DOS_DIR(dosmode)) { @@ -147,7 +131,7 @@ mode_t unix_mode(connection_struct *conn, int dosmode, if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode)) result |= S_IXGRP; - + if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode)) result |= S_IXOTH; @@ -162,8 +146,7 @@ mode_t unix_mode(connection_struct *conn, int dosmode, } } - DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname), - (int)result)); + DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result )); return(result); } @@ -171,38 +154,37 @@ mode_t unix_mode(connection_struct *conn, int dosmode, Change a unix mode to a dos mode. ****************************************************************************/ -static uint32 dos_mode_from_sbuf(connection_struct *conn, - const struct smb_filename *smb_fname) +static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf) { int result = 0; enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn)); if (ro_opts == MAP_READONLY_YES) { /* Original Samba method - map inverse of user "w" bit. */ - if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) { + if ((sbuf->st_mode & S_IWUSR) == 0) { result |= aRONLY; } } else if (ro_opts == MAP_READONLY_PERMISSIONS) { /* Check actual permissions for read-only. */ - if (!can_write_to_file(conn, smb_fname)) { + if (!can_write_to_file(conn, path, sbuf)) { result |= aRONLY; } } /* Else never set the readonly bit. */ - if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0)) + if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0)) result |= aARCH; - if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0)) + if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0)) result |= aSYSTEM; - - if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0)) + + if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0)) result |= aHIDDEN; - - if (S_ISDIR(smb_fname->st.st_ex_mode)) + + if (S_ISDIR(sbuf->st_mode)) result = aDIR | (result & aRONLY); - result |= set_sparse_flag(&smb_fname->st); - result |= set_link_read_only_flag(&smb_fname->st); + result |= set_sparse_flag(sbuf); + result |= set_link_read_only_flag(sbuf); DEBUG(8,("dos_mode_from_sbuf returning ")); @@ -211,26 +193,20 @@ static uint32 dos_mode_from_sbuf(connection_struct *conn, if (result & aSYSTEM) DEBUG(8, ("s")); if (result & aDIR ) DEBUG(8, ("d")); if (result & aARCH ) DEBUG(8, ("a")); - + DEBUG(8,("\n")); return result; } /**************************************************************************** Get DOS attributes from an EA. - This can also pull the create time into the stat struct inside smb_fname. ****************************************************************************/ -static bool get_ea_dos_attribute(connection_struct *conn, - struct smb_filename *smb_fname, - uint32 *pattr) +static bool get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr) { - struct xattr_DOSATTRIB dosattrib; - enum ndr_err_code ndr_err; - DATA_BLOB blob; ssize_t sizeret; fstring attrstr; - uint32_t dosattr; + unsigned int dosattr; if (!lp_store_dos_attributes(SNUM(conn))) { return False; @@ -239,9 +215,7 @@ static bool get_ea_dos_attribute(connection_struct *conn, /* Don't reset pattr to zero as we may already have filename-based attributes we need to preserve. */ - sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name, - SAMBA_XATTR_DOS_ATTRIB, attrstr, - sizeof(attrstr)); + sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr)); if (sizeret == -1) { if (errno == ENOSYS #if defined(ENOTSUP) @@ -249,75 +223,23 @@ static bool get_ea_dos_attribute(connection_struct *conn, #else ) { #endif - DEBUG(1,("get_ea_dos_attributes: Cannot get attribute " - "from EA on file %s: Error = %s\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); + DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n", + path, strerror(errno) )); set_store_dos_attributes(SNUM(conn), False); } return False; } + /* Null terminate string. */ + attrstr[sizeret] = 0; + DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr)); - blob.data = (uint8_t *)attrstr; - blob.length = sizeret; - - ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), NULL, &dosattrib, - (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB); - - DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n", - smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex)); - - switch (dosattrib.version) { - case 0xFFFF: - dosattr = dosattrib.info.compatinfoFFFF.attrib; - break; - case 1: - dosattr = dosattrib.info.info1.attrib; - if (!null_nttime(dosattrib.info.info1.create_time)) { - struct timespec create_time = - nt_time_to_unix_timespec( - &dosattrib.info.info1.create_time); - - update_stat_ex_create_time(&smb_fname->st, - create_time); - - DEBUG(10,("get_ea_dos_attributes: file %s case 1 " - "set btime %s\n", - smb_fname_str_dbg(smb_fname), - time_to_asc(convert_timespec_to_time_t( - create_time)) )); - } - break; - case 2: - dosattr = dosattrib.info.oldinfo2.attrib; - /* Don't know what flags to check for this case. */ - break; - case 3: - dosattr = dosattrib.info.info3.attrib; - if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) && - !null_nttime(dosattrib.info.info3.create_time)) { - struct timespec create_time = - nt_time_to_unix_timespec( - &dosattrib.info.info3.create_time); - - update_stat_ex_create_time(&smb_fname->st, - create_time); - - DEBUG(10,("get_ea_dos_attributes: file %s case 3 " - "set btime %s\n", - smb_fname_str_dbg(smb_fname), - time_to_asc(convert_timespec_to_time_t( - create_time)) )); - } - break; - default: - DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on " - "file %s - %s\n", smb_fname_str_dbg(smb_fname), - attrstr)); - return false; - } + if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' || + sscanf(attrstr, "%x", &dosattr) != 1) { + DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr)); + return False; + } - if (S_ISDIR(smb_fname->st.st_ex_mode)) { + if (S_ISDIR(sbuf->st_mode)) { dosattr |= aDIR; } *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK); @@ -329,7 +251,7 @@ static bool get_ea_dos_attribute(connection_struct *conn, if (dosattr & aSYSTEM) DEBUG(8, ("s")); if (dosattr & aDIR ) DEBUG(8, ("d")); if (dosattr & aARCH ) DEBUG(8, ("a")); - + DEBUG(8,("\n")); return True; @@ -337,50 +259,20 @@ static bool get_ea_dos_attribute(connection_struct *conn, /**************************************************************************** Set DOS attributes in an EA. - Also sets the create time. ****************************************************************************/ -static bool set_ea_dos_attribute(connection_struct *conn, - struct smb_filename *smb_fname, - uint32 dosmode) +static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode) { - struct xattr_DOSATTRIB dosattrib; - enum ndr_err_code ndr_err; - DATA_BLOB blob; + fstring attrstr; files_struct *fsp = NULL; - bool ret = false; + bool ret = False; if (!lp_store_dos_attributes(SNUM(conn))) { return False; } - ZERO_STRUCT(dosattrib); - ZERO_STRUCT(blob); - - dosattrib.version = 3; - dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB| - XATTR_DOSINFO_CREATE_TIME; - dosattrib.info.info3.attrib = dosmode; - unix_timespec_to_nt_time(&dosattrib.info.info3.create_time, - smb_fname->st.st_ex_btime); - - ndr_err = ndr_push_struct_blob( - &blob, talloc_tos(), NULL, &dosattrib, - (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB); - - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n", - ndr_errstr(ndr_err))); - return false; - } - - if (blob.data == NULL || blob.length == 0) { - return false; - } - - if (SMB_VFS_SETXATTR(conn, smb_fname->base_name, - SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length, - 0) == -1) { + snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK); + if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) { if((errno != EPERM) && (errno != EACCES)) { if (errno == ENOSYS #if defined(ENOTSUP) @@ -388,13 +280,11 @@ static bool set_ea_dos_attribute(connection_struct *conn, #else ) { #endif - DEBUG(1,("set_ea_dos_attributes: Cannot set " - "attribute EA on file %s: Error = %s\n", - smb_fname_str_dbg(smb_fname), - strerror(errno) )); + DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n", + path, strerror(errno) )); set_store_dos_attributes(SNUM(conn), False); } - return false; + return False; } /* We want DOS semantics, ie allow non owner with write permission to change the @@ -403,7 +293,7 @@ static bool set_ea_dos_attribute(connection_struct *conn, /* Check if we have write access. */ if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn))) - return false; + return False; /* * We need to open the file with write access whilst @@ -411,48 +301,43 @@ static bool set_ea_dos_attribute(connection_struct *conn, * are not violating security in doing the setxattr. */ - if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname, + if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, path, sbuf, &fsp))) return ret; become_root(); - if (SMB_VFS_SETXATTR(conn, smb_fname->base_name, - SAMBA_XATTR_DOS_ATTRIB, blob.data, - blob.length, 0) == 0) { - ret = true; + if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) { + ret = True; } unbecome_root(); close_file_fchmod(NULL, fsp); return ret; } - DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n", - (unsigned int)dosmode, - smb_fname_str_dbg(smb_fname))); - return true; + DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path)); + return True; } /**************************************************************************** Change a unix mode to a dos mode for an ms dfs link. ****************************************************************************/ -uint32 dos_mode_msdfs(connection_struct *conn, - const struct smb_filename *smb_fname) +uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf) { uint32 result = 0; - DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname))); + DEBUG(8,("dos_mode_msdfs: %s\n", path)); - if (!VALID_STAT(smb_fname->st)) { + if (!VALID_STAT(*sbuf)) { return 0; } /* First do any modifications that depend on the path name. */ /* hide files with a name starting with a . */ if (lp_hide_dot_files(SNUM(conn))) { - const char *p = strrchr_m(smb_fname->base_name, '/'); + const char *p = strrchr_m(path,'/'); if (p) { p++; } else { - p = smb_fname->base_name; + p = path; } /* Only . and .. are not hidden. */ @@ -461,13 +346,12 @@ uint32 dos_mode_msdfs(connection_struct *conn, result |= aHIDDEN; } } - - result |= dos_mode_from_sbuf(conn, smb_fname); + + result |= dos_mode_from_sbuf(conn, path, sbuf); /* Optimization : Only call is_hidden_path if it's not already hidden. */ - if (!(result & aHIDDEN) && - IS_HIDDEN_PATH(conn, smb_fname->base_name)) { + if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) { result |= aHIDDEN; } @@ -485,7 +369,7 @@ uint32 dos_mode_msdfs(connection_struct *conn, if (result & aDIR ) DEBUG(8, ("d")); if (result & aARCH ) DEBUG(8, ("a")); if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]")); - + DEBUG(8,("\n")); return(result); @@ -515,55 +399,56 @@ int dos_attributes_to_stat_dos_flags(uint32_t dosmode) } /**************************************************************************** - Gets DOS attributes, accessed via st_ex_flags in the stat struct. + Gets DOS attributes, accessed via st_flags in the stat struct. ****************************************************************************/ static bool get_stat_dos_flags(connection_struct *conn, - const struct smb_filename *smb_fname, + const char *fname, + const SMB_STRUCT_STAT *sbuf, uint32_t *dosmode) { - SMB_ASSERT(VALID_STAT(smb_fname->st)); + SMB_ASSERT(sbuf && VALID_STAT(*sbuf)); SMB_ASSERT(dosmode); if (!lp_store_dos_attributes(SNUM(conn))) { return false; } - DEBUG(5, ("Getting stat dos attributes for %s.\n", - smb_fname_str_dbg(smb_fname))); + DEBUG(5, ("Getting stat dos attributes for %s.\n", fname)); - if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE) + if (sbuf->st_flags & UF_DOS_ARCHIVE) *dosmode |= aARCH; - if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN) + if (sbuf->st_flags & UF_DOS_HIDDEN) *dosmode |= aHIDDEN; - if (smb_fname->st.st_ex_flags & UF_DOS_RO) + if (sbuf->st_flags & UF_DOS_RO) *dosmode |= aRONLY; - if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM) + if (sbuf->st_flags & UF_DOS_SYSTEM) *dosmode |= aSYSTEM; - if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX) + if (sbuf->st_flags & UF_DOS_NOINDEX) *dosmode |= FILE_ATTRIBUTE_NONINDEXED; - if (S_ISDIR(smb_fname->st.st_ex_mode)) + if (S_ISDIR(sbuf->st_mode)) *dosmode |= aDIR; - *dosmode |= set_sparse_flag(&smb_fname->st); - *dosmode |= set_link_read_only_flag(&smb_fname->st); + *dosmode |= set_sparse_flag(sbuf); + *dosmode |= set_link_read_only_flag(sbuf); return true; } /**************************************************************************** - Sets DOS attributes, stored in st_ex_flags of the inode. + Sets DOS attributes, stored in st_flags of the inode. ****************************************************************************/ static bool set_stat_dos_flags(connection_struct *conn, - const struct smb_filename *smb_fname, - uint32_t dosmode, - bool *attributes_changed) + const char *fname, + SMB_STRUCT_STAT *sbuf, + uint32_t dosmode, + bool *attributes_changed) { uint32_t new_flags = 0; int error = 0; - SMB_ASSERT(VALID_STAT(smb_fname->st)); + SMB_ASSERT(sbuf && VALID_STAT(*sbuf)); SMB_ASSERT(attributes_changed); *attributes_changed = false; @@ -572,25 +457,23 @@ static bool set_stat_dos_flags(connection_struct *conn, return false; } - DEBUG(5, ("Setting stat dos attributes for %s.\n", - smb_fname_str_dbg(smb_fname))); + DEBUG(5, ("Setting stat dos attributes for %s.\n", fname)); - new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) | + new_flags = (sbuf->st_flags & ~UF_DOS_FLAGS) | dos_attributes_to_stat_dos_flags(dosmode); /* Return early if no flags changed. */ - if (new_flags == smb_fname->st.st_ex_flags) + if (new_flags == sbuf->st_flags) return true; DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags, - smb_fname->st.st_ex_flags)); + sbuf->st_flags)); /* Set new flags with chflags. */ - error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags); + error = SMB_VFS_CHFLAGS(conn, fname, new_flags); if (error) { DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on " - "file %s! errno=%d\n", new_flags, - smb_fname_str_dbg(smb_fname), errno)); + "file %s! errno=%d\n", new_flags, fname, errno)); return false; } @@ -601,29 +484,27 @@ static bool set_stat_dos_flags(connection_struct *conn, /**************************************************************************** Change a unix mode to a dos mode. - May also read the create timespec into the stat struct in smb_fname - if "store dos attributes" is true. ****************************************************************************/ -uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname) +uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf) { uint32 result = 0; bool offline, used_stat_dos_flags = false; - DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname))); + DEBUG(8,("dos_mode: %s\n", path)); - if (!VALID_STAT(smb_fname->st)) { + if (!VALID_STAT(*sbuf)) { return 0; } /* First do any modifications that depend on the path name. */ /* hide files with a name starting with a . */ if (lp_hide_dot_files(SNUM(conn))) { - const char *p = strrchr_m(smb_fname->base_name,'/'); + const char *p = strrchr_m(path,'/'); if (p) { p++; } else { - p = smb_fname->base_name; + p = path; } /* Only . and .. are not hidden. */ @@ -632,28 +513,28 @@ uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname) result |= aHIDDEN; } } - + #ifdef HAVE_STAT_DOS_FLAGS - used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result); + used_stat_dos_flags = get_stat_dos_flags(conn, path, sbuf, &result); #endif if (!used_stat_dos_flags) { /* Get the DOS attributes from an EA by preference. */ - if (get_ea_dos_attribute(conn, smb_fname, &result)) { - result |= set_sparse_flag(&smb_fname->st); + if (get_ea_dos_attribute(conn, path, sbuf, &result)) { + result |= set_sparse_flag(sbuf); } else { - result |= dos_mode_from_sbuf(conn, smb_fname); + result |= dos_mode_from_sbuf(conn, path, sbuf); } } - offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &smb_fname->st); - if (S_ISREG(smb_fname->st.st_ex_mode) && offline) { + + offline = SMB_VFS_IS_OFFLINE(conn, path, sbuf); + if (S_ISREG(sbuf->st_mode) && offline) { result |= FILE_ATTRIBUTE_OFFLINE; } /* Optimization : Only call is_hidden_path if it's not already hidden. */ - if (!(result & aHIDDEN) && - IS_HIDDEN_PATH(conn, smb_fname->base_name)) { + if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) { result |= aHIDDEN; } @@ -671,7 +552,7 @@ uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname) if (result & aDIR ) DEBUG(8, ("d")); if (result & aARCH ) DEBUG(8, ("a")); if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]")); - + DEBUG(8,("\n")); return(result); @@ -679,51 +560,54 @@ uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname) /******************************************************************* chmod a file - but preserve some bits. - If "store dos attributes" is also set it will store the create time - from the stat struct in smb_fname (in NTTIME format) in the EA - attribute also. ********************************************************************/ -int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, - uint32 dosmode, const char *parent_dir, bool newfile) +int file_set_dosmode(connection_struct *conn, const char *fname, + uint32 dosmode, SMB_STRUCT_STAT *st, + const char *parent_dir, + bool newfile) { + SMB_STRUCT_STAT st1; int mask=0; mode_t tmp; mode_t unixmode; int ret = -1, lret = -1; uint32_t old_mode; - struct timespec new_create_timespec; /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */ dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE); - DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", - dosmode, smb_fname_str_dbg(smb_fname))); + DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname)); - unixmode = smb_fname->st.st_ex_mode; + if (st == NULL) { + SET_STAT_INVALID(st1); + st = &st1; + } + + if (!VALID_STAT(*st)) { + if (SMB_VFS_STAT(conn,fname,st)) + return(-1); + } - get_acl_group_bits(conn, smb_fname->base_name, - &smb_fname->st.st_ex_mode); + unixmode = st->st_mode; - if (S_ISDIR(smb_fname->st.st_ex_mode)) + get_acl_group_bits(conn, fname, &st->st_mode); + + if (S_ISDIR(st->st_mode)) dosmode |= aDIR; else dosmode &= ~aDIR; - new_create_timespec = smb_fname->st.st_ex_btime; - - old_mode = dos_mode(conn, smb_fname); - + old_mode = dos_mode(conn,fname,st); + if (dosmode & FILE_ATTRIBUTE_OFFLINE) { if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) { - lret = SMB_VFS_SET_OFFLINE(conn, smb_fname->base_name); + lret = SMB_VFS_SET_OFFLINE(conn, fname); if (lret == -1) { - DEBUG(0, ("set_dos_mode: client has asked to " - "set FILE_ATTRIBUTE_OFFLINE to " - "%s/%s but there was an error while " - "setting it or it is not " - "supported.\n", parent_dir, - smb_fname_str_dbg(smb_fname))); + DEBUG(0, ("set_dos_mode: client has asked to set " + "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was " + "an error while setting it or it is not supported.\n", + parent_dir, fname)); } } } @@ -731,37 +615,39 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, dosmode &= ~FILE_ATTRIBUTE_OFFLINE; old_mode &= ~FILE_ATTRIBUTE_OFFLINE; - smb_fname->st.st_ex_btime = new_create_timespec; + if (old_mode == dosmode) { + st->st_mode = unixmode; + return(0); + } #ifdef HAVE_STAT_DOS_FLAGS { bool attributes_changed; - if (set_stat_dos_flags(conn, smb_fname, dosmode, + if (set_stat_dos_flags(conn, fname, st, dosmode, &attributes_changed)) { if (!newfile && attributes_changed) { notify_fname(conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_ATTRIBUTES, - smb_fname->base_name); + FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); } - smb_fname->st.st_ex_mode = unixmode; + st->st_mode = unixmode; return 0; } } #endif + /* Store the DOS attributes in an EA by preference. */ - if (set_ea_dos_attribute(conn, smb_fname, dosmode)) { + if (set_ea_dos_attribute(conn, fname, st, dosmode)) { if (!newfile) { notify_fname(conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_ATTRIBUTES, - smb_fname->base_name); + FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); } - smb_fname->st.st_ex_mode = unixmode; + st->st_mode = unixmode; return 0; } - unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir); + unixmode = unix_mode(conn,dosmode,fname, parent_dir); /* preserve the s bits */ mask |= (S_ISUID | S_ISGID); @@ -779,10 +665,10 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, if (!MAP_HIDDEN(conn)) mask |= S_IXOTH; - unixmode |= (smb_fname->st.st_ex_mode & mask); + unixmode |= (st->st_mode & mask); /* if we previously had any r bits set then leave them alone */ - if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) { + if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) { unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH); unixmode |= tmp; } @@ -790,17 +676,16 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, /* if we previously had any w bits set then leave them alone whilst adding in the new w bits, if the new mode is not rdonly */ if (!IS_DOS_READONLY(dosmode)) { - unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); + unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); } - ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode); + ret = SMB_VFS_CHMOD(conn, fname, unixmode); if (ret == 0) { if(!newfile || (lret != -1)) { notify_fname(conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_ATTRIBUTES, - smb_fname->base_name); + FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); } - smb_fname->st.st_ex_mode = unixmode; + st->st_mode = unixmode; return 0; } @@ -825,8 +710,8 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, * break batch oplocks open by others. JRA. */ files_struct *fsp; - if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname, - &fsp))) + if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, st, + &fsp))) return -1; become_root(); ret = SMB_VFS_FCHMOD(fsp, unixmode); @@ -834,11 +719,10 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, close_file_fchmod(NULL, fsp); if (!newfile) { notify_fname(conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_ATTRIBUTES, - smb_fname->base_name); + FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); } if (ret == 0) { - smb_fname->st.st_ex_mode = unixmode; + st->st_mode = unixmode; } } @@ -850,19 +734,19 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, than POSIX. *******************************************************************/ -int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname, +int file_ntimes(connection_struct *conn, const char *fname, struct smb_file_time *ft) { + SMB_STRUCT_STAT sbuf; int ret = -1; errno = 0; + ZERO_STRUCT(sbuf); DEBUG(6, ("file_ntime: actime: %s", time_to_asc(convert_timespec_to_time_t(ft->atime)))); DEBUG(6, ("file_ntime: modtime: %s", time_to_asc(convert_timespec_to_time_t(ft->mtime)))); - DEBUG(6, ("file_ntime: ctime: %s", - time_to_asc(convert_timespec_to_time_t(ft->ctime)))); DEBUG(6, ("file_ntime: createtime: %s", time_to_asc(convert_timespec_to_time_t(ft->create_time)))); @@ -877,7 +761,7 @@ int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname, return 0; } - if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) { + if(SMB_VFS_NTIMES(conn, fname, ft) == 0) { return 0; } @@ -896,10 +780,10 @@ int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname, */ /* Check if we have write access. */ - if (can_write_to_file(conn, smb_fname)) { + if (can_write_to_file(conn, fname, &sbuf)) { /* We are allowed to become root and change the filetime. */ become_root(); - ret = SMB_VFS_NTIMES(conn, smb_fname, ft); + ret = SMB_VFS_NTIMES(conn, fname, ft); unbecome_root(); } @@ -911,7 +795,8 @@ int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname, returned on all future write time queries and set on close. ******************************************************************/ -bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime) +bool set_sticky_write_time_path(connection_struct *conn, const char *fname, + struct file_id fileid, const struct timespec mtime) { if (null_timespec(mtime)) { return true; @@ -929,77 +814,27 @@ bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime) returned on all future write time queries and set on close. ******************************************************************/ -bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime) +bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime) { - if (null_timespec(mtime)) { - return true; - } - fsp->write_time_forced = true; TALLOC_FREE(fsp->update_write_time_event); - return set_sticky_write_time_path(fsp->file_id, mtime); + return set_sticky_write_time_path(fsp->conn, fsp->fsp_name, + fsp->file_id, mtime); } /****************************************************************** - Set a create time EA. + Update a write time immediately, without the 2 second delay. ******************************************************************/ -NTSTATUS set_create_timespec_ea(connection_struct *conn, - const struct smb_filename *psmb_fname, - struct timespec create_time) +bool update_write_time(struct files_struct *fsp) { - NTSTATUS status; - struct smb_filename *smb_fname = NULL; - uint32_t dosmode; - int ret; - - if (!lp_store_dos_attributes(SNUM(conn))) { - return NT_STATUS_OK; - } - - status = create_synthetic_smb_fname(talloc_tos(), - psmb_fname->base_name, - NULL, &psmb_fname->st, - &smb_fname); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - dosmode = dos_mode(conn, smb_fname); - - smb_fname->st.st_ex_btime = create_time; - - ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false); - if (ret == -1) { - map_nt_error_from_unix(errno); + if (!set_write_time(fsp->file_id, timespec_current())) { + return false; } - DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n", - smb_fname_str_dbg(smb_fname))); - - return NT_STATUS_OK; -} - -/****************************************************************** - Return a create time. -******************************************************************/ - -struct timespec get_create_timespec(connection_struct *conn, - struct files_struct *fsp, - const struct smb_filename *smb_fname) -{ - return smb_fname->st.st_ex_btime; -} + notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name); -/****************************************************************** - Return a change time (may look at EA in future). -******************************************************************/ - -struct timespec get_change_timespec(connection_struct *conn, - struct files_struct *fsp, - const struct smb_filename *smb_fname) -{ - return smb_fname->st.st_ex_mtime; + return true; } diff --git a/source3/smbd/error.c b/source3/smbd/error.c index 252eb77416..ce22f86414 100644 --- a/source3/smbd/error.c +++ b/source3/smbd/error.c @@ -30,29 +30,9 @@ bool use_nt_status(void) /**************************************************************************** Create an error packet. Normally called using the ERROR() macro. - - Setting eclass and ecode to zero and status to a valid NT error will - reply with an NT error if the client supports CAP_STATUS32, otherwise - it maps to and returns a DOS error if the client doesn't support CAP_STATUS32. - This is the normal mode of calling this function via reply_nterror(req, status). - - Setting eclass and ecode to non-zero and status to NT_STATUS_OK (0) will map - from a DOS error to an NT error and reply with an NT error if the client - supports CAP_STATUS32, otherwise it replies with the given DOS error. - This mode is currently not used in the server. - - Setting both eclass, ecode and status to non-zero values allows a non-default - mapping from NT error codes to DOS error codes, and will return one or the - other depending on the client supporting CAP_STATUS32 or not. This is the - path taken by calling reply_botherror(req, eclass, ecode, status); - - Setting status to NT_STATUS_DOS(eclass, ecode) forces DOS errors even if the - client supports CAP_STATUS32. This is the path taken to force a DOS error - reply by calling reply_force_doserror(req, eclass, ecode). - - Setting status only and eclass to -1 forces NT errors even if the client - doesn't support CAP_STATUS32. This mode is currently never used in the - server. + Setting eclass and ecode only and status to NT_STATUS_OK forces DOS errors. + Setting status only and eclass and ecode to zero forces NT errors. + If the override errors are set they take precedence over any passed in values. ****************************************************************************/ void error_packet_set(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file) @@ -115,20 +95,21 @@ void reply_nt_error(struct smb_request *req, NTSTATUS ntstatus, error_packet_set((char *)req->outbuf, 0, 0, ntstatus, line, file); } -/**************************************************************************** - Forces a DOS error on the wire. -****************************************************************************/ +void reply_force_nt_error(struct smb_request *req, NTSTATUS ntstatus, + int line, const char *file) +{ + TALLOC_FREE(req->outbuf); + reply_outbuf(req, 0, 0); + error_packet_set((char *)req->outbuf, -1, -1, ntstatus, line, file); +} -void reply_force_dos_error(struct smb_request *req, uint8 eclass, uint32 ecode, +void reply_dos_error(struct smb_request *req, uint8 eclass, uint32 ecode, int line, const char *file) { TALLOC_FREE(req->outbuf); reply_outbuf(req, 0, 0); - error_packet_set((char *)req->outbuf, - eclass, ecode, - NT_STATUS_DOS(eclass, ecode), - line, - file); + error_packet_set((char *)req->outbuf, eclass, ecode, NT_STATUS_OK, line, + file); } void reply_both_error(struct smb_request *req, uint8 eclass, uint32 ecode, @@ -151,12 +132,37 @@ void reply_openerror(struct smb_request *req, NTSTATUS status) */ reply_botherror(req, NT_STATUS_OBJECT_NAME_COLLISION, ERRDOS, ERRfilexists); - } else if (NT_STATUS_EQUAL(status, NT_STATUS_TOO_MANY_OPENED_FILES)) { - /* EMFILE always seems to be returned as a DOS error. - * See bug 6837. NOTE this forces a DOS error on the wire - * even though it's calling reply_nterror(). */ - reply_force_doserror(req, ERRDOS, ERRnofids); } else { reply_nterror(req, status); } } + +void reply_unix_error(struct smb_request *req, uint8 defclass, uint32 defcode, + NTSTATUS defstatus, int line, const char *file) +{ + int eclass=defclass; + int ecode=defcode; + NTSTATUS ntstatus = defstatus; + int i=0; + + TALLOC_FREE(req->outbuf); + reply_outbuf(req, 0, 0); + + if (errno != 0) { + DEBUG(3,("unix_error_packet: error string = %s\n", + strerror(errno))); + + while (unix_dos_nt_errmap[i].dos_class != 0) { + if (unix_dos_nt_errmap[i].unix_error == errno) { + eclass = unix_dos_nt_errmap[i].dos_class; + ecode = unix_dos_nt_errmap[i].dos_code; + ntstatus = unix_dos_nt_errmap[i].nt_error; + break; + } + i++; + } + } + + error_packet_set((char *)req->outbuf, eclass, ecode, ntstatus, + line, file); +} diff --git a/source3/smbd/fake_file.c b/source3/smbd/fake_file.c index 6898793d29..ef54398bc4 100644 --- a/source3/smbd/fake_file.c +++ b/source3/smbd/fake_file.c @@ -71,45 +71,28 @@ static struct fake_file_handle *init_fake_file_handle(enum FAKE_FILE_TYPE type) Does this name match a fake filename ? ****************************************************************************/ -enum FAKE_FILE_TYPE is_fake_file_path(const char *path) +enum FAKE_FILE_TYPE is_fake_file(const char *fname) { +#ifdef HAVE_SYS_QUOTAS int i; +#endif - if (!path) { + if (!fname) { return FAKE_FILE_TYPE_NONE; } +#ifdef HAVE_SYS_QUOTAS for (i=0;fake_files[i].name!=NULL;i++) { - if (strncmp(path,fake_files[i].name,strlen(fake_files[i].name))==0) { - DEBUG(5,("is_fake_file: [%s] is a fake file\n",path)); + if (strncmp(fname,fake_files[i].name,strlen(fake_files[i].name))==0) { + DEBUG(5,("is_fake_file: [%s] is a fake file\n",fname)); return fake_files[i].type; } } +#endif return FAKE_FILE_TYPE_NONE; } -enum FAKE_FILE_TYPE is_fake_file(const struct smb_filename *smb_fname) -{ - char *fname = NULL; - NTSTATUS status; - enum FAKE_FILE_TYPE ret; - - if (!smb_fname) { - return FAKE_FILE_TYPE_NONE; - } - - status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - return FAKE_FILE_TYPE_NONE; - } - - ret = is_fake_file_path(fname); - - TALLOC_FREE(fname); - - return ret; -} /**************************************************************************** Open a fake quota file with a share mode. @@ -118,7 +101,7 @@ enum FAKE_FILE_TYPE is_fake_file(const struct smb_filename *smb_fname) NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, uint16_t current_vuid, enum FAKE_FILE_TYPE fake_file_type, - const struct smb_filename *smb_fname, + const char *fname, uint32 access_mask, files_struct **result) { @@ -129,8 +112,7 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, if (conn->server_info->utok.uid != 0) { DEBUG(3, ("open_fake_file_shared: access_denied to " "service[%s] file[%s] user[%s]\n", - lp_servicename(SNUM(conn)), - smb_fname_str_dbg(smb_fname), + lp_servicename(SNUM(conn)), fname, conn->server_info->unix_name)); return NT_STATUS_ACCESS_DENIED; @@ -142,8 +124,7 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, } DEBUG(5,("open_fake_file_shared: fname = %s, FID = %d, access_mask = 0x%x\n", - smb_fname_str_dbg(smb_fname), fsp->fnum, - (unsigned int)access_mask)); + fname, fsp->fnum, (unsigned int)access_mask)); fsp->conn = conn; fsp->fh->fd = -1; @@ -151,12 +132,8 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, fsp->fh->pos = -1; fsp->can_lock = False; /* Should this be true ? - No, JRA */ fsp->access_mask = access_mask; - status = fsp_set_smb_fname(fsp, smb_fname); - if (!NT_STATUS_IS_OK(status)) { - file_free(req, fsp); - return NT_STATUS_NO_MEMORY; - } - + string_set(&fsp->fsp_name,fname); + fsp->fake_file_handle = init_fake_file_handle(fake_file_type); if (fsp->fake_file_handle==NULL) { diff --git a/source3/smbd/file_access.c b/source3/smbd/file_access.c index 7d0a552956..1c0124ecbc 100644 --- a/source3/smbd/file_access.c +++ b/source3/smbd/file_access.c @@ -27,36 +27,32 @@ * Security descriptor / NT Token level access check function. */ bool can_access_file_acl(struct connection_struct *conn, - const struct smb_filename *smb_fname, - uint32_t access_mask) + const char * fname, + uint32_t access_mask) { NTSTATUS status; uint32_t access_granted; struct security_descriptor *secdesc = NULL; - bool ret; if (conn->server_info->utok.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ return true; } - status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name, + status = SMB_VFS_GET_NT_ACL(conn, fname, (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION), &secdesc); if (!NT_STATUS_IS_OK(status)) { DEBUG(5, ("Could not get acl: %s\n", nt_errstr(status))); - ret = false; - goto out; + return false; } status = se_access_check(secdesc, conn->server_info->ptok, access_mask, &access_granted); - ret = NT_STATUS_IS_OK(status); - out: TALLOC_FREE(secdesc); - return ret; + return NT_STATUS_IS_OK(status); } /**************************************************************************** @@ -64,67 +60,50 @@ bool can_access_file_acl(struct connection_struct *conn, this to successfully return ACCESS_DENIED on a file open for delete access. ****************************************************************************/ -bool can_delete_file_in_directory(connection_struct *conn, - struct smb_filename *smb_fname) +bool can_delete_file_in_directory(connection_struct *conn, const char *fname) { + SMB_STRUCT_STAT sbuf; TALLOC_CTX *ctx = talloc_tos(); char *dname = NULL; - struct smb_filename *smb_fname_parent = NULL; - NTSTATUS status; - bool ret; if (!CAN_WRITE(conn)) { return False; } /* Get the parent directory permission mask and owners. */ - if (!parent_dirname(ctx, smb_fname->base_name, &dname, NULL)) { + if (!parent_dirname(ctx, fname, &dname, NULL)) { return False; } - - status = create_synthetic_smb_fname(ctx, dname, NULL, NULL, - &smb_fname_parent); - if (!NT_STATUS_IS_OK(status)) { - ret = false; - goto out; - } - - if(SMB_VFS_STAT(conn, smb_fname_parent) != 0) { - ret = false; - goto out; + if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) { + return False; } /* fast paths first */ - if (!S_ISDIR(smb_fname_parent->st.st_ex_mode)) { - ret = false; - goto out; + if (!S_ISDIR(sbuf.st_mode)) { + return False; } if (conn->server_info->utok.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ - ret = true; - goto out; + return True; } #ifdef S_ISVTX /* sticky bit means delete only by owner of file or by root or * by owner of directory. */ - if (smb_fname_parent->st.st_ex_mode & S_ISVTX) { - if(SMB_VFS_STAT(conn, smb_fname) != 0) { + if (sbuf.st_mode & S_ISVTX) { + SMB_STRUCT_STAT sbuf_file; + if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) { if (errno == ENOENT) { /* If the file doesn't already exist then * yes we'll be able to delete it. */ - ret = true; - goto out; + return True; } DEBUG(10,("can_delete_file_in_directory: can't " - "stat file %s (%s)", - smb_fname_str_dbg(smb_fname), - strerror(errno) )); - ret = false; - goto out; + "stat file %s (%s)", + fname, strerror(errno) )); + return False; } - /* * Patch from SATOH Fumiyasu <fumiyas@miraclelinux.com> * for bug #3348. Don't assume owning sticky bit @@ -133,15 +112,12 @@ bool can_delete_file_in_directory(connection_struct *conn, * or the owner of the directory as we have no possible * chance of deleting. Otherwise, go on and check the ACL. */ - if ((conn->server_info->utok.uid != - smb_fname_parent->st.st_ex_uid) && - (conn->server_info->utok.uid != smb_fname->st.st_ex_uid)) { + if ((conn->server_info->utok.uid != sbuf.st_uid) && + (conn->server_info->utok.uid != sbuf_file.st_uid)) { DEBUG(10,("can_delete_file_in_directory: not " - "owner of file %s or directory %s", - smb_fname_str_dbg(smb_fname), - smb_fname_str_dbg(smb_fname_parent))); - ret = false; - goto out; + "owner of file %s or directory %s", + fname, dname)); + return False; } } #endif @@ -157,11 +133,7 @@ bool can_delete_file_in_directory(connection_struct *conn, * check the file DELETE permission separately. */ - ret = can_access_file_acl(conn, smb_fname_parent, FILE_DELETE_CHILD); - out: - TALLOC_FREE(dname); - TALLOC_FREE(smb_fname_parent); - return ret; + return can_access_file_acl(conn, dname, FILE_DELETE_CHILD); } /**************************************************************************** @@ -170,9 +142,7 @@ bool can_delete_file_in_directory(connection_struct *conn, Note this doesn't take into account share write permissions. ****************************************************************************/ -bool can_access_file_data(connection_struct *conn, - const struct smb_filename *smb_fname, - uint32 access_mask) +bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask) { if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) { return False; @@ -182,31 +152,32 @@ bool can_access_file_data(connection_struct *conn, /* some fast paths first */ DEBUG(10,("can_access_file_data: requesting 0x%x on file %s\n", - (unsigned int)access_mask, smb_fname_str_dbg(smb_fname))); + (unsigned int)access_mask, fname )); if (conn->server_info->utok.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ return True; } - SMB_ASSERT(VALID_STAT(smb_fname->st)); + if (!VALID_STAT(*psbuf)) { + /* Get the file permission mask and owners. */ + if(SMB_VFS_STAT(conn, fname, psbuf) != 0) { + return False; + } + } /* Check primary owner access. */ - if (conn->server_info->utok.uid == smb_fname->st.st_ex_uid) { + if (conn->server_info->utok.uid == psbuf->st_uid) { switch (access_mask) { case FILE_READ_DATA: - return (smb_fname->st.st_ex_mode & S_IRUSR) ? - True : False; + return (psbuf->st_mode & S_IRUSR) ? True : False; case FILE_WRITE_DATA: - return (smb_fname->st.st_ex_mode & S_IWUSR) ? - True : False; + return (psbuf->st_mode & S_IWUSR) ? True : False; default: /* FILE_READ_DATA|FILE_WRITE_DATA */ - if ((smb_fname->st.st_ex_mode & - (S_IWUSR|S_IRUSR)) == - (S_IWUSR|S_IRUSR)) { + if ((psbuf->st_mode & (S_IWUSR|S_IRUSR)) == (S_IWUSR|S_IRUSR)) { return True; } else { return False; @@ -216,7 +187,7 @@ bool can_access_file_data(connection_struct *conn, /* now for ACL checks */ - return can_access_file_acl(conn, smb_fname, access_mask); + return can_access_file_acl(conn, fname, access_mask); } /**************************************************************************** @@ -224,10 +195,9 @@ bool can_access_file_data(connection_struct *conn, Note this doesn't take into account share write permissions. ****************************************************************************/ -bool can_write_to_file(connection_struct *conn, - const struct smb_filename *smb_fname) +bool can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) { - return can_access_file_data(conn, smb_fname, FILE_WRITE_DATA); + return can_access_file_data(conn, fname, psbuf, FILE_WRITE_DATA); } /**************************************************************************** diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index 1c27fef09b..adf664b396 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -57,7 +57,6 @@ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) /* you can't read from print files */ if (fsp->print_file) { - errno = EBADF; return -1; } @@ -103,7 +102,7 @@ tryagain: } DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n", - fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret)); + fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); fsp->fh->pos += ret; fsp->fh->position_information = fsp->fh->pos; @@ -136,7 +135,7 @@ static ssize_t real_write_file(struct smb_request *req, } DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n", - fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret)); + fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); if (ret != -1) { fsp->fh->pos += ret; @@ -164,31 +163,25 @@ static int wcp_file_size_change(files_struct *fsp) wcp->file_size = wcp->offset + wcp->data_size; ret = SMB_VFS_FTRUNCATE(fsp, wcp->file_size); if (ret == -1) { - DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f " - "error %s\n", fsp_str_dbg(fsp), - (double)wcp->file_size, strerror(errno))); + DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f error %s\n", + fsp->fsp_name, (double)wcp->file_size, strerror(errno) )); } return ret; } -void update_write_time_handler(struct event_context *ctx, +static void update_write_time_handler(struct event_context *ctx, struct timed_event *te, struct timeval now, void *private_data) { files_struct *fsp = (files_struct *)private_data; - DEBUG(5, ("Update write time on %s\n", fsp_str_dbg(fsp))); - - /* change the write time in the open file db. */ - (void)set_write_time(fsp->file_id, timespec_current()); - - /* And notify. */ - notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name->base_name); - /* Remove the timed event handler. */ TALLOC_FREE(fsp->update_write_time_event); + DEBUG(5, ("Update write time on %s\n", fsp->fsp_name)); + + /* change the write time if not already changed by someone else */ + update_write_time(fsp); } /********************************************************* @@ -200,11 +193,6 @@ void trigger_write_time_update(struct files_struct *fsp) { int delay; - if (fsp->posix_open) { - /* Don't use delayed writes on POSIX files. */ - return; - } - if (fsp->write_time_forced) { /* No point - "sticky" write times * in effect. @@ -212,16 +200,11 @@ void trigger_write_time_update(struct files_struct *fsp) return; } - /* We need to remember someone did a write - * and update to current time on close. */ - - fsp->update_write_time_on_close = true; - if (fsp->update_write_time_triggered) { /* - * We only update the write time after 2 seconds - * on the first normal write. After that - * no other writes affect this until close. + * We only update the write time + * on the first write. After that + * no other writes affect this. */ return; } @@ -231,10 +214,8 @@ void trigger_write_time_update(struct files_struct *fsp) "smbd", "writetimeupdatedelay", WRITE_TIME_UPDATE_USEC_DELAY); - DEBUG(5, ("Update write time %d usec later on %s\n", - delay, fsp_str_dbg(fsp))); - /* trigger the update 2 seconds later */ + fsp->update_write_time_on_close = true; fsp->update_write_time_event = event_add_timed(smbd_event_context(), NULL, timeval_current_ofs(0, delay), @@ -243,13 +224,6 @@ void trigger_write_time_update(struct files_struct *fsp) void trigger_write_time_update_immediate(struct files_struct *fsp) { - struct smb_file_time ft; - - if (fsp->posix_open) { - /* Don't use delayed writes on POSIX files. */ - return; - } - if (fsp->write_time_forced) { /* * No point - "sticky" write times @@ -259,21 +233,12 @@ void trigger_write_time_update_immediate(struct files_struct *fsp) } TALLOC_FREE(fsp->update_write_time_event); - DEBUG(5, ("Update write time immediate on %s\n", - fsp_str_dbg(fsp))); + DEBUG(5, ("Update write time immediate on %s\n", fsp->fsp_name)); - /* After an immediate update, reset the trigger. */ fsp->update_write_time_triggered = true; - fsp->update_write_time_on_close = false; - ZERO_STRUCT(ft); - ft.mtime = timespec_current(); - - /* Update the time in the open file db. */ - (void)set_write_time(fsp->file_id, ft.mtime); - - /* Now set on disk - takes care of notify. */ - (void)smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false); + fsp->update_write_time_on_close = false; + update_write_time(fsp); } /**************************************************************************** @@ -309,17 +274,20 @@ ssize_t write_file(struct smb_request *req, } if (!fsp->modified) { + SMB_STRUCT_STAT st; fsp->modified = True; - if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) == 0) { + if (SMB_VFS_FSTAT(fsp, &st) == 0) { int dosmode; trigger_write_time_update(fsp); - dosmode = dos_mode(fsp->conn, fsp->fsp_name); + dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) { - file_set_dosmode(fsp->conn, fsp->fsp_name, - dosmode | aARCH, NULL, false); + file_set_dosmode(fsp->conn,fsp->fsp_name, + dosmode | aARCH,&st, + NULL, + false); } /* @@ -328,8 +296,7 @@ ssize_t write_file(struct smb_request *req, */ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) { - setup_write_cache(fsp, - fsp->fsp_name->st.st_ex_size); + setup_write_cache(fsp, st.st_size); wcp = fsp->wcp; } } @@ -394,10 +361,8 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", return total_written; } - DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f " - "wcp->data_size=%u\n", fsp_str_dbg(fsp), fsp->fh->fd, - (double)pos, (unsigned int)n, (double)wcp->offset, - (unsigned int)wcp->data_size)); + DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n", + fsp->fsp_name, fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); fsp->fh->pos = pos + n; @@ -842,8 +807,7 @@ void delete_write_cache(files_struct *fsp) SAFE_FREE(wcp->data); SAFE_FREE(fsp->wcp); - DEBUG(10,("delete_write_cache: File %s deleted write cache\n", - fsp_str_dbg(fsp))); + DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name )); } /**************************************************************************** @@ -886,7 +850,7 @@ static bool setup_write_cache(files_struct *fsp, SMB_OFF_T file_size) allocated_write_caches++; DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n", - fsp_str_dbg(fsp), (unsigned long)wcp->alloc_size)); + fsp->fsp_name, (unsigned long)wcp->alloc_size )); return True; } @@ -903,7 +867,7 @@ void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size) char *msg; if (asprintf(&msg, "set_filelen_write_cache: size change " "on file %s with write cache size = %lu\n", - fsp->fsp_name->base_name, + fsp->fsp_name, (unsigned long)fsp->wcp->data_size) != -1) { smb_panic(msg); } else { @@ -982,15 +946,11 @@ NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_throug Perform a stat whether a valid fd or not. ************************************************************/ -int fsp_stat(files_struct *fsp) +int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst) { if (fsp->fh->fd == -1) { - if (fsp->posix_open) { - return SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name); - } else { - return SMB_VFS_STAT(fsp->conn, fsp->fsp_name); - } + return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst); } else { - return SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st); + return SMB_VFS_FSTAT(fsp, pst); } } diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index ab79dfd926..e3acfc8483 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -29,7 +29,10 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *orig_path, - struct smb_filename *smb_fname); + const char *basepath, + const char *streamname, + SMB_STRUCT_STAT *pst, + char **path); /**************************************************************************** Mangle the 2nd name and check if it is then equal to the first name. @@ -80,28 +83,10 @@ static NTSTATUS determine_path_error(const char *name, } } -static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname) -{ - /* Ensure we catch all names with in "/." - this is disallowed under Windows and - in POSIX they've already been removed. */ - const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/ - if (p) { - if (p[2] == '/') { - /* Error code within a pathname. */ - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } else if (p[2] == '\0') { - /* Error code at the end of a pathname. */ - return NT_STATUS_OBJECT_NAME_INVALID; - } - } - return NT_STATUS_OK; -} - /**************************************************************************** This routine is called to convert names from the dos namespace to unix -namespace. It needs to handle any case conversions, mangling, format changes, -streams etc. +namespace. It needs to handle any case conversions, mangling, format +changes etc. We assume that we have already done a chdir() to the right "root" directory for this service. @@ -109,61 +94,55 @@ for this service. The function will return an NTSTATUS error if some part of the name except for the last part cannot be resolved, else NT_STATUS_OK. -Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we -didn't get any fatal errors that should immediately terminate the calling SMB -processing whilst resolving. +Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we didn't +get any fatal errors that should immediately terminate the calling +SMB processing whilst resolving. -If the UCF_SAVE_LCOMP flag is passed in, then the unmodified last component -of the pathname is set in smb_filename->original_lcomp. +If the saved_last_component != 0, then the unmodified last component +of the pathname is returned there. If saved_last_component == 0 then nothing +is returned there. -If UCF_ALWAYS_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard was detected -and should be allowed in the last component of the path only. +If last_component_wcard is true then a MS wildcard was detected and +should be allowed in the last component of the path only. -If the orig_path was a stream, smb_filename->base_name will point to the base -filename, and smb_filename->stream_name will point to the stream name. If -orig_path was not a stream, then smb_filename->stream_name will be NULL. - -On exit from unix_convert, the smb_filename->st stat struct will be populated -if the file exists and was found, if not this stat struct will be filled with -zeros (and this can be detected by checking for nlinks = 0, which can never be -true for any file). +On exit from unix_convert, if *pst was not null, then the file stat +struct will be returned if the file exists and was found, if not this +stat struct will be filled with zeros (and this can be detected by checking +for nlinks = 0, which can never be true for any file). ****************************************************************************/ NTSTATUS unix_convert(TALLOC_CTX *ctx, - connection_struct *conn, - const char *orig_path, - struct smb_filename **smb_fname_out, - uint32_t ucf_flags) + connection_struct *conn, + const char *orig_path, + bool allow_wcard_last_component, + char **pp_conv_path, + char **pp_saved_last_component, + SMB_STRUCT_STAT *pst) { - struct smb_filename *smb_fname = NULL; + SMB_STRUCT_STAT st; char *start, *end; char *dirpath = NULL; + char *name = NULL; char *stream = NULL; bool component_was_mangled = False; bool name_has_wildcard = False; bool posix_pathnames = false; - bool allow_wcard_last_component = - (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP); - bool save_last_component = ucf_flags & UCF_SAVE_LCOMP; - NTSTATUS status; + NTSTATUS result; int ret = -1; - *smb_fname_out = NULL; - - smb_fname = talloc_zero(ctx, struct smb_filename); - if (smb_fname == NULL) { - return NT_STATUS_NO_MEMORY; + SET_STAT_INVALID(*pst); + *pp_conv_path = NULL; + if(pp_saved_last_component) { + *pp_saved_last_component = NULL; } if (conn->printer) { /* we don't ever use the filenames on a printer share as a filename - so don't convert them */ - if (!(smb_fname->base_name = talloc_strdup(smb_fname, - orig_path))) { - status = NT_STATUS_NO_MEMORY; - goto err; + if (!(*pp_conv_path = talloc_strdup(ctx,orig_path))) { + return NT_STATUS_NO_MEMORY; } - goto done; + return NT_STATUS_OK; } DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path)); @@ -191,16 +170,15 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (!*orig_path) { - if (!(smb_fname->base_name = talloc_strdup(smb_fname, "."))) { - status = NT_STATUS_NO_MEMORY; - goto err; + if (!(name = talloc_strdup(ctx,"."))) { + return NT_STATUS_NO_MEMORY; } - if (SMB_VFS_STAT(conn, smb_fname) != 0) { - status = map_nt_error_from_unix(errno); - goto err; + if (SMB_VFS_STAT(conn,name,&st) == 0) { + *pst = st; + } else { + return map_nt_error_from_unix(errno); } - DEBUG(5, ("conversion finished \"\" -> %s\n", - smb_fname->base_name)); + DEBUG(5,("conversion finished \"\" -> %s\n",name)); goto done; } @@ -208,19 +186,17 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, orig_path[1] == '\0')) { /* Start of pathname can't be "." only. */ if (orig_path[1] == '\0' || orig_path[2] == '\0') { - status = NT_STATUS_OBJECT_NAME_INVALID; + result = NT_STATUS_OBJECT_NAME_INVALID; } else { - status =determine_path_error(&orig_path[2], - allow_wcard_last_component); + result =determine_path_error( + &orig_path[2], allow_wcard_last_component); } - goto err; + return result; } - /* Start with the full orig_path as given by the caller. */ - if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) { + if (!(name = talloc_strdup(ctx, orig_path))) { DEBUG(0, ("talloc_strdup failed\n")); - status = NT_STATUS_NO_MEMORY; - goto err; + return NT_STATUS_NO_MEMORY; } /* @@ -234,69 +210,50 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if (conn->case_sensitive && !conn->case_preserve && !conn->short_case_preserve) { - strnorm(smb_fname->base_name, lp_defaultcase(SNUM(conn))); + strnorm(name, lp_defaultcase(SNUM(conn))); } /* * Ensure saved_last_component is valid even if file exists. */ - if(save_last_component) { - end = strrchr_m(smb_fname->base_name, '/'); + if(pp_saved_last_component) { + end = strrchr_m(name, '/'); if (end) { - smb_fname->original_lcomp = talloc_strdup(smb_fname, - end + 1); + *pp_saved_last_component = talloc_strdup(ctx, end + 1); } else { - smb_fname->original_lcomp = - talloc_strdup(smb_fname, smb_fname->base_name); - } - if (smb_fname->original_lcomp == NULL) { - status = NT_STATUS_NO_MEMORY; - goto err; + *pp_saved_last_component = talloc_strdup(ctx, + name); } } - posix_pathnames = (lp_posix_pathnames() || - (ucf_flags & UCF_POSIX_PATHNAMES)); + posix_pathnames = lp_posix_pathnames(); - /* - * Strip off the stream, and add it back when we're done with the - * base_name. - */ if (!posix_pathnames) { - stream = strchr_m(smb_fname->base_name, ':'); + stream = strchr_m(name, ':'); if (stream != NULL) { - char *tmp = talloc_strdup(smb_fname, stream); + char *tmp = talloc_strdup(ctx, stream); if (tmp == NULL) { - status = NT_STATUS_NO_MEMORY; - goto err; + TALLOC_FREE(name); + return NT_STATUS_NO_MEMORY; } - /* - * Since this is actually pointing into - * smb_fname->base_name this truncates base_name. - */ *stream = '\0'; stream = tmp; } } - start = smb_fname->base_name; + start = name; - /* - * If we're providing case insentive semantics or + /* If we're providing case insentive semantics or * the underlying filesystem is case insensitive, * then a case-normalized hit in the stat-cache is * authoratitive. JRA. - * - * Note: We're only checking base_name. The stream_name will be - * added and verified in build_stream_path(). */ - if((!conn->case_sensitive || !(conn->fs_capabilities & - FILE_CASE_SENSITIVE_SEARCH)) && - stat_cache_lookup(conn, &smb_fname->base_name, &dirpath, &start, - &smb_fname->st)) { + if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && + stat_cache_lookup(conn, &name, &dirpath, &start, &st)) { + *pst = st; goto done; } @@ -307,108 +264,53 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) { DEBUG(0, ("talloc_strdup failed\n")); - status = NT_STATUS_NO_MEMORY; - goto err; + TALLOC_FREE(name); + return NT_STATUS_NO_MEMORY; } /* - * If we have a wildcard we must walk the path to - * find where the error is, even if case sensitive - * is true. + * stat the name - if it exists then we are all done! */ - name_has_wildcard = ms_has_wild(smb_fname->base_name); - if (name_has_wildcard && !allow_wcard_last_component) { - /* Wildcard not valid anywhere. */ - status = NT_STATUS_OBJECT_NAME_INVALID; - goto fail; + if (posix_pathnames) { + ret = SMB_VFS_LSTAT(conn,name,&st); + } else { + ret = SMB_VFS_STAT(conn,name,&st); } - DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", - smb_fname->base_name, dirpath, start)); - - if (!name_has_wildcard) { - /* - * stat the name - if it exists then we can add the stream back (if - * there was one) and be done! - */ - - if (posix_pathnames) { - ret = SMB_VFS_LSTAT(conn, smb_fname); - } else { - ret = SMB_VFS_STAT(conn, smb_fname); - } - - if (ret == 0) { - status = check_for_dot_component(smb_fname); - if (!NT_STATUS_IS_OK(status)) { + if (ret == 0) { + /* Ensure we catch all names with in "/." + this is disallowed under Windows. */ + const char *p = strstr(name, "/."); /* mb safe. */ + if (p) { + if (p[2] == '/') { + /* Error code within a pathname. */ + result = NT_STATUS_OBJECT_PATH_NOT_FOUND; + goto fail; + } else if (p[2] == '\0') { + /* Error code at the end of a pathname. */ + result = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } - /* Add the path (not including the stream) to the cache. */ - stat_cache_add(orig_path, smb_fname->base_name, - conn->case_sensitive); - DEBUG(5,("conversion of base_name finished %s -> %s\n", - orig_path, smb_fname->base_name)); - goto done; } + stat_cache_add(orig_path, name, conn->case_sensitive); + DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); + *pst = st; + goto done; + } - /* - * A special case - if we don't have any wildcards or mangling chars and are case - * sensitive or the underlying filesystem is case insentive then searching - * won't help. - */ - - if ((conn->case_sensitive || !(conn->fs_capabilities & - FILE_CASE_SENSITIVE_SEARCH)) && - !mangle_is_mangled(smb_fname->base_name, conn->params)) { - - status = check_for_dot_component(smb_fname); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } + DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", + name, dirpath, start)); - /* - * The stat failed. Could be ok as it could be - * a new file. - */ + /* + * A special case - if we don't have any mangling chars and are case + * sensitive or the underlying filesystem is case insentive then searching + * won't help. + */ - if (errno == ENOTDIR || errno == ELOOP) { - status = NT_STATUS_OBJECT_PATH_NOT_FOUND; - goto fail; - } else if (errno == ENOENT) { - /* - * Was it a missing last component ? - * or a missing intermediate component ? - */ - struct smb_filename parent_fname; - ZERO_STRUCT(parent_fname); - if (!parent_dirname(ctx, smb_fname->base_name, - &parent_fname.base_name, - NULL)) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - if (posix_pathnames) { - ret = SMB_VFS_LSTAT(conn, &parent_fname); - } else { - ret = SMB_VFS_STAT(conn, &parent_fname); - } - if (ret == -1) { - if (errno == ENOTDIR || - errno == ENOENT || - errno == ELOOP) { - status = NT_STATUS_OBJECT_PATH_NOT_FOUND; - goto fail; - } - } - /* - * Missing last component is ok - new file. - * Also deal with permission denied elsewhere. - * Just drop out to done. - */ - goto done; - } - } + if ((conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && + !mangle_is_mangled(name, conn->params)) { + goto done; } /* @@ -444,14 +346,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, *end = 0; } - if (save_last_component) { - TALLOC_FREE(smb_fname->original_lcomp); - smb_fname->original_lcomp = talloc_strdup(smb_fname, + if (pp_saved_last_component) { + TALLOC_FREE(*pp_saved_last_component); + *pp_saved_last_component = talloc_strdup(ctx, end ? end + 1 : start); - if (!smb_fname->original_lcomp) { + if (!*pp_saved_last_component) { DEBUG(0, ("talloc failed\n")); - status = NT_STATUS_NO_MEMORY; - goto err; + return NT_STATUS_NO_MEMORY; } } @@ -460,9 +361,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if (ISDOT(start)) { if (!end) { /* Error code at the end of a pathname. */ - status = NT_STATUS_OBJECT_NAME_INVALID; + result = NT_STATUS_OBJECT_NAME_INVALID; } else { - status = determine_path_error(end+1, + result = determine_path_error(end+1, allow_wcard_last_component); } goto fail; @@ -473,9 +374,15 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, name_has_wildcard = ms_has_wild(start); + /* Wildcard not valid anywhere. */ + if (name_has_wildcard && !allow_wcard_last_component) { + result = NT_STATUS_OBJECT_NAME_INVALID; + goto fail; + } + /* Wildcards never valid within a pathname. */ if (name_has_wildcard && end) { - status = NT_STATUS_OBJECT_NAME_INVALID; + result = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } @@ -484,9 +391,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (posix_pathnames) { - ret = SMB_VFS_LSTAT(conn, smb_fname); + ret = SMB_VFS_LSTAT(conn,name, &st); } else { - ret = SMB_VFS_STAT(conn, smb_fname); + ret = SMB_VFS_STAT(conn,name, &st); } if (ret == 0) { @@ -494,7 +401,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * It exists. it must either be a directory or this must * be the last part of the path for it to be OK. */ - if (end && !S_ISDIR(smb_fname->st.st_ex_mode)) { + if (end && !(st.st_mode & S_IFDIR)) { /* * An intermediate part of the name isn't * a directory. @@ -509,15 +416,25 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * applications depend on the difference between * these two errors. */ - status = NT_STATUS_OBJECT_PATH_NOT_FOUND; + result = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } + if (!end) { + /* + * We just scanned for, and found the end of + * the path. We must return the valid stat + * struct. JRA. + */ + + *pst = st; + } + } else { char *found_name = NULL; /* Stat failed - ensure we don't use it. */ - SET_STAT_INVALID(smb_fname->st); + SET_STAT_INVALID(st); /* * Reset errno so we can detect @@ -563,11 +480,11 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP) { - status = + result = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { - status = + result = map_nt_error_from_unix(errno); } goto fail; @@ -588,10 +505,10 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (errno == ENOTDIR || errno == ELOOP) { - status = + result = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { - status = + result = map_nt_error_from_unix(errno); } goto fail; @@ -623,13 +540,12 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, &unmangled, conn->params)) { char *tmp; - size_t start_ofs = - start - smb_fname->base_name; + size_t start_ofs = start - name; if (*dirpath != '\0') { - tmp = talloc_asprintf( - smb_fname, "%s/%s", - dirpath, unmangled); + tmp = talloc_asprintf(ctx, + "%s/%s", dirpath, + unmangled); TALLOC_FREE(unmangled); } else { @@ -637,13 +553,11 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, } if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); - status = NT_STATUS_NO_MEMORY; - goto err; + return NT_STATUS_NO_MEMORY; } - TALLOC_FREE(smb_fname->base_name); - smb_fname->base_name = tmp; - start = - smb_fname->base_name + start_ofs; + TALLOC_FREE(name); + name = tmp; + start = name + start_ofs; end = start + strlen(start); } @@ -658,50 +572,46 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (end) { char *tmp; - size_t start_ofs = - start - smb_fname->base_name; + size_t start_ofs = start - name; if (*dirpath != '\0') { - tmp = talloc_asprintf(smb_fname, + tmp = talloc_asprintf(ctx, "%s/%s/%s", dirpath, found_name, end+1); } else { - tmp = talloc_asprintf(smb_fname, + tmp = talloc_asprintf(ctx, "%s/%s", found_name, end+1); } if (tmp == NULL) { DEBUG(0, ("talloc_asprintf failed\n")); - status = NT_STATUS_NO_MEMORY; - goto err; + return NT_STATUS_NO_MEMORY; } - TALLOC_FREE(smb_fname->base_name); - smb_fname->base_name = tmp; - start = smb_fname->base_name + start_ofs; + TALLOC_FREE(name); + name = tmp; + start = name + start_ofs; end = start + strlen(found_name); *end = '\0'; } else { char *tmp; - size_t start_ofs = - start - smb_fname->base_name; + size_t start_ofs = start - name; if (*dirpath != '\0') { - tmp = talloc_asprintf(smb_fname, + tmp = talloc_asprintf(ctx, "%s/%s", dirpath, found_name); } else { - tmp = talloc_strdup(smb_fname, + tmp = talloc_strdup(ctx, found_name); } if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); - status = NT_STATUS_NO_MEMORY; - goto err; + return NT_STATUS_NO_MEMORY; } - TALLOC_FREE(smb_fname->base_name); - smb_fname->base_name = tmp; - start = smb_fname->base_name + start_ofs; + TALLOC_FREE(name); + name = tmp; + start = name + start_ofs; /* * We just scanned for, and found the end of @@ -710,13 +620,15 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (posix_pathnames) { - ret = SMB_VFS_LSTAT(conn, smb_fname); + ret = SMB_VFS_LSTAT(conn,name, &st); } else { - ret = SMB_VFS_STAT(conn, smb_fname); + ret = SMB_VFS_STAT(conn,name, &st); } - if (ret != 0) { - SET_STAT_INVALID(smb_fname->st); + if (ret == 0) { + *pst = st; + } else { + SET_STAT_INVALID(st); } } @@ -729,13 +641,12 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * We should never provide different behaviors * depending on DEVELOPER!!! */ - if (VALID_STAT(smb_fname->st)) { + if (VALID_STAT(st)) { bool delete_pending; - get_file_infos(vfs_file_id_from_sbuf(conn, - &smb_fname->st), + get_file_infos(vfs_file_id_from_sbuf(conn, &st), &delete_pending, NULL); if (delete_pending) { - status = NT_STATUS_DELETE_PENDING; + result = NT_STATUS_DELETE_PENDING; goto fail; } } @@ -750,8 +661,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, "%s/%s", dirpath, start); if (!tmp) { DEBUG(0, ("talloc_asprintf failed\n")); - status = NT_STATUS_NO_MEMORY; - goto err; + return NT_STATUS_NO_MEMORY; } TALLOC_FREE(dirpath); dirpath = tmp; @@ -760,15 +670,15 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, TALLOC_FREE(dirpath); if (!(dirpath = talloc_strdup(ctx,start))) { DEBUG(0, ("talloc_strdup failed\n")); - status = NT_STATUS_NO_MEMORY; - goto err; + return NT_STATUS_NO_MEMORY; } } /* - * Cache the dirpath thus far. Don't cache a name with mangled - * or wildcard components as this can change the size. + * Don't cache a name with mangled or wildcard components + * as this can change the size. */ + if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, dirpath, conn->case_sensitive); @@ -783,56 +693,53 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, } /* - * Cache the full path. Don't cache a name with mangled or wildcard - * components as this can change the size. + * Don't cache a name with mangled or wildcard components + * as this can change the size. */ if(!component_was_mangled && !name_has_wildcard) { - stat_cache_add(orig_path, smb_fname->base_name, - conn->case_sensitive); + stat_cache_add(orig_path, name, conn->case_sensitive); } /* * The name has been resolved. */ - DEBUG(5,("conversion finished %s -> %s\n", orig_path, - smb_fname->base_name)); + DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); done: - /* Add back the stream if one was stripped off originally. */ if (stream != NULL) { - smb_fname->stream_name = stream; + char *tmp = NULL; - /* Check path now that the base_name has been converted. */ - status = build_stream_path(ctx, conn, orig_path, smb_fname); - if (!NT_STATUS_IS_OK(status)) { + result = build_stream_path(ctx, conn, orig_path, name, stream, + pst, &tmp); + if (!NT_STATUS_IS_OK(result)) { goto fail; } + + DEBUG(10, ("build_stream_path returned %s\n", tmp)); + + TALLOC_FREE(name); + name = tmp; } + *pp_conv_path = name; TALLOC_FREE(dirpath); - *smb_fname_out = smb_fname; return NT_STATUS_OK; fail: DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start)); if (*dirpath != '\0') { - smb_fname->base_name = talloc_asprintf(smb_fname, "%s/%s", - dirpath, start); + *pp_conv_path = talloc_asprintf(ctx, + "%s/%s", dirpath, start); } else { - smb_fname->base_name = talloc_strdup(smb_fname, start); + *pp_conv_path = talloc_strdup(ctx, start); } - if (!smb_fname->base_name) { + if (!*pp_conv_path) { DEBUG(0, ("talloc_asprintf failed\n")); - status = NT_STATUS_NO_MEMORY; - goto err; + return NT_STATUS_NO_MEMORY; } - - *smb_fname_out = smb_fname; + TALLOC_FREE(name); TALLOC_FREE(dirpath); - return status; - err: - TALLOC_FREE(smb_fname); - return status; + return result; } /**************************************************************************** @@ -893,8 +800,7 @@ static int get_real_filename_full_scan(connection_struct *conn, TALLOC_CTX *mem_ctx, char **found_name) { struct smb_Dir *cur_dir; - const char *dname = NULL; - char *talloced = NULL; + const char *dname; char *unmangled_name = NULL; long curpos; @@ -946,11 +852,10 @@ static int get_real_filename_full_scan(connection_struct *conn, /* now scan for matching names */ curpos = 0; - while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) { + while ((dname = ReadDirName(cur_dir, &curpos, NULL))) { /* Is it dot or dot dot. */ if (ISDOT(dname) || ISDOTDOT(dname)) { - TALLOC_FREE(talloced); continue; } @@ -973,13 +878,10 @@ static int get_real_filename_full_scan(connection_struct *conn, TALLOC_FREE(cur_dir); if (!*found_name) { errno = ENOMEM; - TALLOC_FREE(talloced); return -1; } - TALLOC_FREE(talloced); return 0; } - TALLOC_FREE(talloced); } TALLOC_FREE(unmangled_name); @@ -1026,29 +928,40 @@ int get_real_filename(connection_struct *conn, const char *path, static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *orig_path, - struct smb_filename *smb_fname) + const char *basepath, + const char *streamname, + SMB_STRUCT_STAT *pst, + char **path) { + SMB_STRUCT_STAT st; + char *result = NULL; NTSTATUS status; unsigned int i, num_streams; struct stream_struct *streams = NULL; - if (SMB_VFS_STAT(conn, smb_fname) == 0) { - DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname))); + result = talloc_asprintf(mem_ctx, "%s%s", basepath, streamname); + if (result == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (SMB_VFS_STAT(conn, result, &st) == 0) { + *pst = st; + *path = result; return NT_STATUS_OK; } if (errno != ENOENT) { - DEBUG(10, ("vfs_stat failed: %s\n", strerror(errno))); status = map_nt_error_from_unix(errno); + DEBUG(10, ("vfs_stat failed: %s\n", nt_errstr(status))); goto fail; } - /* Fall back to a case-insensitive scan of all streams on the file. */ - status = SMB_VFS_STREAMINFO(conn, NULL, smb_fname->base_name, mem_ctx, + status = SMB_VFS_STREAMINFO(conn, NULL, basepath, mem_ctx, &num_streams, &streams); if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { - SET_STAT_INVALID(smb_fname->st); + SET_STAT_INVALID(*pst); + *path = result; return NT_STATUS_OK; } @@ -1059,8 +972,8 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, for (i=0; i<num_streams; i++) { DEBUG(10, ("comparing [%s] and [%s]: ", - smb_fname->stream_name, streams[i].name)); - if (fname_equal(smb_fname->stream_name, streams[i].name, + streamname, streams[i].name)); + if (fname_equal(streamname, streams[i].name, conn->case_sensitive)) { DEBUGADD(10, ("equal\n")); break; @@ -1068,118 +981,33 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, DEBUGADD(10, ("not equal\n")); } - /* Couldn't find the stream. */ if (i == num_streams) { - SET_STAT_INVALID(smb_fname->st); + SET_STAT_INVALID(*pst); + *path = result; TALLOC_FREE(streams); return NT_STATUS_OK; } - DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n", - smb_fname->stream_name, streams[i].name)); + TALLOC_FREE(result); - - TALLOC_FREE(smb_fname->stream_name); - smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name); - if (smb_fname->stream_name == NULL) { + result = talloc_asprintf(mem_ctx, "%s%s", basepath, streams[i].name); + if (result == NULL) { status = NT_STATUS_NO_MEMORY; goto fail; } - SET_STAT_INVALID(smb_fname->st); - - if (SMB_VFS_STAT(conn, smb_fname) == 0) { - DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname))); - } - status = NT_STATUS_OK; - fail: - TALLOC_FREE(streams); - return status; -} - -/** - * Go through all the steps to validate a filename. - * - * @param ctx talloc_ctx to allocate memory with. - * @param conn connection struct for vfs calls. - * @param dfs_path Whether this path requires dfs resolution. - * @param name_in The unconverted name. - * @param ucf_flags flags to pass through to unix_convert(). - * UCF_ALWAYS_ALLOW_WCARD_LCOMP will be OR'd in if - * p_cont_wcard != NULL and is true and - * UCF_COND_ALLOW_WCARD_LCOMP. - * @param p_cont_wcard If not NULL, will be set to true if the dfs path - * resolution detects a wildcard. - * @param pp_smb_fname The final converted name will be allocated if the - * return is NT_STATUS_OK. - * - * @return NT_STATUS_OK if all operations completed succesfully, appropriate - * error otherwise. - */ -NTSTATUS filename_convert(TALLOC_CTX *ctx, - connection_struct *conn, - bool dfs_path, - const char *name_in, - uint32_t ucf_flags, - bool *ppath_contains_wcard, - struct smb_filename **pp_smb_fname) -{ - NTSTATUS status; - char *fname = NULL; - - *pp_smb_fname = NULL; - - status = resolve_dfspath_wcard(ctx, conn, - dfs_path, - name_in, - &fname, - ppath_contains_wcard); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10,("filename_convert: resolve_dfspath failed " - "for name %s with %s\n", - name_in, - nt_errstr(status) )); - return status; - } - - if (is_fake_file_path(name_in)) { - SMB_STRUCT_STAT st; - ZERO_STRUCT(st); - st.st_ex_nlink = 1; - status = create_synthetic_smb_fname_split(ctx, - name_in, - &st, - pp_smb_fname); - return status; - } + SET_STAT_INVALID(*pst); - /* - * If the caller conditionally allows wildcard lookups, only add the - * always allow if the path actually does contain a wildcard. - */ - if (ucf_flags & UCF_COND_ALLOW_WCARD_LCOMP && - ppath_contains_wcard != NULL && *ppath_contains_wcard) { - ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP; + if (SMB_VFS_STAT(conn, result, pst) == 0) { + stat_cache_add(orig_path, result, conn->case_sensitive); } - status = unix_convert(ctx, conn, fname, pp_smb_fname, ucf_flags); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10,("filename_convert: unix_convert failed " - "for name %s with %s\n", - fname, - nt_errstr(status) )); - return status; - } - - status = check_name(conn, (*pp_smb_fname)->base_name); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3,("filename_convert: check_name failed " - "for name %s with %s\n", - smb_fname_str_dbg(*pp_smb_fname), - nt_errstr(status) )); - TALLOC_FREE(*pp_smb_fname); - return status; - } + *path = result; + TALLOC_FREE(streams); + return NT_STATUS_OK; + fail: + TALLOC_FREE(result); + TALLOC_FREE(streams); return status; } diff --git a/source3/smbd/filename_util.c b/source3/smbd/filename_util.c deleted file mode 100644 index aad8a08e2b..0000000000 --- a/source3/smbd/filename_util.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Filename utility functions. - Copyright (C) Tim Prouty 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "includes.h" - -/** - * XXX: This is temporary and there should be no callers of this outside of - * this file once smb_filename is plumbed through all path based operations. - * The one legitimate caller currently is smb_fname_str_dbg(), which this - * could be made static for. - */ -NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, - const struct smb_filename *smb_fname, - char **full_name) -{ - if (smb_fname->stream_name) { - /* stream_name must always be NULL if there is no stream. */ - SMB_ASSERT(smb_fname->stream_name[0] != '\0'); - - *full_name = talloc_asprintf(ctx, "%s%s", smb_fname->base_name, - smb_fname->stream_name); - } else { - *full_name = talloc_strdup(ctx, smb_fname->base_name); - } - - if (!*full_name) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -/** - * There are actually legitimate callers of this such as functions that - * enumerate streams using the SMB_VFS_STREAMINFO interface and then want to - * operate on each stream. - */ -NTSTATUS create_synthetic_smb_fname(TALLOC_CTX *ctx, const char *base_name, - const char *stream_name, - const SMB_STRUCT_STAT *psbuf, - struct smb_filename **smb_fname_out) -{ - struct smb_filename smb_fname_loc; - - ZERO_STRUCT(smb_fname_loc); - - /* Setup the base_name/stream_name. */ - smb_fname_loc.base_name = CONST_DISCARD(char *, base_name); - smb_fname_loc.stream_name = CONST_DISCARD(char *, stream_name); - - /* Copy the psbuf if one was given. */ - if (psbuf) - smb_fname_loc.st = *psbuf; - - /* Let copy_smb_filename() do the heavy lifting. */ - return copy_smb_filename(ctx, &smb_fname_loc, smb_fname_out); -} - -/** - * XXX: This is temporary and there should be no callers of this once - * smb_filename is plumbed through all path based operations. - */ -NTSTATUS create_synthetic_smb_fname_split(TALLOC_CTX *ctx, - const char *fname, - const SMB_STRUCT_STAT *psbuf, - struct smb_filename **smb_fname_out) -{ - NTSTATUS status; - const char *stream_name = NULL; - char *base_name = NULL; - - if (!lp_posix_pathnames()) { - stream_name = strchr_m(fname, ':'); - } - - /* Setup the base_name/stream_name. */ - if (stream_name) { - base_name = talloc_strndup(ctx, fname, - PTR_DIFF(stream_name, fname)); - } else { - base_name = talloc_strdup(ctx, fname); - } - - if (!base_name) { - return NT_STATUS_NO_MEMORY; - } - - status = create_synthetic_smb_fname(ctx, base_name, stream_name, psbuf, - smb_fname_out); - TALLOC_FREE(base_name); - return status; -} - -/** - * Return a string using the talloc_tos() - */ -const char *smb_fname_str_dbg(const struct smb_filename *smb_fname) -{ - char *fname = NULL; - NTSTATUS status; - - if (smb_fname == NULL) { - return ""; - } - status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - return ""; - } - return fname; -} - -/** - * Return a debug string using the talloc_tos(). This can only be called from - * DEBUG() macros due to the debut_ctx(). - */ -const char *fsp_str_dbg(const struct files_struct *fsp) -{ - return smb_fname_str_dbg(fsp->fsp_name); -} - -NTSTATUS copy_smb_filename(TALLOC_CTX *ctx, - const struct smb_filename *smb_fname_in, - struct smb_filename **smb_fname_out) -{ - /* stream_name must always be NULL if there is no stream. */ - if (smb_fname_in->stream_name) { - SMB_ASSERT(smb_fname_in->stream_name[0] != '\0'); - } - - *smb_fname_out = talloc_zero(ctx, struct smb_filename); - if (*smb_fname_out == NULL) { - return NT_STATUS_NO_MEMORY; - } - - if (smb_fname_in->base_name) { - (*smb_fname_out)->base_name = - talloc_strdup(*smb_fname_out, smb_fname_in->base_name); - if (!(*smb_fname_out)->base_name) - goto no_mem_err; - } - - if (smb_fname_in->stream_name) { - (*smb_fname_out)->stream_name = - talloc_strdup(*smb_fname_out, smb_fname_in->stream_name); - if (!(*smb_fname_out)->stream_name) - goto no_mem_err; - } - - if (smb_fname_in->original_lcomp) { - (*smb_fname_out)->original_lcomp = - talloc_strdup(*smb_fname_out, smb_fname_in->original_lcomp); - if (!(*smb_fname_out)->original_lcomp) - goto no_mem_err; - } - - (*smb_fname_out)->st = smb_fname_in->st; - return NT_STATUS_OK; - - no_mem_err: - TALLOC_FREE(*smb_fname_out); - return NT_STATUS_NO_MEMORY; -} - -/**************************************************************************** - Simple check to determine if the filename is a stream. - ***************************************************************************/ -bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) -{ - /* stream_name must always be NULL if there is no stream. */ - if (smb_fname->stream_name) { - SMB_ASSERT(smb_fname->stream_name[0] != '\0'); - } - - if (lp_posix_pathnames()) { - return false; - } - - return smb_fname->stream_name != NULL; -} - -/**************************************************************************** - Returns true if the filename's stream == "::$DATA" - ***************************************************************************/ -bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname) -{ - if (!is_ntfs_stream_smb_fname(smb_fname)) { - return false; - } - - return StrCaseCmp(smb_fname->stream_name, "::$DATA") == 0; -} diff --git a/source3/smbd/files.c b/source3/smbd/files.c index 455666f8df..03d2f58271 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -44,7 +44,6 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, { int i; files_struct *fsp; - NTSTATUS status; /* we want to give out file handles differently on each new connection because of a common bug in MS clients where they try to @@ -66,26 +65,21 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, return NT_STATUS_TOO_MANY_OPENED_FILES; } - /* - * Make a child of the connection_struct as an fsp can't exist - * indepenedent of a connection. - */ - fsp = talloc_zero(conn, struct files_struct); + fsp = SMB_MALLOC_P(files_struct); if (!fsp) { return NT_STATUS_NO_MEMORY; } - /* - * This can't be a child of fsp because the file_handle can be ref'd - * when doing a dos/fcb open, which will then share the file_handle - * across multiple fsps. - */ - fsp->fh = talloc_zero(conn, struct fd_handle); + ZERO_STRUCTP(fsp); + + fsp->fh = SMB_MALLOC_P(struct fd_handle); if (!fsp->fh) { - TALLOC_FREE(fsp); + SAFE_FREE(fsp); return NT_STATUS_NO_MEMORY; } + ZERO_STRUCTP(fsp->fh); + fsp->fh->ref_count = 1; fsp->fh->fd = -1; @@ -101,18 +95,8 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, fsp->fnum = i + FILE_HANDLE_OFFSET; SMB_ASSERT(fsp->fnum < 65536); - /* - * Create an smb_filename with "" for the base_name. There are very - * few NULL checks, so make sure it's initialized with something. to - * be safe until an audit can be done. - */ - status = create_synthetic_smb_fname(fsp, "", NULL, NULL, - &fsp->fsp_name); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(fsp); - TALLOC_FREE(fsp->fh); - } - + string_set(&fsp->fsp_name,""); + DLIST_ADD(Files, fsp); DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n", @@ -250,9 +234,8 @@ void file_dump_open_table(void) files_struct *fsp; for (fsp=Files;fsp;fsp=fsp->next,count++) { - DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, gen = %lu, " - "fileid=%s\n", count, fsp->fnum, fsp_str_dbg(fsp), - fsp->fh->fd, (unsigned long)fsp->fh->gen_id, + DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, gen = %lu, fileid=%s\n", + count, fsp->fnum, fsp->fsp_name, fsp->fh->fd, (unsigned long)fsp->fh->gen_id, file_id_string_tos(&fsp->file_id))); } } @@ -298,10 +281,8 @@ files_struct *file_find_dif(struct file_id id, unsigned long gen_id) if ((fsp->fh->fd == -1) && (fsp->oplock_type != NO_OPLOCK) && (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) { - DEBUG(0,("file_find_dif: file %s file_id = " - "%s, gen = %u oplock_type = %u is a " - "stat open with oplock type !\n", - fsp_str_dbg(fsp), + DEBUG(0,("file_find_dif: file %s file_id = %s, gen = %u \ +oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id), (unsigned int)fsp->fh->gen_id, (unsigned int)fsp->oplock_type )); @@ -402,12 +383,10 @@ bool file_find_subpath(files_struct *dir_fsp) { files_struct *fsp; size_t dlen; - char *d_fullname = NULL; - - d_fullname = talloc_asprintf(talloc_tos(), "%s/%s", - dir_fsp->conn->connectpath, - dir_fsp->fsp_name->base_name); - + char *d_fullname = talloc_asprintf(talloc_tos(), + "%s/%s", + dir_fsp->conn->connectpath, + dir_fsp->fsp_name); if (!d_fullname) { return false; } @@ -424,9 +403,9 @@ bool file_find_subpath(files_struct *dir_fsp) d1_fullname = talloc_asprintf(talloc_tos(), "%s/%s", fsp->conn->connectpath, - fsp->fsp_name->base_name); + fsp->fsp_name); - /* + /* * If the open file has a path that is a longer * component, then it's a subpath. */ @@ -467,19 +446,17 @@ void file_free(struct smb_request *req, files_struct *fsp) { DLIST_REMOVE(Files, fsp); + string_free(&fsp->fsp_name); + TALLOC_FREE(fsp->fake_file_handle); if (fsp->fh->ref_count == 1) { - TALLOC_FREE(fsp->fh); + SAFE_FREE(fsp->fh); } else { fsp->fh->ref_count--; } if (fsp->notify) { - if (fsp->is_directory) { - notify_remove_onelevel(fsp->conn->notify_ctx, - &fsp->file_id, fsp); - } notify_remove(fsp->conn->notify_ctx, fsp); TALLOC_FREE(fsp->notify); } @@ -516,8 +493,7 @@ void file_free(struct smb_request *req, files_struct *fsp) information */ ZERO_STRUCTP(fsp); - /* fsp->fsp_name is a talloc child and is free'd automatically. */ - TALLOC_FREE(fsp); + SAFE_FREE(fsp); } /**************************************************************************** @@ -563,11 +539,11 @@ files_struct *file_fsp(struct smb_request *req, uint16 fid) Duplicate the file handle part for a DOS or FCB open. ****************************************************************************/ -NTSTATUS dup_file_fsp(struct smb_request *req, files_struct *from, +void dup_file_fsp(struct smb_request *req, files_struct *from, uint32 access_mask, uint32 share_access, uint32 create_options, files_struct *to) { - TALLOC_FREE(to->fh); + SAFE_FREE(to->fh); to->fh = from->fh; to->fh->ref_count++; @@ -592,25 +568,5 @@ NTSTATUS dup_file_fsp(struct smb_request *req, files_struct *from, to->modified = from->modified; to->is_directory = from->is_directory; to->aio_write_behind = from->aio_write_behind; - return fsp_set_smb_fname(to, from->fsp_name); -} - -/** - * The only way that the fsp->fsp_name field should ever be set. - */ -NTSTATUS fsp_set_smb_fname(struct files_struct *fsp, - const struct smb_filename *smb_fname_in) -{ - NTSTATUS status; - struct smb_filename *smb_fname_new; - - status = copy_smb_filename(fsp, smb_fname_in, &smb_fname_new); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - TALLOC_FREE(fsp->fsp_name); - fsp->fsp_name = smb_fname_new; - - return NT_STATUS_OK; + string_set(&to->fsp_name,from->fsp_name); } diff --git a/source3/smbd/globals.c b/source3/smbd/globals.c index 68fa795ba2..9e7d103562 100644 --- a/source3/smbd/globals.c +++ b/source3/smbd/globals.c @@ -43,9 +43,18 @@ bool blocking_lock_cancel_state = false; struct smbd_dmapi_context *dmapi_ctx = NULL; #endif +connection_struct *Connections = NULL; +/* number of open connections */ +struct bitmap *bmap = 0; +int num_open = 0; + bool dfree_broken = false; +struct bitmap *dptr_bmap = NULL; +struct dptr_struct *dirptrs = NULL; +int dirhandles_open = 0; + /* how many write cache buffers have been allocated */ unsigned int allocated_write_caches = 0; @@ -84,9 +93,41 @@ char *last_to = NULL; struct msg_state *smbd_msg_state = NULL; +bool global_encrypted_passwords_negotiated = false; +bool global_spnego_negotiated = false; +struct auth_context *negprot_global_auth_context = NULL; +bool done_negprot = false; + bool logged_ioctl_message = false; +/* users from session setup */ +char *session_userlist = NULL; +/* workgroup from session setup. */ +char *session_workgroup = NULL; +/* this holds info on user ids that are already validated for this VC */ +user_struct *validated_users = NULL; +uint16_t next_vuid = VUID_OFFSET; +int num_validated_vuids = 0; +#ifdef HAVE_NETGROUP +char *my_yp_domain = NULL; +#endif + +bool already_got_session = false; + +/* + * Size of data we can send to client. Set + * by the client for all protocols above CORE. + * Set by us for CORE protocol. + */ +int max_send = BUFFER_SIZE; +/* + * Size of the data we can receive. Set by us. + * Can be modified by the max xmit parameter. + */ +int max_recv = BUFFER_SIZE; +uint16 last_session_tag = UID_FIELD_INVALID; int trans_num = 0; +char *orig_inbuf = NULL; pid_t mypid = 0; time_t last_smb_conf_reload_time = 0; time_t last_printer_reload_time = 0; @@ -95,7 +136,7 @@ time_t last_printer_reload_time = 0; for processing. ****************************************************************************/ struct pending_message_list *deferred_open_queue = NULL; -uint32_t common_flags2 = FLAGS2_LONG_PATH_COMPONENTS|FLAGS2_32_BIT_ERROR_CODES|FLAGS2_EXTENDED_ATTRIBUTES; +uint32_t common_flags2 = FLAGS2_LONG_PATH_COMPONENTS|FLAGS2_32_BIT_ERROR_CODES; struct smb_srv_trans_enc_ctx *partial_srv_trans_enc_ctx = NULL; struct smb_srv_trans_enc_ctx *srv_trans_enc_ctx = NULL; @@ -113,6 +154,11 @@ uint16_t last_flags = 0; struct db_context *session_db_ctx_ptr = NULL; uint32_t global_client_caps = 0; +bool done_sesssetup = false; +/**************************************************************************** + List to store partial SPNEGO auth fragments. +****************************************************************************/ +struct pending_auth_data *pd_list = NULL; uint16_t fnf_handle = 257; @@ -130,6 +176,8 @@ int32_t level_II_oplocks_open = 0; bool global_client_failed_oplock_break = false; struct kernel_oplocks *koplocks = NULL; +struct notify_mid_map *notify_changes_by_mid = NULL; + int am_parent = 1; int server_fd = -1; struct event_context *smbd_event_ctx = NULL; @@ -149,9 +197,4 @@ void smbd_init_globals(void) ZERO_STRUCT(conn_ctx_stack); ZERO_STRUCT(sec_ctx_stack); - - smbd_server_conn = talloc_zero(smbd_event_context(), struct smbd_server_connection); - if (!smbd_server_conn) { - exit_server("failed to create smbd_server_connection"); - } } diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 0db61f87a3..6ac92ed3dd 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -42,8 +42,18 @@ struct smbd_dmapi_context; extern struct smbd_dmapi_context *dmapi_ctx; #endif +extern connection_struct *Connections; +/* number of open connections */ +extern struct bitmap *bmap; +extern int num_open; + extern bool dfree_broken; +extern struct bitmap *dptr_bmap; +//struct dptr_struct; +extern struct dptr_struct *dirptrs; +extern int dirhandles_open; + /* how many write cache buffers have been allocated */ extern unsigned int allocated_write_caches; @@ -81,9 +91,41 @@ extern char *last_to; struct msg_state; extern struct msg_state *smbd_msg_state; +extern bool global_encrypted_passwords_negotiated; +extern bool global_spnego_negotiated; +extern struct auth_context *negprot_global_auth_context; +extern bool done_negprot; + extern bool logged_ioctl_message; +/* users from session setup */ +extern char *session_userlist; +/* workgroup from session setup. */ +extern char *session_workgroup; +/* this holds info on user ids that are already validated for this VC */ +extern user_struct *validated_users; +extern uint16_t next_vuid; +extern int num_validated_vuids; +#ifdef HAVE_NETGROUP +extern char *my_yp_domain; +#endif + +extern bool already_got_session; + +/* + * Size of data we can send to client. Set + * by the client for all protocols above CORE. + * Set by us for CORE protocol. + */ +extern int max_send; +/* + * Size of the data we can receive. Set by us. + * Can be modified by the max xmit parameter. + */ +extern int max_recv; +extern uint16 last_session_tag; extern int trans_num; +extern char *orig_inbuf; extern pid_t mypid; extern time_t last_smb_conf_reload_time; @@ -117,6 +159,12 @@ extern uint16_t last_flags; extern struct db_context *session_db_ctx_ptr; extern uint32_t global_client_caps; +extern bool done_sesssetup; +/**************************************************************************** + List to store partial SPNEGO auth fragments. +****************************************************************************/ +struct pending_auth_data; +extern struct pending_auth_data *pd_list; extern uint16_t fnf_handle; @@ -139,6 +187,8 @@ extern int32_t level_II_oplocks_open; extern bool global_client_failed_oplock_break; extern struct kernel_oplocks *koplocks; +extern struct notify_mid_map *notify_changes_by_mid; + extern int am_parent; extern int server_fd; extern struct event_context *smbd_event_ctx; @@ -149,368 +199,10 @@ struct child_pid; extern struct child_pid *children; extern int num_children; -struct tstream_context; -struct smbd_smb2_request; -struct smbd_smb2_session; -struct smbd_smb2_tcon; - -DATA_BLOB negprot_spnego(void); - -NTSTATUS smb2_signing_sign_pdu(DATA_BLOB session_key, - struct iovec *vector, - int count); -NTSTATUS smb2_signing_check_pdu(DATA_BLOB session_key, - const struct iovec *vector, - int count); - -struct smbd_lock_element { - uint32_t smbpid; - enum brl_type brltype; - uint64_t offset; - uint64_t count; -}; - -NTSTATUS smbd_do_locking(struct smb_request *req, - files_struct *fsp, - uint8_t type, - int32_t timeout, - uint16_t num_ulocks, - struct smbd_lock_element *ulocks, - uint16_t num_locks, - struct smbd_lock_element *locks, - bool *async); - -NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, - TALLOC_CTX *mem_ctx, - uint16_t info_level, - files_struct *fsp, - struct smb_filename *smb_fname, - bool delete_pending, - struct timespec write_time_ts, - bool ms_dfs_link, - struct ea_list *ea_list, - int lock_data_count, - char *lock_data, - uint16_t flags2, - unsigned int max_data_bytes, - char **ppdata, - unsigned int *pdata_size); - -NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, - struct smb_request *req, - TALLOC_CTX *mem_ctx, - uint16_t info_level, - files_struct *fsp, - struct smb_filename *smb_fname, - char **ppdata, int total_data, - int *ret_data_size); - -NTSTATUS smbd_do_qfsinfo(connection_struct *conn, - TALLOC_CTX *mem_ctx, - uint16_t info_level, - uint16_t flags2, - unsigned int max_data_bytes, - char **ppdata, - int *ret_data_len); - -bool smbd_dirptr_get_entry(TALLOC_CTX *ctx, - struct dptr_struct *dirptr, - const char *mask, - uint32_t dirtype, - bool dont_descend, - bool ask_sharemode, - bool (*match_fn)(TALLOC_CTX *ctx, - void *private_data, - const char *dname, - const char *mask, - char **_fname), - bool (*mode_fn)(TALLOC_CTX *ctx, - void *private_data, - struct smb_filename *smb_fname, - uint32_t *_mode), - void *private_data, - char **_fname, - struct smb_filename **_smb_fname, - uint32_t *_mode, - long *_prev_offset); - -bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx, - connection_struct *conn, - struct dptr_struct *dirptr, - uint16 flags2, - const char *path_mask, - uint32 dirtype, - int info_level, - int requires_resume_key, - bool dont_descend, - bool ask_sharemode, - uint8_t align, - bool do_pad, - char **ppdata, - char *base_data, - char *end_data, - int space_remaining, - bool *out_of_space, - bool *got_exact_match, - int *_last_entry_off, - struct ea_list *name_list); - -NTSTATUS smbd_check_open_rights(struct connection_struct *conn, - const struct smb_filename *smb_fname, - uint32_t access_mask, - uint32_t *access_granted); - -void smbd_notify_cancel_by_smbreq(struct smbd_server_connection *sconn, - const struct smb_request *smbreq); - -void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn, - const char *reason, - const char *location); -#define smbd_server_connection_terminate(sconn, reason) \ - smbd_server_connection_terminate_ex(sconn, reason, __location__) - -bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size); - -void reply_smb2002(struct smb_request *req, uint16_t choice); -void smbd_smb2_first_negprot(struct smbd_server_connection *sconn, - const uint8_t *inbuf, size_t size); - -NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req, - NTSTATUS status, - DATA_BLOB *info, - const char *location); -#define smbd_smb2_request_error(req, status) \ - smbd_smb2_request_error_ex(req, status, NULL, __location__) -NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req, - NTSTATUS status, - DATA_BLOB body, DATA_BLOB *dyn, - const char *location); -#define smbd_smb2_request_done(req, body, dyn) \ - smbd_smb2_request_done_ex(req, NT_STATUS_OK, body, dyn, __location__) - -NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn, - uint64_t file_id_persistent, - uint64_t file_id_volatile, - uint8_t oplock_level); - -NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req, - struct tevent_req *subreq); - -NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req); - -struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req); - -NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_tcon(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_close(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_write(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_keepalive(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_find(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_notify(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_getinfo(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_setinfo(struct smbd_smb2_request *req); -NTSTATUS smbd_smb2_request_process_break(struct smbd_smb2_request *req); - -struct smbd_smb2_request { - struct smbd_smb2_request *prev, *next; - - TALLOC_CTX *mem_pool; - struct smbd_smb2_request **parent; - - struct smbd_server_connection *sconn; - - /* the session the request operates on, maybe NULL */ - struct smbd_smb2_session *session; - - /* the tcon the request operates on, maybe NULL */ - struct smbd_smb2_tcon *tcon; - - int current_idx; - bool do_signing; - - struct files_struct *compat_chain_fsp; - - NTSTATUS next_status; - - /* - * The sub request for async backend calls. - * This is used for SMB2 Cancel. - */ - struct tevent_req *subreq; - - struct { - /* the NBT header is not allocated */ - uint8_t nbt_hdr[4]; - /* - * vector[0] NBT - * . - * vector[1] SMB2 - * vector[2] fixed body - * vector[3] dynamic body - * . - * . - * . - * vector[4] SMB2 - * vector[5] fixed body - * vector[6] dynamic body - * . - * . - * . - */ - struct iovec *vector; - int vector_count; - } in; - struct { - /* the NBT header is not allocated */ - uint8_t nbt_hdr[4]; - /* - * vector[0] NBT - * . - * vector[1] SMB2 - * vector[2] fixed body - * vector[3] dynamic body - * . - * . - * . - * vector[4] SMB2 - * vector[5] fixed body - * vector[6] dynamic body - * . - * . - * . - */ - struct iovec *vector; - int vector_count; - } out; -}; - -struct smbd_server_connection; - -struct smbd_smb2_session { - struct smbd_smb2_session *prev, *next; - struct smbd_server_connection *sconn; - NTSTATUS status; - uint64_t vuid; - AUTH_NTLMSSP_STATE *auth_ntlmssp_state; - struct auth_serversupplied_info *server_info; - DATA_BLOB session_key; - bool do_signing; - - user_struct *compat_vuser; - - struct { - /* an id tree used to allocate tids */ - struct idr_context *idtree; - - /* this is the limit of tid values for this connection */ - uint32_t limit; - - struct smbd_smb2_tcon *list; - } tcons; -}; - -struct smbd_smb2_tcon { - struct smbd_smb2_tcon *prev, *next; - struct smbd_smb2_session *session; - uint32_t tid; - int snum; - connection_struct *compat_conn; -}; - -struct pending_auth_data; - struct smbd_server_connection { - struct { - bool got_session; - } nbt; - bool allow_smb2; - struct { - struct fd_event *fde; - uint64_t num_requests; - struct { - bool encrypted_passwords; - bool spnego; - struct auth_context *auth_context; - bool done; - /* - * Size of the data we can receive. Set by us. - * Can be modified by the max xmit parameter. - */ - int max_recv; - } negprot; - - struct { - bool done_sesssetup; - /* - * Size of data we can send to client. Set - * by the client for all protocols above CORE. - * Set by us for CORE protocol. - */ - int max_send; - uint16_t last_session_tag; - - /* users from session setup */ - char *session_userlist; - /* workgroup from session setup. */ - char *session_workgroup; - /* - * this holds info on user ids that are already - * validated for this VC - */ - user_struct *validated_users; - uint16_t next_vuid; - int num_validated_vuids; -#ifdef HAVE_NETGROUP - char *my_yp_domain; -#endif - } sessions; - struct { - connection_struct *Connections; - /* number of open connections */ - struct bitmap *bmap; - int num_open; - } tcons; - struct smb_signing_state *signing_state; - /* List to store partial SPNEGO auth fragments. */ - struct pending_auth_data *pd_list; - - struct notify_mid_map *notify_mid_maps; - - struct { - struct bitmap *dptr_bmap; - struct dptr_struct *dirptrs; - int dirhandles_open; - } searches; - } smb1; - struct { - struct tevent_context *event_ctx; - struct tevent_queue *recv_queue; - struct tevent_queue *send_queue; - struct tstream_context *stream; - struct { - /* an id tree used to allocate vuids */ - /* this holds info on session vuids that are already - * validated for this VC */ - struct idr_context *idtree; - - /* this is the limit of vuid values for this connection */ - uint64_t limit; - - struct smbd_smb2_session *list; - } sessions; - struct smbd_smb2_request *requests; - } smb2; + struct fd_event *fde; + uint64_t num_requests; }; - extern struct smbd_server_connection *smbd_server_conn; void smbd_init_globals(void); diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index 97b338a536..2cf0038985 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -93,8 +93,6 @@ void send_trans_reply(connection_struct *conn, int ldata = rdata ? rdata_len : 0; int lparam = rparam ? rparam_len : 0; - struct smbd_server_connection *sconn = smbd_server_conn; - int max_send = sconn->smb1.sessions.max_send; if (buffer_too_large) DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata )); @@ -136,7 +134,6 @@ void send_trans_reply(connection_struct *conn, show_msg((char *)req->outbuf); if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(conn), &req->pcd)) { exit_server_cleanly("send_trans_reply: srv_send_smb failed."); } @@ -196,7 +193,6 @@ void send_trans_reply(connection_struct *conn, show_msg((char *)req->outbuf); if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(conn), &req->pcd)) exit_server_cleanly("send_trans_reply: srv_send_smb " "failed."); @@ -303,7 +299,6 @@ static void api_dcerpc_cmd_write_done(struct tevent_req *subreq) send: if (!srv_send_smb( smbd_server_fd(), (char *)req->outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(req->conn) || req->encrypted, &req->pcd)) { exit_server_cleanly("construct_reply: srv_send_smb failed."); @@ -330,7 +325,6 @@ static void api_dcerpc_cmd_read_done(struct tevent_req *subreq) reply_nterror(req, status); if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(req->conn) ||req->encrypted, &req->pcd)) { exit_server_cleanly("construct_reply: srv_send_smb " @@ -457,7 +451,7 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid, } DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n", - subcommand, fsp_str_dbg(fsp), pnum)); + subcommand, fsp->fsp_name, pnum)); DEBUG(10, ("api_fd_reply: p:%p max_trans_reply: %d\n", fsp, mdrcnt)); diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index 7b01968a1f..40b6acae9f 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -26,9 +26,6 @@ */ #include "includes.h" -#include "smbd/globals.h" -#include "../librpc/gen_ndr/cli_samr.h" -#include "../librpc/gen_ndr/srv_samr.h" #include "../lib/util/binsearch.h" #ifdef CHECK_TYPES @@ -649,16 +646,18 @@ static void fill_printq_info_52(connection_struct *conn, int snum, { int i; fstring location; - struct spoolss_DriverInfo8 *driver = NULL; + NT_PRINTER_DRIVER_INFO_LEVEL driver; NT_PRINTER_INFO_LEVEL *printer = NULL; + ZERO_STRUCT(driver); + if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) { DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n", lp_servicename(snum))); goto err; } - if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername, + if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, "Windows 4.0", 0)) ) { DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n", @@ -666,38 +665,38 @@ static void fill_printq_info_52(connection_struct *conn, int snum, goto err; } - trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0); - trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0); - trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0); + trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0); + trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0); + trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0); PACKI(desc, "W", 0x0400); /* don't know */ - PACKS(desc, "z", driver->driver_name); /* long printer name */ - PACKS(desc, "z", driver->driver_path); /* Driverfile Name */ - PACKS(desc, "z", driver->data_file); /* Datafile name */ - PACKS(desc, "z", driver->monitor_name); /* language monitor */ + PACKS(desc, "z", driver.info_3->name); /* long printer name */ + PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */ + PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */ + PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */ fstrcpy(location, "\\\\%L\\print$\\WIN40\\0"); standard_sub_basic( "", "", location, sizeof(location)-1 ); PACKS(desc,"z", location); /* share to retrieve files */ - PACKS(desc,"z", driver->default_datatype); /* default data type */ - PACKS(desc,"z", driver->help_file); /* helpfile name */ - PACKS(desc,"z", driver->driver_path); /* driver name */ + PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */ + PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */ + PACKS(desc,"z", driver.info_3->driverpath); /* driver name */ - DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name)); - DEBUG(3,("Driver: %s:\n",driver->driver_path)); - DEBUG(3,("Data File: %s:\n",driver->data_file)); - DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name)); + DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name)); + DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath)); + DEBUG(3,("Data File: %s:\n",driver.info_3->datafile)); + DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname)); DEBUG(3,("Driver Location: %s:\n",location)); - DEBUG(3,("Data Type: %s:\n",driver->default_datatype)); - DEBUG(3,("Help File: %s:\n",driver->help_file)); + DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype)); + DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile)); PACKI(desc,"N",count); /* number of files to copy */ - for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++) + for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++) { - trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0); - PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */ - DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i])); + trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0); + PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */ + DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i])); } /* sanity check */ @@ -718,7 +717,8 @@ done: if ( printer ) free_a_printer( &printer, 2 ); - free_a_printer_driver(driver); + if ( driver.info_3 ) + free_a_printer_driver( driver, 3 ); } @@ -807,7 +807,7 @@ static void fill_printq_info(connection_struct *conn, int snum, int uLevel, static int get_printerdrivernumber(int snum) { int result = 0; - struct spoolss_DriverInfo8 *driver; + NT_PRINTER_DRIVER_INFO_LEVEL driver; NT_PRINTER_INFO_LEVEL *printer = NULL; ZERO_STRUCT(driver); @@ -818,7 +818,7 @@ static int get_printerdrivernumber(int snum) goto done; } - if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername, + if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, "Windows 4.0", 0)) ) { DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n", @@ -827,13 +827,15 @@ static int get_printerdrivernumber(int snum) } /* count the number of files */ - while (driver->dependent_files && *driver->dependent_files[result]) - result++; + while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] ) + result++; + \ done: if ( printer ) free_a_printer( &printer, 2 ); - free_a_printer_driver(driver); + if ( driver.info_3 ) + free_a_printer_driver( driver, 3 ); return result; } @@ -1780,9 +1782,7 @@ static bool check_share_info(int uLevel, char* id) } break; case 1: - /* Level-2 descriptor is allowed (and ignored) */ - if (strcmp(id,"B13BWz") != 0 && - strcmp(id,"B13BWzWWWzB9B") != 0) { + if (strcmp(id,"B13BWz") != 0) { return False; } break; @@ -2885,7 +2885,6 @@ static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - struct smbd_server_connection *sconn = smbd_server_conn; fstring user; char *p = get_safe_str_ptr(param,tpscnt,param,2); *rparam_len = 2; @@ -2943,7 +2942,7 @@ static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, * function. */ - (void)map_username(sconn, user); + (void)map_username(user); if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) { SSVAL(*rparam,0,NERR_Success); @@ -3665,7 +3664,6 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid, char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - struct smbd_server_connection *sconn = smbd_server_conn; char *str1 = get_safe_str_ptr(param,tpscnt,param,2); char *str2 = skip_string(param,tpscnt,str1); char *UserName = skip_string(param,tpscnt,str2); @@ -3678,7 +3676,7 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid, /* get NIS home of a previously validated user - simeon */ /* With share level security vuid will always be zero. Don't depend on vuser being non-null !!. JRA */ - user_struct *vuser = get_valid_user_struct(sconn, vuid); + user_struct *vuser = get_valid_user_struct(vuid); if(vuser != NULL) { DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->server_info->utok.uid, @@ -3921,7 +3919,6 @@ static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - struct smbd_server_connection *sconn = smbd_server_conn; char *str1 = get_safe_str_ptr(param,tpscnt,param,2); char *str2 = skip_string(param,tpscnt,str1); char *p = skip_string(param,tpscnt,str2); @@ -3930,7 +3927,7 @@ static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char* name; /* With share level security vuid will always be zero. Don't depend on vuser being non-null !!. JRA */ - user_struct *vuser = get_valid_user_struct(sconn, vuid); + user_struct *vuser = get_valid_user_struct(vuid); if (!str1 || !str2 || !p) { return False; @@ -4870,7 +4867,6 @@ void api_reply(connection_struct *conn, uint16 vuid, int tdscnt, int tpscnt, int mdrcnt, int mprcnt) { - struct smbd_server_connection *sconn = smbd_server_conn; int api_command; char *rdata = NULL; char *rparam = NULL; @@ -4919,7 +4915,7 @@ void api_reply(connection_struct *conn, uint16 vuid, /* Check whether this api call can be done anonymously */ if (api_commands[i].auth_user && lp_restrict_anonymous()) { - user_struct *user = get_valid_user_struct(sconn, vuid); + user_struct *user = get_valid_user_struct(vuid); if (!user || user->server_info->guest) { reply_nterror(req, NT_STATUS_ACCESS_DENIED); diff --git a/source3/smbd/mangle_hash.c b/source3/smbd/mangle_hash.c index d1af0994a8..11ccbee3e6 100644 --- a/source3/smbd/mangle_hash.c +++ b/source3/smbd/mangle_hash.c @@ -290,15 +290,15 @@ static bool is_8_3(const char *fname, bool check_case, bool allow_wildcards, if (strlen(f) > 12) return False; - if (!push_ucs2_talloc(NULL, &ucs2name, f, &size)) { - DEBUG(0,("is_8_3: internal error push_ucs2_talloc() failed!\n")); + if (!push_ucs2_allocate(&ucs2name, f, &size)) { + DEBUG(0,("is_8_3: internal error push_ucs2_allocate() failed!\n")); goto done; } ret = is_8_3_w(ucs2name, allow_wildcards); done: - TALLOC_FREE(ucs2name); + SAFE_FREE(ucs2name); if (!NT_STATUS_IS_OK(ret)) { return False; @@ -618,12 +618,12 @@ static bool must_mangle(const char *name, magic_char = lp_magicchar(p); - if (!push_ucs2_talloc(NULL, &name_ucs2, name, &converted_size)) { - DEBUG(0, ("push_ucs2_talloc failed!\n")); + if (!push_ucs2_allocate(&name_ucs2, name, &converted_size)) { + DEBUG(0, ("push_ucs2_allocate failed!\n")); return False; } status = is_valid_name(name_ucs2, False, False); - TALLOC_FREE(name_ucs2); + SAFE_FREE(name_ucs2); /* We return true if we *must* mangle, so if it's * a valid name (status == OK) then we must return * false. Bug #6939. */ @@ -660,20 +660,20 @@ static bool hash_name_to_8_3(const char *in, DEBUG(5,("hash_name_to_8_3( %s, cache83 = %s)\n", in, cache83 ? "True" : "False")); - if (!push_ucs2_talloc(NULL, &in_ucs2, in, &converted_size)) { - DEBUG(0, ("push_ucs2_talloc failed!\n")); + if (!push_ucs2_allocate(&in_ucs2, in, &converted_size)) { + DEBUG(0, ("push_ucs2_allocate failed!\n")); return False; } /* If it's already 8.3, just copy. */ if (NT_STATUS_IS_OK(is_valid_name(in_ucs2, False, False)) && NT_STATUS_IS_OK(is_8_3_w(in_ucs2, False))) { - TALLOC_FREE(in_ucs2); + SAFE_FREE(in_ucs2); safe_strcpy(out, in, 12); return True; } - TALLOC_FREE(in_ucs2); + SAFE_FREE(in_ucs2); if (!to_8_3(magic_char, in, out, default_case)) { return False; } diff --git a/source3/smbd/map_username.c b/source3/smbd/map_username.c index 24b4ddd271..fde2a3c4d3 100644 --- a/source3/smbd/map_username.c +++ b/source3/smbd/map_username.c @@ -68,7 +68,7 @@ static bool set_last_from_to(const char *from, const char *to) return true; } -bool map_username(struct smbd_server_connection *sconn, fstring user) +bool map_username(fstring user) { XFILE *f; char *mapfile = lp_username_map(); @@ -184,7 +184,7 @@ bool map_username(struct smbd_server_connection *sconn, fstring user) } if (strchr_m(dosname,'*') || - user_in_list(sconn, user, (const char **)dosuserlist)) { + user_in_list(user, (const char **)dosuserlist)) { DEBUG(3,("Mapped user %s to %s\n",user,unixname)); mapped_user = True; diff --git a/source3/smbd/message.c b/source3/smbd/message.c index 82b3dc30a2..dbc833f091 100644 --- a/source3/smbd/message.c +++ b/source3/smbd/message.c @@ -59,7 +59,7 @@ static void msg_deliver(struct msg_state *state) if (!name) { goto done; } - fd = mkstemp(name); + fd = smb_mkstemp(name); if (fd == -1) { DEBUG(1, ("can't open message file %s: %s\n", name, @@ -145,7 +145,7 @@ void reply_sends(struct smb_request *req) START_PROFILE(SMBsends); if (!(*lp_msg_command())) { - reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED); + reply_doserror(req, ERRSRV, ERRmsgoff); END_PROFILE(SMBsends); return; } @@ -193,7 +193,7 @@ void reply_sendstrt(struct smb_request *req) START_PROFILE(SMBsendstrt); if (!(*lp_msg_command())) { - reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED); + reply_doserror(req, ERRSRV, ERRmsgoff); END_PROFILE(SMBsendstrt); return; } @@ -240,7 +240,7 @@ void reply_sendtxt(struct smb_request *req) START_PROFILE(SMBsendtxt); if (! (*lp_msg_command())) { - reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED); + reply_doserror(req, ERRSRV, ERRmsgoff); END_PROFILE(SMBsendtxt); return; } @@ -288,7 +288,7 @@ void reply_sendend(struct smb_request *req) START_PROFILE(SMBsendend); if (! (*lp_msg_command())) { - reply_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED); + reply_doserror(req, ERRSRV, ERRmsgoff); END_PROFILE(SMBsendend); return; } diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index dcef75e094..efbc05ceb0 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -268,11 +268,11 @@ NTSTATUS create_conn_struct(TALLOC_CTX *ctx, if (!smbd_vfs_init(conn)) { NTSTATUS status = map_nt_error_from_unix(errno); DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n")); - conn_free(conn); + conn_free_internal(conn); return status; } - conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res); + conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn); /* * Windows seems to insist on doing trans2getdfsreferral() calls on @@ -284,7 +284,7 @@ NTSTATUS create_conn_struct(TALLOC_CTX *ctx, if (oldcwd == NULL) { NTSTATUS status = map_nt_error_from_unix(errno); DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno))); - conn_free(conn); + conn_free_internal(conn); return status; } @@ -293,7 +293,7 @@ NTSTATUS create_conn_struct(TALLOC_CTX *ctx, DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. " "Error was %s\n", conn->connectpath, strerror(errno) )); - conn_free(conn); + conn_free_internal(conn); return status; } @@ -411,6 +411,7 @@ static bool is_msdfs_link_internal(TALLOC_CTX *ctx, char **pp_link_target, SMB_STRUCT_STAT *sbufp) { + SMB_STRUCT_STAT st; int referral_len = 0; #if defined(HAVE_BROKEN_READLINK) char link_target_buf[PATH_MAX]; @@ -419,7 +420,6 @@ static bool is_msdfs_link_internal(TALLOC_CTX *ctx, #endif size_t bufsize = 0; char *link_target = NULL; - struct smb_filename smb_fname; if (pp_link_target) { bufsize = 1024; @@ -433,22 +433,21 @@ static bool is_msdfs_link_internal(TALLOC_CTX *ctx, link_target = link_target_buf; } - ZERO_STRUCT(smb_fname); - smb_fname.base_name = discard_const_p(char, path); + if (sbufp == NULL) { + sbufp = &st; + } - if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) { + if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) { DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n", path)); goto err; } - if (!S_ISLNK(smb_fname.st.st_ex_mode)) { + + if (!S_ISLNK(sbufp->st_mode)) { DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n", path)); goto err; } - if (sbufp != NULL) { - *sbufp = smb_fname.st; - } referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1); if (referral_len == -1) { @@ -516,8 +515,9 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, { char *p = NULL; char *q = NULL; + SMB_STRUCT_STAT sbuf; NTSTATUS status; - struct smb_filename *smb_fname = NULL; + char *localpath = NULL; char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/' components). */ @@ -536,32 +536,20 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, * think this is needed. JRA. */ - status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname, - search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0); - - if (!NT_STATUS_IS_OK(status)) { - if (!NT_STATUS_EQUAL(status, - NT_STATUS_OBJECT_PATH_NOT_FOUND)) { - return status; - } - - /* Create an smb_fname to use below. */ - status = create_synthetic_smb_fname(ctx, pdp->reqpath, NULL, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath, + NULL, &sbuf); + if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, + NT_STATUS_OBJECT_PATH_NOT_FOUND)) { + return status; } /* Optimization - check if we can redirect the whole path. */ - if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name, - pp_targetpath, NULL)) { + if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) { if (search_flag) { DEBUG(6,("dfs_path_lookup (FindFirst) No redirection " "for dfs link %s.\n", dfspath)); - status = NT_STATUS_OK; - goto out; + return NT_STATUS_OK; } DEBUG(6,("dfs_path_lookup: %s resolves to a " @@ -571,8 +559,7 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, if (consumedcntp) { *consumedcntp = strlen(dfspath); } - status = NT_STATUS_PATH_NOT_COVERED; - goto out; + return NT_STATUS_PATH_NOT_COVERED; } /* Prepare to test only for '/' components in the given path, @@ -581,8 +568,7 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, canon_dfspath = talloc_strdup(ctx, dfspath); if (!canon_dfspath) { - status = NT_STATUS_NO_MEMORY; - goto out; + return NT_STATUS_NO_MEMORY; } if (!pdp->posix_path) { string_replace(canon_dfspath, '\\', '/'); @@ -604,7 +590,7 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, * DFS path. If we hit a DFS link then we're done. */ - p = strrchr_m(smb_fname->base_name, '/'); + p = strrchr_m(localpath, '/'); if (consumedcntp) { q = strrchr_m(canon_dfspath, '/'); } @@ -616,11 +602,9 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, } if (is_msdfs_link_internal(ctx, conn, - smb_fname->base_name, pp_targetpath, - NULL)) { + localpath, pp_targetpath, NULL)) { DEBUG(4, ("dfs_path_lookup: Redirecting %s because " - "parent %s is dfs link\n", dfspath, - smb_fname_str_dbg(smb_fname))); + "parent %s is dfs link\n", dfspath, localpath)); if (consumedcntp) { *consumedcntp = strlen(canon_dfspath); @@ -630,12 +614,11 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, *consumedcntp)); } - status = NT_STATUS_PATH_NOT_COVERED; - goto out; + return NT_STATUS_PATH_NOT_COVERED; } /* Step back on the filesystem. */ - p = strrchr_m(smb_fname->base_name, '/'); + p = strrchr_m(localpath, '/'); if (consumedcntp) { /* And in the canonicalized dfs path. */ @@ -643,10 +626,7 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, } } - status = NT_STATUS_OK; - out: - TALLOC_FREE(smb_fname); - return status; + return NT_STATUS_OK; } /***************************************************************** @@ -932,7 +912,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, DEBUG(3,("get_referred_path: No valid referrals for path %s\n", dfs_path)); vfs_ChDir(conn, oldpath); - conn_free(conn); + conn_free_internal(conn); TALLOC_FREE(pdp); return status; } @@ -944,13 +924,13 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, DEBUG(3,("get_referred_path: failed to parse symlink " "target %s\n", targetpath )); vfs_ChDir(conn, oldpath); - conn_free(conn); + conn_free_internal(conn); TALLOC_FREE(pdp); return NT_STATUS_NOT_FOUND; } vfs_ChDir(conn, oldpath); - conn_free(conn); + conn_free_internal(conn); TALLOC_FREE(pdp); return NT_STATUS_OK; } @@ -1367,7 +1347,7 @@ static bool junction_to_local_path(const struct junction_map *jucn, jucn->volume_name); if (!*pp_path_out) { vfs_ChDir(*conn_out, *oldpath); - conn_free(*conn_out); + conn_free_internal(*conn_out); return False; } return True; @@ -1426,22 +1406,9 @@ bool create_msdfs_link(const struct junction_map *jucn) if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) { if (errno == EEXIST) { - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - - status = create_synthetic_smb_fname(talloc_tos(), path, - NULL, NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); + if(SMB_VFS_UNLINK(conn,path)!=0) { goto out; } - - if(SMB_VFS_UNLINK(conn, smb_fname)!=0) { - TALLOC_FREE(smb_fname); - goto out; - } - TALLOC_FREE(smb_fname); } if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) { DEBUG(1,("create_msdfs_link: symlink failed " @@ -1455,7 +1422,7 @@ bool create_msdfs_link(const struct junction_map *jucn) out: vfs_ChDir(conn, cwd); - conn_free(conn); + conn_free_internal(conn); return ret; } @@ -1465,28 +1432,17 @@ bool remove_msdfs_link(const struct junction_map *jucn) char *cwd; connection_struct *conn; bool ret = False; - struct smb_filename *smb_fname = NULL; - NTSTATUS status; if (!junction_to_local_path(jucn, &path, &conn, &cwd)) { return false; } - status = create_synthetic_smb_fname(talloc_tos(), path, - NULL, NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return false; - } - - if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) { + if( SMB_VFS_UNLINK(conn, path) == 0 ) { ret = True; } - TALLOC_FREE(smb_fname); vfs_ChDir(conn, cwd); - conn_free(conn); + conn_free_internal(conn); return ret; } @@ -1498,8 +1454,7 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum) { size_t cnt = 0; SMB_STRUCT_DIR *dirp = NULL; - const char *dname = NULL; - char *talloced = NULL; + char *dname = NULL; const char *connect_path = lp_pathname(snum); const char *msdfs_proxy = lp_msdfs_proxy(snum); connection_struct *conn; @@ -1536,21 +1491,19 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum) goto out; } - while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced)) - != NULL) { + while ((dname = vfs_readdirname(conn, dirp, NULL)) != NULL) { if (is_msdfs_link(conn, dname, NULL)) { cnt++; } - TALLOC_FREE(talloced); } SMB_VFS_CLOSEDIR(conn,dirp); out: vfs_ChDir(conn, cwd); - conn_free(conn); + conn_free_internal(conn); return cnt; } @@ -1564,8 +1517,7 @@ static int form_junctions(TALLOC_CTX *ctx, { size_t cnt = 0; SMB_STRUCT_DIR *dirp = NULL; - const char *dname = NULL; - char *talloced = NULL; + char *dname = NULL; const char *connect_path = lp_pathname(snum); char *service_name = lp_servicename(snum); const char *msdfs_proxy = lp_msdfs_proxy(snum); @@ -1639,13 +1591,11 @@ static int form_junctions(TALLOC_CTX *ctx, goto out; } - while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced)) - != NULL) { + while ((dname = vfs_readdirname(conn, dirp, NULL)) != NULL) { char *link_target = NULL; if (cnt >= jn_remain) { DEBUG(2, ("form_junctions: ran out of MSDFS " "junction slots")); - TALLOC_FREE(talloced); goto out; } if (is_msdfs_link_internal(ctx, @@ -1663,7 +1613,6 @@ static int form_junctions(TALLOC_CTX *ctx, dname); if (!jucn[cnt].service_name || !jucn[cnt].volume_name) { - TALLOC_FREE(talloced); goto out; } jucn[cnt].comment = ""; @@ -1671,7 +1620,6 @@ static int form_junctions(TALLOC_CTX *ctx, } TALLOC_FREE(link_target); } - TALLOC_FREE(talloced); } out: @@ -1681,7 +1629,7 @@ out: } vfs_ChDir(conn, cwd); - conn_free(conn); + conn_free_internal(conn); return cnt; } @@ -1729,9 +1677,40 @@ struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn) } /****************************************************************************** - Core function to resolve a dfs pathname possibly containing a wildcard. If - ppath_contains_wcard != NULL, it will be set to true if a wildcard is - detected during dfs resolution. + Core function to resolve a dfs pathname. +******************************************************************************/ + +NTSTATUS resolve_dfspath(TALLOC_CTX *ctx, + connection_struct *conn, + bool dfs_pathnames, + const char *name_in, + char **pp_name_out) +{ + NTSTATUS status = NT_STATUS_OK; + bool dummy; + if (dfs_pathnames) { + status = dfs_redirect(ctx, + conn, + name_in, + False, + pp_name_out, + &dummy); + } else { + /* + * Cheat and just return a copy of the in ptr. + * Once srvstr_get_path() uses talloc it'll + * be a talloced ptr anyway. + */ + *pp_name_out = CONST_DISCARD(char *,name_in); + } + return status; +} + +/****************************************************************************** + Core function to resolve a dfs pathname possibly containing a wildcard. + This function is identical to the above except for the bool param to + dfs_redirect but I need this to be separate so it's really clear when + we're allowing wildcards and when we're not. JRA. ******************************************************************************/ NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx, @@ -1741,20 +1720,14 @@ NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx, char **pp_name_out, bool *ppath_contains_wcard) { - bool path_contains_wcard; NTSTATUS status = NT_STATUS_OK; - if (dfs_pathnames) { status = dfs_redirect(ctx, conn, name_in, True, pp_name_out, - &path_contains_wcard); - - if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) { - *ppath_contains_wcard = path_contains_wcard; - } + ppath_contains_wcard); } else { /* * Cheat and just return a copy of the in ptr. diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index 81d29d90f9..a921954c49 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -20,35 +20,29 @@ #include "includes.h" #include "smbd/globals.h" -#include "../libcli/auth/spnego.h" extern fstring remote_proto; +extern enum protocol_types Protocol; static void get_challenge(uint8 buff[8]) { NTSTATUS nt_status; - struct smbd_server_connection *sconn = smbd_server_conn; /* We might be called more than once, multiple negprots are * permitted */ - if (sconn->smb1.negprot.auth_context) { - DEBUG(3, ("get challenge: is this a secondary negprot? " - "sconn->negprot.auth_context is non-NULL!\n")); - sconn->smb1.negprot.auth_context->free( - &sconn->smb1.negprot.auth_context); + if (negprot_global_auth_context) { + DEBUG(3, ("get challenge: is this a secondary negprot? negprot_global_auth_context is non-NULL!\n")); + (negprot_global_auth_context->free)(&negprot_global_auth_context); } DEBUG(10, ("get challenge: creating negprot_global_auth_context\n")); - nt_status = make_auth_context_subsystem( - &sconn->smb1.negprot.auth_context); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0, ("make_auth_context_subsystem returned %s", - nt_errstr(nt_status))); + if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) { + DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status))); smb_panic("cannot make_negprot_global_auth_context!"); } DEBUG(10, ("get challenge: getting challenge\n")); - sconn->smb1.negprot.auth_context->get_ntlm_challenge( - sconn->smb1.negprot.auth_context, buff); + negprot_global_auth_context->get_ntlm_challenge( + negprot_global_auth_context, buff); } /**************************************************************************** @@ -60,7 +54,7 @@ static void reply_corep(struct smb_request *req, uint16 choice) reply_outbuf(req, 1, 0); SSVAL(req->outbuf, smb_vwv0, choice); - set_Protocol(PROTOCOL_CORE); + Protocol = PROTOCOL_CORE; } /**************************************************************************** @@ -80,7 +74,7 @@ static void reply_coreplus(struct smb_request *req, uint16 choice) SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); SSVAL(req->outbuf,smb_vwv1,0x1); /* user level security, don't * encrypt */ - set_Protocol(PROTOCOL_COREPLUS); + Protocol = PROTOCOL_COREPLUS; } /**************************************************************************** @@ -92,32 +86,29 @@ static void reply_lanman1(struct smb_request *req, uint16 choice) int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); int secword=0; time_t t = time(NULL); - struct smbd_server_connection *sconn = smbd_server_conn; - sconn->smb1.negprot.encrypted_passwords = lp_encrypted_passwords(); + global_encrypted_passwords_negotiated = lp_encrypted_passwords(); - if (lp_security()>=SEC_USER) { + if (lp_security()>=SEC_USER) secword |= NEGOTIATE_SECURITY_USER_LEVEL; - } - if (sconn->smb1.negprot.encrypted_passwords) { + if (global_encrypted_passwords_negotiated) secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; - } - reply_outbuf(req, 13, sconn->smb1.negprot.encrypted_passwords?8:0); + reply_outbuf(req, 13, global_encrypted_passwords_negotiated?8:0); SSVAL(req->outbuf,smb_vwv0,choice); SSVAL(req->outbuf,smb_vwv1,secword); /* Create a token value and add it to the outgoing packet. */ - if (sconn->smb1.negprot.encrypted_passwords) { + if (global_encrypted_passwords_negotiated) { get_challenge((uint8 *)smb_buf(req->outbuf)); SSVAL(req->outbuf,smb_vwv11, 8); } - set_Protocol(PROTOCOL_LANMAN1); + Protocol = PROTOCOL_LANMAN1; /* Reply, SMBlockread, SMBwritelock supported. */ SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); - SSVAL(req->outbuf,smb_vwv2,sconn->smb1.negprot.max_recv); + SSVAL(req->outbuf,smb_vwv2,max_recv); SSVAL(req->outbuf,smb_vwv3,lp_maxmux()); /* maxmux */ SSVAL(req->outbuf,smb_vwv4,1); SSVAL(req->outbuf,smb_vwv5,raw); /* tell redirector we support @@ -139,34 +130,31 @@ static void reply_lanman2(struct smb_request *req, uint16 choice) int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); int secword=0; time_t t = time(NULL); - struct smbd_server_connection *sconn = smbd_server_conn; - sconn->smb1.negprot.encrypted_passwords = lp_encrypted_passwords(); + global_encrypted_passwords_negotiated = lp_encrypted_passwords(); - if (lp_security()>=SEC_USER) { + if (lp_security()>=SEC_USER) secword |= NEGOTIATE_SECURITY_USER_LEVEL; - } - if (sconn->smb1.negprot.encrypted_passwords) { + if (global_encrypted_passwords_negotiated) secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; - } - reply_outbuf(req, 13, sconn->smb1.negprot.encrypted_passwords?8:0); + reply_outbuf(req, 13, global_encrypted_passwords_negotiated?8:0); SSVAL(req->outbuf,smb_vwv0,choice); SSVAL(req->outbuf,smb_vwv1,secword); SIVAL(req->outbuf,smb_vwv6,sys_getpid()); /* Create a token value and add it to the outgoing packet. */ - if (sconn->smb1.negprot.encrypted_passwords) { + if (global_encrypted_passwords_negotiated) { get_challenge((uint8 *)smb_buf(req->outbuf)); SSVAL(req->outbuf,smb_vwv11, 8); } - set_Protocol(PROTOCOL_LANMAN2); + Protocol = PROTOCOL_LANMAN2; /* Reply, SMBlockread, SMBwritelock supported. */ SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); - SSVAL(req->outbuf,smb_vwv2,sconn->smb1.negprot.max_recv); + SSVAL(req->outbuf,smb_vwv2,max_recv); SSVAL(req->outbuf,smb_vwv3,lp_maxmux()); SSVAL(req->outbuf,smb_vwv4,1); SSVAL(req->outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */ @@ -178,7 +166,7 @@ static void reply_lanman2(struct smb_request *req, uint16 choice) Generate the spnego negprot reply blob. Return the number of bytes used. ****************************************************************************/ -DATA_BLOB negprot_spnego(void) +static DATA_BLOB negprot_spnego(void) { DATA_BLOB blob; nstring dos_name; @@ -192,9 +180,8 @@ DATA_BLOB negprot_spnego(void) OID_NTLMSSP, NULL}; const char *OIDs_plain[] = {OID_NTLMSSP, NULL}; - struct smbd_server_connection *sconn = smbd_server_conn; - sconn->smb1.negprot.spnego = true; + global_spnego_negotiated = True; memset(guid, '\0', sizeof(guid)); @@ -263,9 +250,8 @@ static void reply_nt1(struct smb_request *req, uint16 choice) bool negotiate_spnego = False; time_t t = time(NULL); ssize_t ret; - struct smbd_server_connection *sconn = smbd_server_conn; - sconn->smb1.negprot.encrypted_passwords = lp_encrypted_passwords(); + global_encrypted_passwords_negotiated = lp_encrypted_passwords(); /* Check the flags field to see if this is Vista. WinXP sets it and Vista does not. But we have to @@ -284,7 +270,7 @@ static void reply_nt1(struct smb_request *req, uint16 choice) /* do spnego in user level security if the client supports it and we can do encrypted passwords */ - if (sconn->smb1.negprot.encrypted_passwords && + if (global_encrypted_passwords_negotiated && (lp_security() != SEC_SHARE) && lp_use_spnego() && (req->flags2 & FLAGS2_EXTENDED_SECURITY)) { @@ -318,13 +304,11 @@ static void reply_nt1(struct smb_request *req, uint16 choice) if (lp_host_msdfs()) capabilities |= CAP_DFS; - if (lp_security() >= SEC_USER) { + if (lp_security() >= SEC_USER) secword |= NEGOTIATE_SECURITY_USER_LEVEL; - } - if (sconn->smb1.negprot.encrypted_passwords) { + if (global_encrypted_passwords_negotiated) secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; - } - + if (lp_server_signing()) { if (lp_security() >= SEC_USER) { secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED; @@ -332,7 +316,7 @@ static void reply_nt1(struct smb_request *req, uint16 choice) capabilities &= ~CAP_RAW_MODE; if (lp_server_signing() == Required) secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED; - srv_set_signing_negotiated(smbd_server_conn); + srv_set_signing_negotiated(); } else { DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n")); if (lp_server_signing() == Required) { @@ -344,12 +328,11 @@ static void reply_nt1(struct smb_request *req, uint16 choice) SSVAL(req->outbuf,smb_vwv0,choice); SCVAL(req->outbuf,smb_vwv1,secword); - set_Protocol(PROTOCOL_NT1); + Protocol = PROTOCOL_NT1; SSVAL(req->outbuf,smb_vwv1+1,lp_maxmux()); /* 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_vwv3+1,max_recv); /* max buffer. LOTS! */ SIVAL(req->outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */ SIVAL(req->outbuf,smb_vwv7+1,sys_getpid()); /* session key */ SIVAL(req->outbuf,smb_vwv9+1,capabilities); /* capabilities */ @@ -359,7 +342,7 @@ static void reply_nt1(struct smb_request *req, uint16 choice) p = q = smb_buf(req->outbuf); if (!negotiate_spnego) { /* Create a token value and add it to the outgoing packet. */ - if (sconn->smb1.negprot.encrypted_passwords) { + if (global_encrypted_passwords_negotiated) { uint8 chal[8]; /* note that we do not send a challenge at all if we are using plaintext */ @@ -498,7 +481,6 @@ static const struct { void (*proto_reply_fn)(struct smb_request *req, uint16 choice); int protocol_level; } supported_protocols[] = { - {"SMB 2.002", "SMB2", reply_smb2002, PROTOCOL_SMB2}, {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1}, {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1}, {"POSIX 2", "NT1", reply_nt1, PROTOCOL_NT1}, @@ -528,15 +510,14 @@ void reply_negprot(struct smb_request *req) char **cliprotos; int i; size_t converted_size; - struct smbd_server_connection *sconn = smbd_server_conn; START_PROFILE(SMBnegprot); - if (sconn->smb1.negprot.done) { + if (done_negprot) { END_PROFILE(SMBnegprot); exit_server_cleanly("multiple negprot's are not permitted"); } - sconn->smb1.negprot.done = true; + done_negprot = True; if (req->buflen == 0) { DEBUG(0, ("negprot got no protocols\n")); @@ -697,7 +678,7 @@ void reply_negprot(struct smb_request *req) DEBUG( 5, ( "negprot index=%d\n", choice ) ); - if ((lp_server_signing() == Required) && (get_Protocol() < PROTOCOL_NT1)) { + if ((lp_server_signing() == Required) && (Protocol < PROTOCOL_NT1)) { exit_server_cleanly("SMB signing is required and " "client negotiated a downlevel protocol"); } diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index 0c75769594..059101cc5b 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -28,9 +28,6 @@ struct notify_change_request { struct smb_request *req; uint32 filter; uint32 max_param; - void (*reply_fn)(struct smb_request *req, - NTSTATUS error_code, - uint8_t *buf, size_t len); struct notify_mid_map *mid_map; void *backend_data; }; @@ -67,10 +64,6 @@ static bool notify_marshall_changes(int num_changes, int i; UNISTR uni_name; - if (num_changes == -1) { - return false; - } - uni_name.buffer = NULL; for (i=0; i<num_changes; i++) { @@ -88,7 +81,7 @@ static bool notify_marshall_changes(int num_changes, c = &changes[i]; - if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_UTF16LE, + if (!convert_string_allocate(NULL, CH_UNIX, CH_UTF16LE, c->name, strlen(c->name)+1, &uni_name.buffer, &namelen, True) || (uni_name.buffer == NULL)) { goto fail; @@ -116,7 +109,7 @@ static bool notify_marshall_changes(int num_changes, */ prs_set_offset(ps, prs_offset(ps)-2); - TALLOC_FREE(uni_name.buffer); + SAFE_FREE(uni_name.buffer); if (prs_offset(ps) > max_offset) { /* Too much data for client. */ @@ -130,7 +123,7 @@ static bool notify_marshall_changes(int num_changes, return True; fail: - TALLOC_FREE(uni_name.buffer); + SAFE_FREE(uni_name.buffer); return False; } @@ -138,24 +131,35 @@ static bool notify_marshall_changes(int num_changes, Setup the common parts of the return packet and send it. *****************************************************************************/ -void change_notify_reply(connection_struct *conn, - struct smb_request *req, - NTSTATUS error_code, - uint32_t max_param, - struct notify_change_buf *notify_buf, - void (*reply_fn)(struct smb_request *req, - NTSTATUS error_code, - uint8_t *buf, size_t len)) +static void change_notify_reply_packet(connection_struct *conn, + struct smb_request *req, + NTSTATUS error_code) { - prs_struct ps; + reply_outbuf(req, 18, 0); if (!NT_STATUS_IS_OK(error_code)) { - reply_fn(req, error_code, NULL, 0); - return; + error_packet_set((char *)req->outbuf, 0, 0, error_code, + __LINE__,__FILE__); } - if (max_param == 0 || notify_buf == NULL) { - reply_fn(req, NT_STATUS_OK, NULL, 0); + show_msg((char *)req->outbuf); + if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, + req->encrypted, &req->pcd)) { + exit_server_cleanly("change_notify_reply_packet: srv_send_smb " + "failed."); + } + TALLOC_FREE(req->outbuf); +} + +void change_notify_reply(connection_struct *conn, + struct smb_request *req, uint32 max_param, + struct notify_change_buf *notify_buf) +{ + prs_struct ps; + + if (notify_buf->num_changes == -1) { + change_notify_reply_packet(conn, req, NT_STATUS_OK); + notify_buf->num_changes = 0; return; } @@ -167,12 +171,14 @@ void change_notify_reply(connection_struct *conn, * We exceed what the client is willing to accept. Send * nothing. */ - prs_mem_free(&ps); - prs_init_empty(&ps, NULL, MARSHALL); + change_notify_reply_packet(conn, req, NT_STATUS_OK); + goto done; } - reply_fn(req, NT_STATUS_OK, (uint8_t *)prs_data_p(&ps), prs_offset(&ps)); + send_nt_replies(conn, req, NT_STATUS_OK, prs_data_p(&ps), + prs_offset(&ps), NULL, 0); + done: prs_mem_free(&ps); TALLOC_FREE(notify_buf->changes); @@ -182,7 +188,7 @@ void change_notify_reply(connection_struct *conn, static void notify_callback(void *private_data, const struct notify_event *e) { files_struct *fsp = (files_struct *)private_data; - DEBUG(10, ("notify_callback called for %s\n", fsp_str_dbg(fsp))); + DEBUG(10, ("notify_callback called for %s\n", fsp->fsp_name)); notify_fsp(fsp, e->action, e->path); } @@ -200,9 +206,8 @@ NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter, return NT_STATUS_NO_MEMORY; } - /* Do notify operations on the base_name. */ if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath, - fsp->fsp_name->base_name) == -1) { + fsp->fsp_name) == -1) { DEBUG(0, ("asprintf failed\n")); TALLOC_FREE(fsp->notify); return NT_STATUS_NO_MEMORY; @@ -227,17 +232,13 @@ NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter, NTSTATUS change_notify_add_request(struct smb_request *req, uint32 max_param, uint32 filter, bool recursive, - struct files_struct *fsp, - void (*reply_fn)(struct smb_request *req, - NTSTATUS error_code, - uint8_t *buf, size_t len)) + struct files_struct *fsp) { struct notify_change_request *request = NULL; struct notify_mid_map *map = NULL; - struct smbd_server_connection *sconn = smbd_server_conn; DEBUG(10, ("change_notify_add_request: Adding request for %s: " - "max_param = %d\n", fsp_str_dbg(fsp), (int)max_param)); + "max_param = %d\n", fsp->fsp_name, (int)max_param)); if (!(request = talloc(NULL, struct notify_change_request)) || !(map = talloc(request, struct notify_mid_map))) { @@ -252,14 +253,16 @@ NTSTATUS change_notify_add_request(struct smb_request *req, request->max_param = max_param; request->filter = filter; request->fsp = fsp; - request->reply_fn = reply_fn; request->backend_data = NULL; DLIST_ADD_END(fsp->notify->requests, request, struct notify_change_request *); map->mid = request->req->mid; - DLIST_ADD(sconn->smb1.notify_mid_maps, map); + DLIST_ADD(notify_changes_by_mid, map); + + /* Push the MID of this packet on the signing queue. */ + srv_defer_sign_response(request->req->mid); return NT_STATUS_OK; } @@ -268,7 +271,6 @@ static void change_notify_remove_request(struct notify_change_request *remove_re { files_struct *fsp; struct notify_change_request *req; - struct smbd_server_connection *sconn = smbd_server_conn; /* * Paranoia checks, the fsp referenced must must have the request in @@ -289,7 +291,7 @@ static void change_notify_remove_request(struct notify_change_request *remove_re } DLIST_REMOVE(fsp->notify->requests, req); - DLIST_REMOVE(sconn->smb1.notify_mid_maps, req->mid_map); + DLIST_REMOVE(notify_changes_by_mid, req->mid_map); TALLOC_FREE(req); } @@ -300,9 +302,8 @@ static void change_notify_remove_request(struct notify_change_request *remove_re void remove_pending_change_notify_requests_by_mid(uint16 mid) { struct notify_mid_map *map; - struct smbd_server_connection *sconn = smbd_server_conn; - for (map = sconn->smb1.notify_mid_maps; map; map = map->next) { + for (map = notify_changes_by_mid; map; map = map->next) { if (map->mid == mid) { break; } @@ -312,28 +313,8 @@ void remove_pending_change_notify_requests_by_mid(uint16 mid) return; } - change_notify_reply(map->req->fsp->conn, map->req->req, - NT_STATUS_CANCELLED, 0, NULL, map->req->reply_fn); - change_notify_remove_request(map->req); -} - -void smbd_notify_cancel_by_smbreq(struct smbd_server_connection *sconn, - const struct smb_request *smbreq) -{ - struct notify_mid_map *map; - - for (map = sconn->smb1.notify_mid_maps; map; map = map->next) { - if (map->req->req == smbreq) { - break; - } - } - - if (map == NULL) { - return; - } - - change_notify_reply(map->req->fsp->conn, map->req->req, - NT_STATUS_CANCELLED, 0, NULL, map->req->reply_fn); + change_notify_reply_packet(map->req->fsp->conn, map->req->req, + NT_STATUS_CANCELLED); change_notify_remove_request(map->req); } @@ -349,9 +330,8 @@ void remove_pending_change_notify_requests_by_fid(files_struct *fsp, } while (fsp->notify->requests != NULL) { - change_notify_reply(fsp->conn, fsp->notify->requests->req, - status, 0, NULL, - fsp->notify->requests->reply_fn); + change_notify_reply_packet( + fsp->conn, fsp->notify->requests->req, status); change_notify_remove_request(fsp->notify->requests); } } @@ -360,33 +340,17 @@ void notify_fname(connection_struct *conn, uint32 action, uint32 filter, const char *path) { char *fullpath; - char *parent; - const char *name; if (path[0] == '.' && path[1] == '/') { path += 2; } - if (parent_dirname(talloc_tos(), path, &parent, &name)) { - struct smb_filename smb_fname_parent; - - ZERO_STRUCT(smb_fname_parent); - smb_fname_parent.base_name = parent; - - if (SMB_VFS_STAT(conn, &smb_fname_parent) != -1) { - notify_onelevel(conn->notify_ctx, action, filter, - SMB_VFS_FILE_ID_CREATE(conn, &smb_fname_parent.st), - name); - } - } - - fullpath = talloc_asprintf(talloc_tos(), "%s/%s", conn->connectpath, - path); - if (fullpath == NULL) { + if (asprintf(&fullpath, "%s/%s", conn->connectpath, path) == -1) { DEBUG(0, ("asprintf failed\n")); return; } + notify_trigger(conn->notify_ctx, action, filter, fullpath); - TALLOC_FREE(fullpath); + SAFE_FREE(fullpath); } static void notify_fsp(files_struct *fsp, uint32 action, const char *name) @@ -419,10 +383,8 @@ static void notify_fsp(files_struct *fsp, uint32 action, const char *name) if (fsp->notify->requests != NULL) { change_notify_reply(fsp->conn, fsp->notify->requests->req, - NT_STATUS_OK, fsp->notify->requests->max_param, - fsp->notify, - fsp->notify->requests->reply_fn); + fsp->notify); change_notify_remove_request(fsp->notify->requests); } return; @@ -480,10 +442,8 @@ static void notify_fsp(files_struct *fsp, uint32 action, const char *name) change_notify_reply(fsp->conn, fsp->notify->requests->req, - NT_STATUS_OK, fsp->notify->requests->max_param, - fsp->notify, - fsp->notify->requests->reply_fn); + fsp->notify); change_notify_remove_request(fsp->notify->requests); } diff --git a/source3/smbd/notify_inotify.c b/source3/smbd/notify_inotify.c index 61599456c6..a12c0a6e7c 100644 --- a/source3/smbd/notify_inotify.c +++ b/source3/smbd/notify_inotify.c @@ -2,17 +2,17 @@ Unix SMB/CIFS implementation. Copyright (C) Andrew Tridgell 2006 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -142,12 +142,12 @@ static bool filter_match(struct inotify_watch_context *w, return True; } - + /* dispatch one inotify event - + the cookies are used to correctly handle renames */ static void inotify_dispatch(struct inotify_private *in, @@ -211,7 +211,7 @@ static void inotify_dispatch(struct inotify_private *in, ne.action = NOTIFY_ACTION_MODIFIED; e->mask = IN_ATTRIB; - + for (w=in->watches;w;w=next) { next = w->next; if (w->wd == e->wd && filter_match(w, e) && @@ -242,7 +242,6 @@ static void inotify_handler(struct event_context *ev, struct fd_event *fde, if (ioctl(in->fd, FIONREAD, &bufsize) != 0 || bufsize == 0) { DEBUG(0,("No data on inotify fd?!\n")); - TALLOC_FREE(fde); return; } @@ -303,7 +302,7 @@ static NTSTATUS inotify_setup(struct sys_notify_context *ctx) /* add a event waiting for the inotify fd to be readable */ event_add_fd(ctx->ev, in, in->fd, EVENT_FD_READ, inotify_handler, in); - + return NT_STATUS_OK; } @@ -357,7 +356,7 @@ static int watch_destructor(struct inotify_watch_context *w) DEBUG(1, ("inotify_rm_watch returned %s\n", strerror(errno))); } - + } return 0; } @@ -438,7 +437,7 @@ NTSTATUS inotify_watch(struct sys_notify_context *ctx, /* the caller frees the handle to stop watching */ talloc_set_destructor(w, watch_destructor); - + return NT_STATUS_OK; } diff --git a/source3/smbd/notify_internal.c b/source3/smbd/notify_internal.c index 1850e2b57f..06da717799 100644 --- a/source3/smbd/notify_internal.c +++ b/source3/smbd/notify_internal.c @@ -2,17 +2,17 @@ Unix SMB/CIFS implementation. Copyright (C) Andrew Tridgell 2006 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -27,8 +27,7 @@ #include "librpc/gen_ndr/ndr_notify.h" struct notify_context { - struct db_context *db_recursive; - struct db_context *db_onelevel; + struct db_context *db; struct server_id server; struct messaging_context *messaging_ctx; struct notify_list *list; @@ -92,18 +91,10 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server, return NULL; } - notify->db_recursive = db_open(notify, lock_path("notify.tdb"), - 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST, - O_RDWR|O_CREAT, 0644); - if (notify->db_recursive == NULL) { - talloc_free(notify); - return NULL; - } - - notify->db_onelevel = db_open(notify, lock_path("notify_onelevel.tdb"), - 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST, - O_RDWR|O_CREAT, 0644); - if (notify->db_onelevel == NULL) { + notify->db = db_open(notify, lock_path("notify.tdb"), + 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST, + O_RDWR|O_CREAT, 0644); + if (notify->db == NULL) { talloc_free(notify); return NULL; } @@ -112,8 +103,7 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server, notify->messaging_ctx = messaging_ctx; notify->list = NULL; notify->array = NULL; - notify->seqnum = notify->db_recursive->get_seqnum( - notify->db_recursive); + notify->seqnum = notify->db->get_seqnum(notify->db); notify->key = string_term_tdb_data(NOTIFY_KEY); talloc_set_destructor(notify, notify_destructor); @@ -133,8 +123,7 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server, */ static NTSTATUS notify_fetch_locked(struct notify_context *notify, struct db_record **rec) { - *rec = notify->db_recursive->fetch_locked(notify->db_recursive, - notify, notify->key); + *rec = notify->db->fetch_locked(notify->db, notify, notify->key); if (*rec == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } @@ -151,7 +140,7 @@ static NTSTATUS notify_load(struct notify_context *notify, struct db_record *rec NTSTATUS status; int seqnum; - seqnum = notify->db_recursive->get_seqnum(notify->db_recursive); + seqnum = notify->db->get_seqnum(notify->db); if (seqnum == notify->seqnum && notify->array != NULL) { return NT_STATUS_OK; @@ -164,8 +153,7 @@ static NTSTATUS notify_load(struct notify_context *notify, struct db_record *rec NT_STATUS_HAVE_NO_MEMORY(notify->array); if (!rec) { - if (notify->db_recursive->fetch(notify->db_recursive, notify, - notify->key, &dbuf) != 0) { + if (notify->db->fetch(notify->db, notify, notify->key, &dbuf) != 0) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } } else { @@ -356,96 +344,6 @@ static NTSTATUS notify_add_array(struct notify_context *notify, struct db_record } /* - Add a non-recursive watch -*/ - -static void notify_add_onelevel(struct notify_context *notify, - struct notify_entry *e, void *private_data) -{ - struct notify_entry_array *array; - struct db_record *rec; - DATA_BLOB blob; - TDB_DATA dbuf; - enum ndr_err_code ndr_err; - NTSTATUS status; - - array = talloc_zero(talloc_tos(), struct notify_entry_array); - if (array == NULL) { - return; - } - - rec = notify->db_onelevel->fetch_locked( - notify->db_onelevel, talloc_tos(), - make_tdb_data((uint8_t *)&e->dir_id, sizeof(e->dir_id))); - if (rec == NULL) { - DEBUG(10, ("notify_add_onelevel: fetch_locked for %s failed" - "\n", file_id_string_tos(&e->dir_id))); - TALLOC_FREE(array); - return; - } - - blob.data = (uint8_t *)rec->value.dptr; - blob.length = rec->value.dsize; - - if (blob.length > 0) { - ndr_err = ndr_pull_struct_blob( - &blob, array, NULL, array, - (ndr_pull_flags_fn_t)ndr_pull_notify_entry_array); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(10, ("ndr_pull_notify_entry_array failed: %s\n", - ndr_errstr(ndr_err))); - TALLOC_FREE(array); - return; - } - if (DEBUGLEVEL >= 10) { - DEBUG(10, ("notify_add_onelevel:\n")); - NDR_PRINT_DEBUG(notify_entry_array, array); - } - } - - array->entries = talloc_realloc(array, array->entries, - struct notify_entry, - array->num_entries+1); - if (array->entries == NULL) { - TALLOC_FREE(array); - return; - } - array->entries[array->num_entries] = *e; - array->entries[array->num_entries].private_data = private_data; - array->entries[array->num_entries].server = notify->server; - array->num_entries += 1; - - ndr_err = ndr_push_struct_blob( - &blob, rec, NULL, array, - (ndr_push_flags_fn_t)ndr_push_notify_entry_array); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(10, ("ndr_push_notify_entry_array failed: %s\n", - ndr_errstr(ndr_err))); - TALLOC_FREE(array); - return; - } - - if (DEBUGLEVEL >= 10) { - DEBUG(10, ("notify_add_onelevel:\n")); - NDR_PRINT_DEBUG(notify_entry_array, array); - } - - dbuf.dptr = blob.data; - dbuf.dsize = blob.length; - - status = rec->store(rec, dbuf, TDB_REPLACE); - TALLOC_FREE(array); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("notify_add_onelevel: store failed: %s\n", - nt_errstr(status))); - return; - } - e->filter = 0; - return; -} - - -/* add a notify watch. This is called when a notify is first setup on a open directory handle. */ @@ -513,11 +411,6 @@ NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e0, } } - if (e.filter != 0) { - notify_add_onelevel(notify, &e, private_data); - status = NT_STATUS_OK; - } - /* if the system notify handler couldn't handle some of the filter bits, or couldn't handle a request for recursion then we need to install it in the array used for the @@ -533,106 +426,6 @@ done: return status; } -NTSTATUS notify_remove_onelevel(struct notify_context *notify, - const struct file_id *fid, - void *private_data) -{ - struct notify_entry_array *array; - struct db_record *rec; - DATA_BLOB blob; - TDB_DATA dbuf; - enum ndr_err_code ndr_err; - NTSTATUS status; - int i; - - if (notify == NULL) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - array = talloc_zero(talloc_tos(), struct notify_entry_array); - if (array == NULL) { - return NT_STATUS_NO_MEMORY; - } - - rec = notify->db_onelevel->fetch_locked( - notify->db_onelevel, array, - make_tdb_data((uint8_t *)fid, sizeof(*fid))); - if (rec == NULL) { - DEBUG(10, ("notify_remove_onelevel: fetch_locked for %s failed" - "\n", file_id_string_tos(fid))); - TALLOC_FREE(array); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - blob.data = (uint8_t *)rec->value.dptr; - blob.length = rec->value.dsize; - - if (blob.length > 0) { - ndr_err = ndr_pull_struct_blob( - &blob, array, NULL, array, - (ndr_pull_flags_fn_t)ndr_pull_notify_entry_array); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(10, ("ndr_pull_notify_entry_array failed: %s\n", - ndr_errstr(ndr_err))); - TALLOC_FREE(array); - return ndr_map_error2ntstatus(ndr_err); - } - if (DEBUGLEVEL >= 10) { - DEBUG(10, ("notify_remove_onelevel:\n")); - NDR_PRINT_DEBUG(notify_entry_array, array); - } - } - - for (i=0; i<array->num_entries; i++) { - if ((private_data == array->entries[i].private_data) && - cluster_id_equal(¬ify->server, - &array->entries[i].server)) { - break; - } - } - - if (i == array->num_entries) { - TALLOC_FREE(array); - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - - array->entries[i] = array->entries[array->num_entries-1]; - array->num_entries -= 1; - - if (array->num_entries == 0) { - rec->delete_rec(rec); - TALLOC_FREE(array); - return NT_STATUS_OK; - } - - ndr_err = ndr_push_struct_blob( - &blob, rec, NULL, array, - (ndr_push_flags_fn_t)ndr_push_notify_entry_array); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(10, ("ndr_push_notify_entry_array failed: %s\n", - ndr_errstr(ndr_err))); - TALLOC_FREE(array); - return ndr_map_error2ntstatus(ndr_err); - } - - if (DEBUGLEVEL >= 10) { - DEBUG(10, ("notify_add_onelevel:\n")); - NDR_PRINT_DEBUG(notify_entry_array, array); - } - - dbuf.dptr = blob.data; - dbuf.dsize = blob.length; - - status = rec->store(rec, dbuf, TDB_REPLACE); - TALLOC_FREE(array); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("notify_add_onelevel: store failed: %s\n", - nt_errstr(status))); - return status; - } - return NT_STATUS_OK; -} - /* remove a notify watch. Called when the directory handle is closed */ @@ -781,96 +574,6 @@ static NTSTATUS notify_send(struct notify_context *notify, struct notify_entry * return status; } -void notify_onelevel(struct notify_context *notify, uint32_t action, - uint32_t filter, struct file_id fid, const char *name) -{ - struct notify_entry_array *array; - TDB_DATA dbuf; - DATA_BLOB blob; - bool have_dead_entries = false; - int i; - - if (notify == NULL) { - return; - } - - array = talloc_zero(talloc_tos(), struct notify_entry_array); - if (array == NULL) { - return; - } - - if (notify->db_onelevel->fetch( - notify->db_onelevel, array, - make_tdb_data((uint8_t *)&fid, sizeof(fid)), - &dbuf) == -1) { - TALLOC_FREE(array); - return; - } - - blob.data = (uint8 *)dbuf.dptr; - blob.length = dbuf.dsize; - - if (blob.length > 0) { - enum ndr_err_code ndr_err; - ndr_err = ndr_pull_struct_blob( - &blob, array, NULL, array, - (ndr_pull_flags_fn_t)ndr_pull_notify_entry_array); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(10, ("ndr_pull_notify_entry_array failed: %s\n", - ndr_errstr(ndr_err))); - TALLOC_FREE(array); - return; - } - if (DEBUGLEVEL >= 10) { - DEBUG(10, ("notify_onelevel:\n")); - NDR_PRINT_DEBUG(notify_entry_array, array); - } - } - - for (i=0; i<array->num_entries; i++) { - struct notify_entry *e = &array->entries[i]; - - if ((e->filter & filter) != 0) { - NTSTATUS status; - - status = notify_send(notify, e, name, action); - if (NT_STATUS_EQUAL( - status, NT_STATUS_INVALID_HANDLE)) { - /* - * Mark the entry as dead. All entries have a - * path set. The marker used here is setting - * that to NULL. - */ - e->path = NULL; - have_dead_entries = true; - } - } - } - - if (!have_dead_entries) { - TALLOC_FREE(array); - return; - } - - for (i=0; i<array->num_entries; i++) { - struct notify_entry *e = &array->entries[i]; - if (e->path != NULL) { - continue; - } - DEBUG(10, ("Deleting notify entries for process %s because " - "it's gone\n", procid_str_static(&e->server))); - /* - * Potential TODO: This might need optimizing, - * notify_remove_onelevel() does a fetch_locked() operation at - * every call. But this would only matter if a process with - * MANY notifies has died without shutting down properly. - */ - notify_remove_onelevel(notify, &e->dir_id, e->private_data); - } - - TALLOC_FREE(array); - return; -} /* trigger a notify message for anyone waiting on a matching event @@ -911,7 +614,7 @@ void notify_trigger(struct notify_context *notify, /* see if there are any entries at this depth */ if (d->num_entries == 0) continue; - + /* try to skip based on the maximum mask. If next_p is NULL then we know it will be a 'this directory' match, otherwise it must be a subdir match */ diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 656375499f..4bfbcd1690 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -21,6 +21,7 @@ #include "includes.h" #include "smbd/globals.h" +extern enum protocol_types Protocol; extern const struct generic_mapping file_generic_mapping; static char *nttrans_realloc(char **ptr, size_t size) @@ -57,8 +58,6 @@ void send_nt_replies(connection_struct *conn, int params_sent_thistime, data_sent_thistime, total_sent_thistime; int alignment_offset = 3; int data_alignment_offset = 0; - struct smbd_server_connection *sconn = smbd_server_conn; - int max_send = sconn->smb1.sessions.max_send; /* * If there genuinely are no parameters or data to send just send @@ -67,20 +66,7 @@ void send_nt_replies(connection_struct *conn, if(params_to_send == 0 && data_to_send == 0) { reply_outbuf(req, 18, 0); - if (NT_STATUS_V(nt_error)) { - error_packet_set((char *)req->outbuf, - 0, 0, nt_error, - __LINE__,__FILE__); - } show_msg((char *)req->outbuf); - if (!srv_send_smb(smbd_server_fd(), - (char *)req->outbuf, - true, req->seqnum+1, - IS_CONN_ENCRYPTED(conn), - &req->pcd)) { - exit_server_cleanly("send_nt_replies: srv_send_smb failed."); - } - TALLOC_FREE(req->outbuf); return; } @@ -244,7 +230,6 @@ void send_nt_replies(connection_struct *conn, show_msg((char *)req->outbuf); if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(conn), &req->pcd)) { exit_server_cleanly("send_nt_replies: srv_send_smb failed."); @@ -271,6 +256,53 @@ void send_nt_replies(connection_struct *conn, } /**************************************************************************** + Is it an NTFS stream name ? + An NTFS file name is <path>.<extention>:<stream name>:<stream type> + $DATA can be used as both a stream name and a stream type. A missing stream + name or type implies $DATA. + + Both Windows stream names and POSIX files can contain the ':' character. + This function first checks for the existence of a colon in the last component + of the given name. If the name contains a colon we differentiate between a + stream and POSIX file by checking if the latter exists through a POSIX stat. + + Function assumes we've already chdir() to the "root" directory of fname. +****************************************************************************/ + +bool is_ntfs_stream_name(const char *fname) +{ + const char *lastcomp; + SMB_STRUCT_STAT sbuf; + + /* If all pathnames are treated as POSIX we ignore streams. */ + if (lp_posix_pathnames()) { + return false; + } + + /* Find the last component of the name. */ + if ((lastcomp = strrchr_m(fname, '/')) != NULL) + ++lastcomp; + else + lastcomp = fname; + + /* If there is no colon in the last component, it's not a stream. */ + if (strchr_m(lastcomp, ':') == NULL) + return false; + + /* + * If file already exists on disk, it's not a stream. The stat must + * bypass the vfs layer so streams modules don't intefere. + */ + if (sys_stat(fname, &sbuf) == 0) { + DEBUG(5, ("is_ntfs_stream_name: file %s contains a ':' but is " + "not a stream\n", fname)); + return false; + } + + return true; +} + +/**************************************************************************** Reply to an NT create and X call on a pipe ****************************************************************************/ @@ -374,53 +406,6 @@ static void do_ntcreate_pipe_open(connection_struct *conn, chain_reply(req); } -struct case_semantics_state { - connection_struct *conn; - bool case_sensitive; - bool case_preserve; - bool short_case_preserve; -}; - -/**************************************************************************** - Restore case semantics. -****************************************************************************/ - -static int restore_case_semantics(struct case_semantics_state *state) -{ - state->conn->case_sensitive = state->case_sensitive; - state->conn->case_preserve = state->case_preserve; - state->conn->short_case_preserve = state->short_case_preserve; - return 0; -} - -/**************************************************************************** - Save case semantics. -****************************************************************************/ - -static struct case_semantics_state *set_posix_case_semantics(TALLOC_CTX *mem_ctx, - connection_struct *conn) -{ - struct case_semantics_state *result; - - if (!(result = talloc(mem_ctx, struct case_semantics_state))) { - return NULL; - } - - result->conn = conn; - result->case_sensitive = conn->case_sensitive; - result->case_preserve = conn->case_preserve; - result->short_case_preserve = conn->short_case_preserve; - - /* Set to POSIX. */ - conn->case_sensitive = True; - conn->case_preserve = True; - conn->short_case_preserve = True; - - talloc_set_destructor(result, restore_case_semantics); - - return result; -} - /**************************************************************************** Reply to an NT create and X call. ****************************************************************************/ @@ -428,7 +413,6 @@ static struct case_semantics_state *set_posix_case_semantics(TALLOC_CTX *mem_ctx void reply_ntcreate_and_X(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname = NULL; char *fname = NULL; uint32 flags; uint32 access_mask; @@ -442,14 +426,13 @@ void reply_ntcreate_and_X(struct smb_request *req) reply bits separately. */ uint32 fattr=0; SMB_OFF_T file_len = 0; + SMB_STRUCT_STAT sbuf; int info = 0; files_struct *fsp = NULL; char *p = NULL; - struct timespec create_timespec; struct timespec c_timespec; struct timespec a_timespec; struct timespec m_timespec; - struct timespec write_time_ts; NTSTATUS status; int oplock_request; uint8_t oplock_granted = NO_OPLOCK_RETURN; @@ -458,9 +441,11 @@ void reply_ntcreate_and_X(struct smb_request *req) START_PROFILE(SMBntcreateX); + SET_STAT_INVALID(sbuf); + if (req->wct < 24) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } flags = IVAL(req->vwv+3, 1); @@ -481,7 +466,8 @@ void reply_ntcreate_and_X(struct smb_request *req) if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBntcreateX); + return; } DEBUG(10,("reply_ntcreate_and_X: flags = 0x%x, access_mask = 0x%x " @@ -510,10 +496,12 @@ void reply_ntcreate_and_X(struct smb_request *req) if (IS_IPC(conn)) { if (lp_nt_pipe_support()) { do_ntcreate_pipe_open(conn, req); - goto out; + END_PROFILE(SMBntcreateX); + return; } - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - goto out; + reply_doserror(req, ERRDOS, ERRnoaccess); + END_PROFILE(SMBntcreateX); + return; } oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; @@ -522,47 +510,31 @@ void reply_ntcreate_and_X(struct smb_request *req) ? BATCH_OPLOCK : 0; } + /* + * Check if POSIX semantics are wanted. + */ + if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { case_state = set_posix_case_semantics(ctx, conn); if (!case_state) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; - } - } - - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); - - TALLOC_FREE(case_state); - - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBntcreateX); + return; } - reply_nterror(req, status); - goto out; + /* + * Bug #6898 - clients using Windows opens should + * never be able to set this attribute into the + * VFS. + */ + file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; } - /* - * Bug #6898 - clients using Windows opens should - * never be able to set this attribute into the - * VFS. - */ - file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; - status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ root_dir_fid, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + CFF_DOS_PATH, /* create_file_flags */ access_mask, /* access_mask */ share_access, /* share_access */ create_disposition, /* create_disposition*/ @@ -573,21 +545,27 @@ void reply_ntcreate_and_X(struct smb_request *req) NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + &sbuf); /* psbuf */ + + TALLOC_FREE(case_state); if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call, no error. */ - goto out; + END_PROFILE(SMBntcreateX); + return; } - reply_openerror(req, status); - goto out; + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) { + reply_botherror(req, status, ERRDOS, ERRfilexists); + } + else { + reply_nterror(req, status); + } + END_PROFILE(SMBntcreateX); + return; } - /* Ensure we're pointing at the correct stat struct. */ - TALLOC_FREE(smb_fname); - smb_fname = fsp->fsp_name; - /* * If the caller set the extended oplock request bit * and we granted one (by whatever means) - set the @@ -613,7 +591,11 @@ void reply_ntcreate_and_X(struct smb_request *req) oplock_granted = NO_OPLOCK_RETURN; } - file_len = smb_fname->st.st_ex_size; + file_len = sbuf.st_size; + fattr = dos_mode(conn,fsp->fsp_name,&sbuf); + if (fattr == 0) { + fattr = FILE_ATTRIBUTE_NORMAL; + } if (flags & EXTENDED_RESPONSE_REQUIRED) { /* This is very strange. We @@ -642,66 +624,34 @@ void reply_ntcreate_and_X(struct smb_request *req) } p += 4; - fattr = dos_mode(conn, smb_fname); - if (fattr == 0) { - fattr = FILE_ATTRIBUTE_NORMAL; - } - - /* Deal with other possible opens having a modified - write time. JRA. */ - ZERO_STRUCT(write_time_ts); - get_file_infos(fsp->file_id, NULL, &write_time_ts); - if (!null_timespec(write_time_ts)) { - update_stat_ex_mtime(&smb_fname->st, write_time_ts); - } - /* Create time. */ - create_timespec = get_create_timespec(conn, fsp, smb_fname); - a_timespec = smb_fname->st.st_ex_atime; - m_timespec = smb_fname->st.st_ex_mtime; - c_timespec = get_change_timespec(conn, fsp, smb_fname); + c_timespec = get_create_timespec( + &sbuf,lp_fake_dir_create_times(SNUM(conn))); + a_timespec = get_atimespec(&sbuf); + m_timespec = get_mtimespec(&sbuf); if (lp_dos_filetime_resolution(SNUM(conn))) { - dos_filetime_timespec(&create_timespec); + dos_filetime_timespec(&c_timespec); dos_filetime_timespec(&a_timespec); dos_filetime_timespec(&m_timespec); - dos_filetime_timespec(&c_timespec); } - put_long_date_timespec(conn->ts_res, p, create_timespec); /* create time. */ + put_long_date_timespec(conn->ts_res, p, c_timespec); /* create time. */ p += 8; put_long_date_timespec(conn->ts_res, p, a_timespec); /* access time */ p += 8; put_long_date_timespec(conn->ts_res, p, m_timespec); /* write time */ p += 8; - put_long_date_timespec(conn->ts_res, p, c_timespec); /* change time */ + put_long_date_timespec(conn->ts_res, p, m_timespec); /* change time */ p += 8; SIVAL(p,0,fattr); /* File Attributes. */ p += 4; - SOFF_T(p, 0, SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&smb_fname->st)); + SOFF_T(p, 0, SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf)); p += 8; SOFF_T(p,0,file_len); p += 8; if (flags & EXTENDED_RESPONSE_REQUIRED) { - uint16_t file_status = (NO_EAS|NO_SUBSTREAMS|NO_REPARSETAG); - size_t num_names = 0; - unsigned int num_streams; - struct stream_struct *streams = NULL; - - /* Do we have any EA's ? */ - status = get_ea_names_from_file(ctx, conn, fsp, - smb_fname->base_name, NULL, &num_names); - if (NT_STATUS_IS_OK(status) && num_names) { - file_status &= ~NO_EAS; - } - status = SMB_VFS_STREAMINFO(conn, NULL, smb_fname->base_name, ctx, - &num_streams, &streams); - /* There is always one stream, ::$DATA. */ - if (NT_STATUS_IS_OK(status) && num_streams > 1) { - file_status &= ~NO_SUBSTREAMS; - } - TALLOC_FREE(streams); - SSVAL(p,2,file_status); + SSVAL(p,2,0x7); } p += 4; SCVAL(p,0,fsp->is_directory ? 1 : 0); @@ -709,8 +659,8 @@ void reply_ntcreate_and_X(struct smb_request *req) if (flags & EXTENDED_RESPONSE_REQUIRED) { uint32 perms = 0; p += 25; - if (fsp->is_directory || - can_write_to_file(conn, smb_fname)) { + if (fsp->is_directory + || can_write_to_file(conn, fsp->fsp_name, &sbuf)) { perms = FILE_GENERIC_ALL; } else { perms = FILE_GENERIC_READ|FILE_EXECUTE; @@ -719,10 +669,9 @@ void reply_ntcreate_and_X(struct smb_request *req) } DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", - fsp->fnum, smb_fname_str_dbg(smb_fname))); + fsp->fnum, fsp->fsp_name)); chain_reply(req); - out: END_PROFILE(SMBntcreateX); return; } @@ -752,7 +701,7 @@ static void do_nt_transact_create_pipe(connection_struct *conn, if(parameter_count < 54) { DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)parameter_count)); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRnoaccess); return; } @@ -782,7 +731,7 @@ static void do_nt_transact_create_pipe(connection_struct *conn, } params = nttrans_realloc(ppparams, param_len); if(params == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); return; } @@ -855,7 +804,7 @@ static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len, security_acl_map_generic(psd->sacl, &file_generic_mapping); if (DEBUGLEVEL >= 10) { - DEBUG(10,("set_sd for file %s\n", fsp_str_dbg(fsp))); + DEBUG(10,("set_sd for file %s\n", fsp->fsp_name )); NDR_PRINT_DEBUG(security_descriptor, psd); } @@ -870,7 +819,7 @@ static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len, Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. ****************************************************************************/ -struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size) +static struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size) { struct ea_list *ea_list_head = NULL; size_t offset = 0; @@ -908,13 +857,13 @@ static void call_nt_transact_create(connection_struct *conn, char **ppdata, uint32 data_count, uint32 max_data_count) { - struct smb_filename *smb_fname = NULL; char *fname = NULL; char *params = *ppparams; char *data = *ppdata; /* Breakout the oplock request bits so we can set the reply bits separately. */ uint32 fattr=0; SMB_OFF_T file_len = 0; + SMB_STRUCT_STAT sbuf; int info = 0; files_struct *fsp = NULL; char *p = NULL; @@ -928,11 +877,9 @@ static void call_nt_transact_create(connection_struct *conn, struct security_descriptor *sd = NULL; uint32 ea_len; uint16 root_dir_fid; - struct timespec create_timespec; struct timespec c_timespec; struct timespec a_timespec; struct timespec m_timespec; - struct timespec write_time_ts; struct ea_list *ea_list = NULL; NTSTATUS status; size_t param_len; @@ -942,6 +889,8 @@ static void call_nt_transact_create(connection_struct *conn, struct case_semantics_state *case_state = NULL; TALLOC_CTX *ctx = talloc_tos(); + SET_STAT_INVALID(sbuf); + DEBUG(5,("call_nt_transact_create\n")); /* @@ -955,10 +904,10 @@ static void call_nt_transact_create(connection_struct *conn, ppsetup, setup_count, ppparams, parameter_count, ppdata, data_count); - goto out; + return; } - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - goto out; + reply_doserror(req, ERRDOS, ERRnoaccess); + return; } /* @@ -968,7 +917,7 @@ static void call_nt_transact_create(connection_struct *conn, if(parameter_count < 54) { DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)parameter_count)); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } flags = IVAL(params,0); @@ -999,7 +948,7 @@ static void call_nt_transact_create(connection_struct *conn, "%u, data_count = %u\n", (unsigned int)ea_len, (unsigned int)sd_len, (unsigned int)data_count)); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } if (sd_len) { @@ -1013,7 +962,7 @@ static void call_nt_transact_create(connection_struct *conn, "unmarshall_sec_desc failed: %s\n", nt_errstr(status))); reply_nterror(req, status); - goto out; + return; } } @@ -1023,7 +972,7 @@ static void call_nt_transact_create(connection_struct *conn, "EA's not supported.\n", (unsigned int)ea_len)); reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); - goto out; + return; } if (ea_len < 10) { @@ -1031,7 +980,7 @@ static void call_nt_transact_create(connection_struct *conn, "too small (should be more than 10)\n", (unsigned int)ea_len )); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } /* We have already checked that ea_len <= data_count here. */ @@ -1039,7 +988,7 @@ static void call_nt_transact_create(connection_struct *conn, ea_len); if (ea_list == NULL) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } } @@ -1048,36 +997,7 @@ static void call_nt_transact_create(connection_struct *conn, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; - } - - if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { - case_state = set_posix_case_semantics(ctx, conn); - if (!case_state) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; - } - } - - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); - - TALLOC_FREE(case_state); - - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - goto out; - } - reply_nterror(req, status); - goto out; + return; } oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; @@ -1087,17 +1007,29 @@ static void call_nt_transact_create(connection_struct *conn, } /* - * Bug #6898 - clients using Windows opens should - * never be able to set this attribute into the - * VFS. + * Check if POSIX semantics are wanted. */ - file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; + + if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { + case_state = set_posix_case_semantics(ctx, conn); + if (!case_state) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + /* + * Bug #6898 - clients using Windows opens should + * never be able to set this attribute into the + * VFS. + */ + file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; + } status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ root_dir_fid, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + CFF_DOS_PATH, /* create_file_flags */ access_mask, /* access_mask */ share_access, /* share_access */ create_disposition, /* create_disposition*/ @@ -1108,7 +1040,10 @@ static void call_nt_transact_create(connection_struct *conn, sd, /* sd */ ea_list, /* ea_list */ &fsp, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + &sbuf); /* psbuf */ + + TALLOC_FREE(case_state); if(!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { @@ -1116,13 +1051,9 @@ static void call_nt_transact_create(connection_struct *conn, return; } reply_openerror(req, status); - goto out; + return; } - /* Ensure we're pointing at the correct stat struct. */ - TALLOC_FREE(smb_fname); - smb_fname = fsp->fsp_name; - /* * If the caller set the extended oplock request bit * and we granted one (by whatever means) - set the @@ -1148,7 +1079,11 @@ static void call_nt_transact_create(connection_struct *conn, oplock_granted = NO_OPLOCK_RETURN; } - file_len = smb_fname->st.st_ex_size; + file_len = sbuf.st_size; + fattr = dos_mode(conn,fsp->fsp_name,&sbuf); + if (fattr == 0) { + fattr = FILE_ATTRIBUTE_NORMAL; + } /* Realloc the size of parameters and data we will return */ if (flags & EXTENDED_RESPONSE_REQUIRED) { @@ -1159,8 +1094,8 @@ static void call_nt_transact_create(connection_struct *conn, } params = nttrans_realloc(ppparams, param_len); if(params == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + reply_doserror(req, ERRDOS, ERRnomem); + return; } p = params; @@ -1177,43 +1112,29 @@ static void call_nt_transact_create(connection_struct *conn, } p += 8; - fattr = dos_mode(conn, smb_fname); - if (fattr == 0) { - fattr = FILE_ATTRIBUTE_NORMAL; - } - - /* Deal with other possible opens having a modified - write time. JRA. */ - ZERO_STRUCT(write_time_ts); - get_file_infos(fsp->file_id, NULL, &write_time_ts); - if (!null_timespec(write_time_ts)) { - update_stat_ex_mtime(&smb_fname->st, write_time_ts); - } - /* Create time. */ - create_timespec = get_create_timespec(conn, fsp, smb_fname); - a_timespec = smb_fname->st.st_ex_atime; - m_timespec = smb_fname->st.st_ex_mtime; - c_timespec = get_change_timespec(conn, fsp, smb_fname); + c_timespec = get_create_timespec( + &sbuf,lp_fake_dir_create_times(SNUM(conn))); + a_timespec = get_atimespec(&sbuf); + m_timespec = get_mtimespec(&sbuf); if (lp_dos_filetime_resolution(SNUM(conn))) { - dos_filetime_timespec(&create_timespec); + dos_filetime_timespec(&c_timespec); dos_filetime_timespec(&a_timespec); dos_filetime_timespec(&m_timespec); - dos_filetime_timespec(&c_timespec); } - put_long_date_timespec(conn->ts_res, p, create_timespec); /* create time. */ + put_long_date_timespec(conn->ts_res, p, c_timespec); /* create time. */ p += 8; put_long_date_timespec(conn->ts_res, p, a_timespec); /* access time */ p += 8; put_long_date_timespec(conn->ts_res, p, m_timespec); /* write time */ p += 8; - put_long_date_timespec(conn->ts_res, p, c_timespec); /* change time */ + put_long_date_timespec(conn->ts_res, p, m_timespec); /* change time */ p += 8; SIVAL(p,0,fattr); /* File Attributes. */ p += 4; - SOFF_T(p, 0, SMB_VFS_GET_ALLOC_SIZE(conn, fsp, &smb_fname->st)); + SOFF_T(p, 0, SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf)); p += 8; SOFF_T(p,0,file_len); p += 8; @@ -1226,8 +1147,8 @@ static void call_nt_transact_create(connection_struct *conn, if (flags & EXTENDED_RESPONSE_REQUIRED) { uint32 perms = 0; p += 25; - if (fsp->is_directory || - can_write_to_file(conn, smb_fname)) { + if (fsp->is_directory + || can_write_to_file(conn, fsp->fsp_name, &sbuf)) { perms = FILE_GENERIC_ALL; } else { perms = FILE_GENERIC_READ|FILE_EXECUTE; @@ -1235,12 +1156,11 @@ static void call_nt_transact_create(connection_struct *conn, SIVAL(p,0,perms); } - DEBUG(5,("call_nt_transact_create: open name = %s\n", - smb_fname_str_dbg(smb_fname))); + DEBUG(5,("call_nt_transact_create: open name = %s\n", fsp->fsp_name)); /* Send the required number of replies */ send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0); - out: + return; } @@ -1256,9 +1176,9 @@ void reply_ntcancel(struct smb_request *req) */ START_PROFILE(SMBntcancel); - srv_cancel_sign_response(smbd_server_conn); remove_pending_change_notify_requests_by_mid(req->mid); remove_pending_lock_requests_by_mid(req->mid); + srv_cancel_sign_response(req->mid, true); DEBUG(3,("reply_ntcancel: cancel called on mid = %d.\n", req->mid)); @@ -1273,10 +1193,15 @@ void reply_ntcancel(struct smb_request *req) static NTSTATUS copy_internals(TALLOC_CTX *ctx, connection_struct *conn, struct smb_request *req, - struct smb_filename *smb_fname_src, - struct smb_filename *smb_fname_dst, + const char *oldname_in, + const char *newname_in, uint32 attrs) { + SMB_STRUCT_STAT sbuf1, sbuf2; + char *oldname = NULL; + char *newname = NULL; + char *last_component_oldname = NULL; + char *last_component_newname = NULL; files_struct *fsp1,*fsp2; uint32 fattr; int info; @@ -1284,45 +1209,70 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, NTSTATUS status = NT_STATUS_OK; char *parent; + ZERO_STRUCT(sbuf1); + ZERO_STRUCT(sbuf2); + if (!CAN_WRITE(conn)) { - status = NT_STATUS_MEDIA_WRITE_PROTECTED; - goto out; + return NT_STATUS_MEDIA_WRITE_PROTECTED; } - /* Source must already exist. */ - if (!VALID_STAT(smb_fname_src->st)) { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - goto out; + status = unix_convert(ctx, conn, oldname_in, False, &oldname, + &last_component_oldname, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + return status; } + status = check_name(conn, oldname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Source must already exist. */ + if (!VALID_STAT(sbuf1)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } /* Ensure attributes match. */ - fattr = dos_mode(conn, smb_fname_src); + fattr = dos_mode(conn,oldname,&sbuf1); if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) { - status = NT_STATUS_NO_SUCH_FILE; - goto out; + return NT_STATUS_NO_SUCH_FILE; } - /* Disallow if dst file already exists. */ - if (VALID_STAT(smb_fname_dst->st)) { - status = NT_STATUS_OBJECT_NAME_COLLISION; - goto out; + status = unix_convert(ctx, conn, newname_in, False, &newname, + &last_component_newname, &sbuf2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = check_name(conn, newname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Disallow if newname already exists. */ + if (VALID_STAT(sbuf2)) { + return NT_STATUS_OBJECT_NAME_COLLISION; } /* No links from a directory. */ - if (S_ISDIR(smb_fname_src->st.st_ex_mode)) { - status = NT_STATUS_FILE_IS_A_DIRECTORY; - goto out; + if (S_ISDIR(sbuf1.st_mode)) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + /* Ensure this is within the share. */ + status = check_reduced_name(conn, oldname); + if (!NT_STATUS_IS_OK(status)) { + return status; } DEBUG(10,("copy_internals: doing file copy %s to %s\n", - smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst))); + oldname, newname)); status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname_src, /* fname */ + oldname, /* fname */ + 0, /* create_file_flags */ FILE_READ_DATA, /* access_mask */ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ FILE_SHARE_DELETE), @@ -1334,17 +1284,19 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp1, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + &sbuf1); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { - goto out; + return status; } status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname_dst, /* fname */ + newname, /* fname */ + 0, /* create_file_flags */ FILE_WRITE_DATA, /* access_mask */ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ FILE_SHARE_DELETE), @@ -1356,15 +1308,16 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp2, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + &sbuf2); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { close_file(NULL, fsp1, ERROR_CLOSE); - goto out; + return status; } - if (smb_fname_src->st.st_ex_size) { - ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size); + if (sbuf1.st_size) { + ret = vfs_transfer_file(fsp1, fsp2, sbuf1.st_size); } /* @@ -1376,32 +1329,27 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, close_file(NULL, fsp1, NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime); + set_close_write_time(fsp2, get_mtimespec(&sbuf1)); status = close_file(NULL, fsp2, NORMAL_CLOSE); /* Grrr. We have to do this as open_file_ntcreate adds aARCH when it creates the file. This isn't the correct thing to do in the copy case. JRA */ - if (!parent_dirname(talloc_tos(), smb_fname_dst->base_name, &parent, - NULL)) { - status = NT_STATUS_NO_MEMORY; - goto out; + if (!parent_dirname(talloc_tos(), newname, &parent, NULL)) { + return NT_STATUS_NO_MEMORY; } - file_set_dosmode(conn, smb_fname_dst, fattr, parent, false); + file_set_dosmode(conn, newname, fattr, &sbuf2, parent, false); TALLOC_FREE(parent); - if (ret < (SMB_OFF_T)smb_fname_src->st.st_ex_size) { - status = NT_STATUS_DISK_FULL; - goto out; + if (ret < (SMB_OFF_T)sbuf1.st_size) { + return NT_STATUS_DISK_FULL; } - out: + if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("copy_internals: Error %s copy file %s to %s\n", - nt_errstr(status), smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst))); + nt_errstr(status), oldname, newname)); } - return status; } @@ -1412,8 +1360,6 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, void reply_ntrename(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname_old = NULL; - struct smb_filename *smb_fname_new = NULL; char *oldname = NULL; char *newname = NULL; const char *p; @@ -1421,8 +1367,6 @@ void reply_ntrename(struct smb_request *req) bool src_has_wcard = False; bool dest_has_wcard = False; uint32 attrs; - uint32_t ucf_flags_src = 0; - uint32_t ucf_flags_dst = 0; uint16 rename_type; TALLOC_CTX *ctx = talloc_tos(); @@ -1430,7 +1374,8 @@ void reply_ntrename(struct smb_request *req) if (req->wct < 4) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBntrename); + return; } attrs = SVAL(req->vwv+0, 0); @@ -1441,12 +1386,14 @@ void reply_ntrename(struct smb_request *req) &status, &src_has_wcard); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBntrename); + return; } if (ms_has_wild(oldname)) { reply_nterror(req, NT_STATUS_OBJECT_PATH_SYNTAX_BAD); - goto out; + END_PROFILE(SMBntrename); + return; } p++; @@ -1454,81 +1401,66 @@ void reply_ntrename(struct smb_request *req) &status, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; - } - - /* The newname must begin with a ':' if the oldname contains a ':'. */ - if (strchr_m(oldname, ':') && (newname[0] != ':')) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBntrename); + return; } - /* - * If this is a rename operation, allow wildcards and save the - * destination's last component. - */ - if (rename_type == RENAME_FLAG_RENAME) { - ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP; - ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP; - } - - /* rename_internals() calls unix_convert(), so don't call it here. */ - status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - oldname, - ucf_flags_src, - NULL, - &smb_fname_old); + status = resolve_dfspath(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + oldname, + &oldname); if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status, - NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBntrename); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBntrename); + return; } - status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - newname, - ucf_flags_dst, - &dest_has_wcard, - &smb_fname_new); + status = resolve_dfspath(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + newname, + &newname); if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status, - NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBntrename); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBntrename); + return; + } + + /* The new name must begin with a ':' if the old name is a stream. */ + if (is_ntfs_stream_name(oldname) && (newname[0] != ':')) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + END_PROFILE(SMBntrename); + return; } - DEBUG(3,("reply_ntrename: %s -> %s\n", - smb_fname_str_dbg(smb_fname_old), - smb_fname_str_dbg(smb_fname_new))); + DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname)); switch(rename_type) { case RENAME_FLAG_RENAME: - status = rename_internals(ctx, conn, req, - smb_fname_old, smb_fname_new, - attrs, False, src_has_wcard, - dest_has_wcard, - DELETE_ACCESS); + status = rename_internals(ctx, conn, req, oldname, + newname, attrs, False, src_has_wcard, + dest_has_wcard, DELETE_ACCESS); break; case RENAME_FLAG_HARD_LINK: if (src_has_wcard || dest_has_wcard) { /* No wildcards. */ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { - status = hardlink_internals(ctx, conn, - smb_fname_old, - smb_fname_new); + status = hardlink_internals(ctx, + conn, + oldname, + newname); } break; case RENAME_FLAG_COPY: @@ -1536,10 +1468,8 @@ void reply_ntrename(struct smb_request *req) /* No wildcards. */ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { - status = copy_internals(ctx, conn, req, - smb_fname_old, - smb_fname_new, - attrs); + status = copy_internals(ctx, conn, req, oldname, + newname, attrs); } break; case RENAME_FLAG_MOVE_CLUSTER_INFORMATION: @@ -1553,15 +1483,17 @@ void reply_ntrename(struct smb_request *req) if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - goto out; + END_PROFILE(SMBntrename); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBntrename); + return; } reply_outbuf(req, 0, 0); - out: + END_PROFILE(SMBntrename); return; } @@ -1571,13 +1503,6 @@ void reply_ntrename(struct smb_request *req) don't allow a directory to be opened. ****************************************************************************/ -static void smbd_smb1_notify_reply(struct smb_request *req, - NTSTATUS error_code, - uint8_t *buf, size_t len) -{ - send_nt_replies(req->conn, req, error_code, (char *)buf, len, NULL, 0); -} - static void call_nt_transact_notify_change(connection_struct *conn, struct smb_request *req, uint16 **ppsetup, @@ -1595,7 +1520,7 @@ static void call_nt_transact_notify_change(connection_struct *conn, bool recursive; if(setup_count < 6) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRbadfunc); return; } @@ -1606,7 +1531,7 @@ static void call_nt_transact_notify_change(connection_struct *conn, DEBUG(3,("call_nt_transact_notify_change\n")); if(!fsp) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); + reply_doserror(req, ERRDOS, ERRbadfid); return; } @@ -1620,7 +1545,7 @@ static void call_nt_transact_notify_change(connection_struct *conn, DEBUG(3,("call_nt_transact_notify_change: notify change " "called on %s, filter = %s, recursive = %d\n", - fsp_str_dbg(fsp), filter_string, recursive)); + fsp->fsp_name, filter_string, recursive)); TALLOC_FREE(filter_string); } @@ -1653,11 +1578,8 @@ static void call_nt_transact_notify_change(connection_struct *conn, * here. */ - change_notify_reply(fsp->conn, req, - NT_STATUS_OK, - max_param_count, - fsp->notify, - smbd_smb1_notify_reply); + change_notify_reply(fsp->conn, req, max_param_count, + fsp->notify); /* * change_notify_reply() above has independently sent its @@ -1673,8 +1595,7 @@ static void call_nt_transact_notify_change(connection_struct *conn, status = change_notify_add_request(req, max_param_count, filter, - recursive, fsp, - smbd_smb1_notify_reply); + recursive, fsp); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); } @@ -1700,7 +1621,7 @@ static void call_nt_transact_rename(connection_struct *conn, TALLOC_CTX *ctx = talloc_tos(); if(parameter_count < 5) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRbadfunc); return; } @@ -1723,7 +1644,7 @@ static void call_nt_transact_rename(connection_struct *conn, send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); DEBUG(3,("nt transact rename from = %s, to = %s ignored!\n", - fsp_str_dbg(fsp), new_name)); + fsp->fsp_name, new_name)); return; } @@ -1769,25 +1690,24 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, DATA_BLOB blob; if(parameter_count < 8) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRbadfunc); return; } fsp = file_fsp(req, SVAL(params,0)); if(!fsp) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); + reply_doserror(req, ERRDOS, ERRbadfid); return; } security_info_wanted = IVAL(params,4); - DEBUG(3,("call_nt_transact_query_security_desc: file = %s, " - "info_wanted = 0x%x\n", fsp_str_dbg(fsp), - (unsigned int)security_info_wanted)); + DEBUG(3,("call_nt_transact_query_security_desc: file = %s, info_wanted = 0x%x\n", fsp->fsp_name, + (unsigned int)security_info_wanted )); params = nttrans_realloc(ppparams, 4); if(params == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); return; } @@ -1820,8 +1740,7 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %lu.\n",(unsigned long)sd_size)); if (DEBUGLEVEL >= 10) { - DEBUG(10,("call_nt_transact_query_security_desc for file %s\n", - fsp_str_dbg(fsp))); + DEBUG(10,("call_nt_transact_query_security_desc for file %s\n", fsp->fsp_name)); NDR_PRINT_DEBUG(security_descriptor, psd); } @@ -1839,7 +1758,7 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, data = nttrans_realloc(ppdata, sd_size); if(data == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); return; } @@ -1880,12 +1799,12 @@ static void call_nt_transact_set_security_desc(connection_struct *conn, NTSTATUS status; if(parameter_count < 8) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRbadfunc); return; } if((fsp = file_fsp(req, SVAL(params,0))) == NULL) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); + reply_doserror(req, ERRDOS, ERRbadfid); return; } @@ -1895,11 +1814,11 @@ static void call_nt_transact_set_security_desc(connection_struct *conn, security_info_sent = IVAL(params,4); - DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", - fsp_str_dbg(fsp), (unsigned int)security_info_sent)); + DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name, + (unsigned int)security_info_sent )); if (data_count == 0) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRnoaccess); return; } @@ -2120,7 +2039,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, cur_pdata+=12; DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n", - shadow_data->num_volumes, fsp_str_dbg(fsp))); + shadow_data->num_volumes,fsp->fsp_name)); if (labels && shadow_data->labels) { for (i=0;i<shadow_data->num_volumes;i++) { srvstr_push(pdata, req->flags2, @@ -2243,7 +2162,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, DEBUG(1,("get_user_quota: access_denied service [%s] user " "[%s]\n", lp_servicename(SNUM(conn)), conn->server_info->unix_name)); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRnoaccess); return; } @@ -2253,7 +2172,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, if (parameter_count < 4) { DEBUG(0,("TRANSACT_GET_USER_QUOTA: requires %d >= 4 bytes parameters\n",parameter_count)); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRinvalidparam); return; } @@ -2288,7 +2207,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, param_len = 4; params = nttrans_realloc(ppparams, param_len); if(params == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); return; } @@ -2308,7 +2227,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, } if (start_enum && vfs_get_user_ntquota_list(fsp,&(qt_handle->quota_list))!=0) { - reply_nterror(req, NT_STATUS_INTERNAL_ERROR); + reply_doserror(req, ERRSRV, ERRerror); return; } @@ -2316,7 +2235,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, param_len = 4; params = nttrans_realloc(ppparams, param_len); if(params == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); return; } @@ -2325,7 +2244,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, pdata = nttrans_realloc(ppdata, max_data_count);/* should be max data count from client*/ if(pdata == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); return; } @@ -2388,20 +2307,20 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, if (data_count < 8) { DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %d bytes data\n",data_count,8)); - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + reply_doserror(req, ERRDOS, ERRunknownlevel); return; } sid_len = IVAL(pdata,4); /* Ensure this is less than 1mb. */ if (sid_len > (1024*1024)) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); return; } if (data_count < 8+sid_len) { DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %lu bytes data\n",data_count,(unsigned long)(8+sid_len))); - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + reply_doserror(req, ERRDOS, ERRunknownlevel); return; } @@ -2432,13 +2351,13 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, param_len = 4; params = nttrans_realloc(ppparams, param_len); if(params == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); return; } pdata = nttrans_realloc(ppdata, data_len); if(pdata == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); return; } @@ -2472,7 +2391,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, default: DEBUG(0,("do_nt_transact_get_user_quota: fnum %d unknown level 0x%04hX\n",fsp->fnum,level)); - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + reply_doserror(req, ERRSRV, ERRerror); return; break; } @@ -2510,7 +2429,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, DEBUG(1,("set_user_quota: access_denied service [%s] user " "[%s]\n", lp_servicename(SNUM(conn)), conn->server_info->unix_name)); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRnoaccess); return; } @@ -2520,7 +2439,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, if (parameter_count < 2) { DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= 2 bytes parameters\n",parameter_count)); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRinvalidparam); return; } @@ -2534,7 +2453,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, if (data_count < 40) { DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %d bytes data\n",data_count,40)); - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + reply_doserror(req, ERRDOS, ERRunknownlevel); return; } @@ -2548,7 +2467,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, if (data_count < 40+sid_len) { DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %lu bytes data\n",data_count,(unsigned long)40+sid_len)); - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + reply_doserror(req, ERRDOS, ERRunknownlevel); return; } @@ -2565,7 +2484,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, ((qt.usedspace != 0xFFFFFFFF)|| (IVAL(pdata,20)!=0xFFFFFFFF))) { /* more than 32 bits? */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + reply_doserror(req, ERRDOS, ERRunknownlevel); return; } #endif /* LARGE_SMB_OFF_T */ @@ -2579,7 +2498,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, ((qt.softlim != 0xFFFFFFFF)|| (IVAL(pdata,28)!=0xFFFFFFFF))) { /* more than 32 bits? */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + reply_doserror(req, ERRDOS, ERRunknownlevel); return; } #endif /* LARGE_SMB_OFF_T */ @@ -2593,7 +2512,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, ((qt.hardlim != 0xFFFFFFFF)|| (IVAL(pdata,36)!=0xFFFFFFFF))) { /* more than 32 bits? */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + reply_doserror(req, ERRDOS, ERRunknownlevel); return; } #endif /* LARGE_SMB_OFF_T */ @@ -2604,7 +2523,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, /* 44 unknown bytes left... */ if (vfs_set_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) { - reply_nterror(req, NT_STATUS_INTERNAL_ERROR); + reply_doserror(req, ERRSRV, ERRerror); return; } @@ -2617,7 +2536,7 @@ static void handle_nttrans(connection_struct *conn, struct trans_state *state, struct smb_request *req) { - if (get_Protocol() >= PROTOCOL_NT1) { + if (Protocol >= PROTOCOL_NT1) { req->flags2 |= 0x40; /* IS_LONG_NAME */ SSVAL(req->inbuf,smb_flg2,req->flags2); } @@ -2738,7 +2657,7 @@ static void handle_nttrans(connection_struct *conn, /* Error in request */ DEBUG(0,("handle_nttrans: Unknown request %d in " "nttrans call\n", state->call)); - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + reply_doserror(req, ERRSRV, ERRerror); return; } return; @@ -2774,7 +2693,7 @@ void reply_nttrans(struct smb_request *req) function_code = SVAL(req->vwv+18, 0); if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRSRV, ERRaccess); END_PROFILE(SMBnttrans); return; } @@ -2788,7 +2707,7 @@ void reply_nttrans(struct smb_request *req) } if ((state = TALLOC_P(conn, struct trans_state)) == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRSRV, ERRaccess); END_PROFILE(SMBnttrans); return; } @@ -2834,7 +2753,7 @@ void reply_nttrans(struct smb_request *req) /* Don't allow more than 128mb for each value. */ if ((state->total_data > (1024*1024*128)) || (state->total_param > (1024*1024*128))) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); END_PROFILE(SMBnttrans); return; } @@ -2855,7 +2774,7 @@ void reply_nttrans(struct smb_request *req) DEBUG(0,("reply_nttrans: data malloc fail for %u " "bytes !\n", (unsigned int)state->total_data)); TALLOC_FREE(state); - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); END_PROFILE(SMBnttrans); return; } @@ -2877,7 +2796,7 @@ void reply_nttrans(struct smb_request *req) "bytes !\n", (unsigned int)state->total_param)); SAFE_FREE(state->data); TALLOC_FREE(state); - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); END_PROFILE(SMBnttrans); return; } @@ -2910,7 +2829,7 @@ void reply_nttrans(struct smb_request *req) SAFE_FREE(state->data); SAFE_FREE(state->param); TALLOC_FREE(state); - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); END_PROFILE(SMBnttrans); return; } diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 120de0f21a..ab3bf1ec75 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -31,7 +31,7 @@ struct deferred_open_record { static NTSTATUS create_file_unixpath(connection_struct *conn, struct smb_request *req, - struct smb_filename *smb_fname, + const char *fname, uint32_t access_mask, uint32_t share_access, uint32_t create_disposition, @@ -43,7 +43,8 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, struct ea_list *ea_list, files_struct **result, - int *pinfo); + int *pinfo, + SMB_STRUCT_STAT *psbuf); /**************************************************************************** SMB1 file varient of se_access_check. Never test FILE_READ_ATTRIBUTES. @@ -64,14 +65,14 @@ NTSTATUS smb1_file_se_access_check(const struct security_descriptor *sd, Check if we have open rights. ****************************************************************************/ -NTSTATUS smbd_check_open_rights(struct connection_struct *conn, - const struct smb_filename *smb_fname, +static NTSTATUS check_open_rights(struct connection_struct *conn, + const char *fname, uint32_t access_mask, uint32_t *access_granted) { /* Check if we have rights to open. */ NTSTATUS status; - struct security_descriptor *sd = NULL; + struct security_descriptor *sd; *access_granted = 0; @@ -84,15 +85,15 @@ NTSTATUS smbd_check_open_rights(struct connection_struct *conn, return NT_STATUS_OK; } - status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name, + status = SMB_VFS_GET_NT_ACL(conn, fname, (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION),&sd); if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("smbd_check_open_rights: Could not get acl " + DEBUG(10, ("check_open_rights: Could not get acl " "on %s: %s\n", - smb_fname_str_dbg(smb_fname), + fname, nt_errstr(status))); return status; } @@ -102,23 +103,15 @@ NTSTATUS smbd_check_open_rights(struct connection_struct *conn, access_mask, access_granted); - DEBUG(10,("smbd_check_open_rights: file %s requesting " + TALLOC_FREE(sd); + + DEBUG(10,("check_open_rights: file %s requesting " "0x%x returning 0x%x (%s)\n", - smb_fname_str_dbg(smb_fname), + fname, (unsigned int)access_mask, (unsigned int)*access_granted, nt_errstr(status) )); - if (!NT_STATUS_IS_OK(status)) { - if (DEBUGLEVEL >= 10) { - DEBUG(10,("smbd_check_open_rights: acl for %s is:\n", - smb_fname_str_dbg(smb_fname) )); - NDR_PRINT_DEBUG(security_descriptor, sd); - } - } - - TALLOC_FREE(sd); - return status; } @@ -127,11 +120,11 @@ NTSTATUS smbd_check_open_rights(struct connection_struct *conn, ****************************************************************************/ static NTSTATUS fd_open(struct connection_struct *conn, + const char *fname, files_struct *fsp, int flags, mode_t mode) { - struct smb_filename *smb_fname = fsp->fsp_name; NTSTATUS status = NT_STATUS_OK; #ifdef O_NOFOLLOW @@ -145,7 +138,7 @@ static NTSTATUS fd_open(struct connection_struct *conn, } #endif - fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode); + fsp->fh->fd = SMB_VFS_OPEN(conn,fname,fsp,flags,mode); if (fsp->fh->fd == -1) { status = map_nt_error_from_unix(errno); if (errno == EMFILE) { @@ -163,7 +156,7 @@ static NTSTATUS fd_open(struct connection_struct *conn, } DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n", - smb_fname_str_dbg(smb_fname), flags, (int)mode, fsp->fh->fd, + fname, flags, (int)mode, fsp->fh->fd, (fsp->fh->fd == -1) ? strerror(errno) : "" )); return status; @@ -201,41 +194,31 @@ void change_file_owner_to_parent(connection_struct *conn, const char *inherit_from_dir, files_struct *fsp) { - struct smb_filename *smb_fname_parent = NULL; - NTSTATUS status; + SMB_STRUCT_STAT parent_st; int ret; - status = create_synthetic_smb_fname(talloc_tos(), inherit_from_dir, - NULL, NULL, &smb_fname_parent); - if (!NT_STATUS_IS_OK(status)) { - return; - } - - ret = SMB_VFS_STAT(conn, smb_fname_parent); + ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st); if (ret == -1) { DEBUG(0,("change_file_owner_to_parent: failed to stat parent " "directory %s. Error was %s\n", - smb_fname_str_dbg(smb_fname_parent), - strerror(errno))); + inherit_from_dir, strerror(errno) )); return; } become_root(); - ret = SMB_VFS_FCHOWN(fsp, smb_fname_parent->st.st_ex_uid, (gid_t)-1); + ret = SMB_VFS_FCHOWN(fsp, parent_st.st_uid, (gid_t)-1); unbecome_root(); if (ret == -1) { DEBUG(0,("change_file_owner_to_parent: failed to fchown " "file %s to parent directory uid %u. Error " - "was %s\n", fsp_str_dbg(fsp), - (unsigned int)smb_fname_parent->st.st_ex_uid, + "was %s\n", fsp->fsp_name, + (unsigned int)parent_st.st_uid, strerror(errno) )); } DEBUG(10,("change_file_owner_to_parent: changed new file %s to " - "parent directory uid %u.\n", fsp_str_dbg(fsp), - (unsigned int)smb_fname_parent->st.st_ex_uid)); - - TALLOC_FREE(smb_fname_parent); + "parent directory uid %u.\n", fsp->fsp_name, + (unsigned int)parent_st.st_uid )); } NTSTATUS change_dir_owner_to_parent(connection_struct *conn, @@ -243,27 +226,20 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) { - struct smb_filename *smb_fname_parent = NULL; - struct smb_filename *smb_fname_cwd = NULL; char *saved_dir = NULL; + SMB_STRUCT_STAT sbuf; + SMB_STRUCT_STAT parent_st; TALLOC_CTX *ctx = talloc_tos(); NTSTATUS status = NT_STATUS_OK; int ret; - status = create_synthetic_smb_fname(ctx, inherit_from_dir, NULL, NULL, - &smb_fname_parent); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - ret = SMB_VFS_STAT(conn, smb_fname_parent); + ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st); if (ret == -1) { status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to stat parent " "directory %s. Error was %s\n", - smb_fname_str_dbg(smb_fname_parent), - strerror(errno))); - goto out; + inherit_from_dir, strerror(errno) )); + return status; } /* We've already done an lstat into psbuf, and we know it's a @@ -279,7 +255,7 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, DEBUG(0,("change_dir_owner_to_parent: failed to get " "current working directory. Error was %s\n", strerror(errno))); - goto out; + return status; } /* Chdir into the new path. */ @@ -288,58 +264,47 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, DEBUG(0,("change_dir_owner_to_parent: failed to change " "current working directory to %s. Error " "was %s\n", fname, strerror(errno) )); - goto chdir; - } - - status = create_synthetic_smb_fname(ctx, ".", NULL, NULL, - &smb_fname_cwd); - if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } - ret = SMB_VFS_STAT(conn, smb_fname_cwd); - if (ret == -1) { + if (SMB_VFS_STAT(conn,".",&sbuf) == -1) { status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to stat " "directory '.' (%s) Error was %s\n", fname, strerror(errno))); - goto chdir; + goto out; } /* Ensure we're pointing at the same place. */ - if (smb_fname_cwd->st.st_ex_dev != psbuf->st_ex_dev || - smb_fname_cwd->st.st_ex_ino != psbuf->st_ex_ino || - smb_fname_cwd->st.st_ex_mode != psbuf->st_ex_mode ) { + if (sbuf.st_dev != psbuf->st_dev || + sbuf.st_ino != psbuf->st_ino || + sbuf.st_mode != psbuf->st_mode ) { DEBUG(0,("change_dir_owner_to_parent: " "device/inode/mode on directory %s changed. " "Refusing to chown !\n", fname )); status = NT_STATUS_ACCESS_DENIED; - goto chdir; + goto out; } become_root(); - ret = SMB_VFS_CHOWN(conn, ".", smb_fname_parent->st.st_ex_uid, - (gid_t)-1); + ret = SMB_VFS_CHOWN(conn, ".", parent_st.st_uid, (gid_t)-1); unbecome_root(); if (ret == -1) { status = map_nt_error_from_unix(errno); DEBUG(10,("change_dir_owner_to_parent: failed to chown " "directory %s to parent directory uid %u. " "Error was %s\n", fname, - (unsigned int)smb_fname_parent->st.st_ex_uid, - strerror(errno) )); - goto chdir; + (unsigned int)parent_st.st_uid, strerror(errno) )); + goto out; } DEBUG(10,("change_dir_owner_to_parent: changed ownership of new " "directory %s to parent directory uid %u.\n", - fname, (unsigned int)smb_fname_parent->st.st_ex_uid )); + fname, (unsigned int)parent_st.st_uid )); - chdir: - vfs_ChDir(conn,saved_dir); out: - TALLOC_FREE(smb_fname_parent); - TALLOC_FREE(smb_fname_cwd); + + vfs_ChDir(conn,saved_dir); return status; } @@ -351,16 +316,18 @@ static NTSTATUS open_file(files_struct *fsp, connection_struct *conn, struct smb_request *req, const char *parent_dir, + const char *name, + const char *path, + SMB_STRUCT_STAT *psbuf, int flags, mode_t unx_mode, uint32 access_mask, /* client requested access mask. */ uint32 open_access_mask) /* what we're actually using in the open. */ { - struct smb_filename *smb_fname = fsp->fsp_name; NTSTATUS status = NT_STATUS_OK; int accmode = (flags & O_ACCMODE); int local_flags = flags; - bool file_existed = VALID_STAT(fsp->fsp_name->st); + bool file_existed = VALID_STAT(*psbuf); fsp->fh->fd = -1; errno = EPERM; @@ -380,8 +347,7 @@ static NTSTATUS open_file(files_struct *fsp, if (!CAN_WRITE(conn)) { /* It's a read-only share - fail if we wanted to write. */ if(accmode != O_RDONLY || (flags & O_TRUNC) || (flags & O_APPEND)) { - DEBUG(3,("Permission denied opening %s\n", - smb_fname_str_dbg(smb_fname))); + DEBUG(3,("Permission denied opening %s\n", path)); return NT_STATUS_ACCESS_DENIED; } else if(flags & O_CREAT) { /* We don't want to write - but we must make sure that @@ -407,7 +373,7 @@ static NTSTATUS open_file(files_struct *fsp, if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) { DEBUG(10,("open_file: truncate requested on read-only open " - "for file %s\n", smb_fname_str_dbg(smb_fname))); + "for file %s\n", path)); local_flags = (flags & ~O_ACCMODE)|O_RDWR; } @@ -430,7 +396,7 @@ static NTSTATUS open_file(files_struct *fsp, * open flags. JRA. */ - if (file_existed && S_ISFIFO(smb_fname->st.st_ex_mode)) { + if (file_existed && S_ISFIFO(psbuf->st_mode)) { local_flags |= O_NONBLOCK; } #endif @@ -441,9 +407,9 @@ static NTSTATUS open_file(files_struct *fsp, * wildcard characters are allowed in stream names * only test the basefilename */ - wild = fsp->base_fsp->fsp_name->base_name; + wild = fsp->base_fsp->fsp_name; } else { - wild = smb_fname->base_name; + wild = path; } if ((local_flags & O_CREAT) && !file_existed && ms_has_wild(wild)) { @@ -451,11 +417,11 @@ static NTSTATUS open_file(files_struct *fsp, } /* Actually do the open */ - status = fd_open(conn, fsp, local_flags, unx_mode); + status = fd_open(conn, path, fsp, local_flags, unx_mode); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " - "(flags=%d)\n", smb_fname_str_dbg(smb_fname), - nt_errstr(status),local_flags,flags)); + "(flags=%d)\n", + path,nt_errstr(status),local_flags,flags)); return status; } @@ -463,9 +429,8 @@ static NTSTATUS open_file(files_struct *fsp, /* Inherit the ACL if required */ if (lp_inherit_perms(SNUM(conn))) { - inherit_access_posix_acl(conn, parent_dir, - smb_fname->base_name, - unx_mode); + inherit_access_posix_acl(conn, parent_dir, path, + unx_mode); } /* Change the owner if required. */ @@ -475,8 +440,7 @@ static NTSTATUS open_file(files_struct *fsp, } notify_fname(conn, NOTIFY_ACTION_ADDED, - FILE_NOTIFY_CHANGE_FILE_NAME, - smb_fname->base_name); + FILE_NOTIFY_CHANGE_FILE_NAME, path); } } else { @@ -484,8 +448,8 @@ static NTSTATUS open_file(files_struct *fsp, if (file_existed) { uint32_t access_granted = 0; - status = smbd_check_open_rights(conn, - smb_fname, + status = check_open_rights(conn, + path, access_mask, &access_granted); if (!NT_STATUS_IS_OK(status)) { @@ -503,19 +467,14 @@ static NTSTATUS open_file(files_struct *fsp, lp_map_system(SNUM(conn)))) { access_granted &= ~FILE_WRITE_ATTRIBUTES; - DEBUG(10,("open_file: " - "overrode " - "FILE_WRITE_" - "ATTRIBUTES " - "on file %s\n", - smb_fname_str_dbg( - smb_fname))); + DEBUG(10,("open_file: overrode FILE_WRITE_ATTRIBUTES " + "on file %s\n", + path )); } if ((access_mask & DELETE_ACCESS) && - (access_granted & DELETE_ACCESS) && - can_delete_file_in_directory(conn, - smb_fname)) { + (access_granted & DELETE_ACCESS) && + can_delete_file_in_directory(conn, path)) { /* Were we trying to do a stat open * for delete and didn't get DELETE * access (only) ? Check if the @@ -526,38 +485,30 @@ static NTSTATUS open_file(files_struct *fsp, access_granted &= ~DELETE_ACCESS; - DEBUG(10,("open_file: " - "overrode " - "DELETE_ACCESS on " - "file %s\n", - smb_fname_str_dbg( - smb_fname))); + DEBUG(10,("open_file: overrode DELETE_ACCESS " + "on file %s\n", + path )); } if (access_granted != 0) { - DEBUG(10,("open_file: Access " - "denied on file " - "%s\n", - smb_fname_str_dbg( - smb_fname))); + DEBUG(10, ("open_file: Access denied on " + "file %s\n", + path)); return status; } } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) && - fsp->posix_open && - S_ISLNK(smb_fname->st.st_ex_mode)) { + fsp->posix_open && + S_ISLNK(psbuf->st_mode)) { /* This is a POSIX stat open for delete * or rename on a symlink that points * nowhere. Allow. */ - DEBUG(10,("open_file: allowing POSIX " - "open on bad symlink %s\n", - smb_fname_str_dbg( - smb_fname))); + DEBUG(10, ("open_file: allowing POSIX open " + "on bad symlink %s\n", + path )); } else { - DEBUG(10,("open_file: " - "smbd_check_open_rights on file " - "%s returned %s\n", - smb_fname_str_dbg(smb_fname), - nt_errstr(status) )); + DEBUG(10, ("open_file: check_open_rights " + "on file %s returned %s\n", + path, nt_errstr(status) )); return status; } } @@ -568,15 +519,13 @@ static NTSTATUS open_file(files_struct *fsp, int ret; if (fsp->fh->fd == -1) { - ret = SMB_VFS_STAT(conn, smb_fname); + ret = SMB_VFS_STAT(conn, path, psbuf); } else { - ret = SMB_VFS_FSTAT(fsp, &smb_fname->st); + ret = SMB_VFS_FSTAT(fsp, psbuf); /* If we have an fd, this stat should succeed. */ if (ret == -1) { DEBUG(0,("Error doing fstat on open file %s " - "(%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno) )); + "(%s)\n", path,strerror(errno) )); } } @@ -594,14 +543,14 @@ static NTSTATUS open_file(files_struct *fsp, * so catch a directory open and return an EISDIR. JRA. */ - if(S_ISDIR(smb_fname->st.st_ex_mode)) { + if(S_ISDIR(psbuf->st_mode)) { fd_close(fsp); errno = EISDIR; return NT_STATUS_FILE_IS_A_DIRECTORY; } - fsp->mode = smb_fname->st.st_ex_mode; - fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st); + fsp->mode = psbuf->st_mode; + fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); fsp->vuid = req ? req->vuid : UID_FIELD_INVALID; fsp->file_pid = req ? req->smbpid : 0; fsp->can_lock = True; @@ -617,16 +566,16 @@ static NTSTATUS open_file(files_struct *fsp, fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = False; if (conn->aio_write_behind_list && - is_in_path(smb_fname->base_name, conn->aio_write_behind_list, - conn->case_sensitive)) { + is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) { fsp->aio_write_behind = True; } + string_set(&fsp->fsp_name, path); fsp->wcp = NULL; /* Write cache pointer. */ DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", conn->server_info->unix_name, - smb_fname_str_dbg(smb_fname), + fsp->fsp_name, BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write), conn->num_files_open)); @@ -793,8 +742,7 @@ static void validate_my_share_entries(int num, str = talloc_asprintf(talloc_tos(), "validate_my_share_entries: " "file %s, oplock_type = 0x%x, op_type = 0x%x\n", - fsp->fsp_name->base_name, - (unsigned int)fsp->oplock_type, + fsp->fsp_name, (unsigned int)fsp->oplock_type, (unsigned int)share_entry->op_type ); smb_panic(str); } @@ -817,6 +765,7 @@ bool is_stat_open(uint32 access_mask) ****************************************************************************/ static NTSTATUS open_mode_check(connection_struct *conn, + const char *fname, struct share_mode_lock *lck, uint32 access_mask, uint32 share_access, @@ -1028,7 +977,7 @@ static bool delay_for_oplocks(struct share_mode_lock *lck, } DEBUG(10,("delay_for_oplocks: oplock type 0x%x on file %s\n", - fsp->oplock_type, fsp_str_dbg(fsp))); + fsp->oplock_type, fsp->fsp_name)); /* No delay. */ return false; @@ -1084,6 +1033,15 @@ static void defer_open(struct share_mode_lock *lck, exit_server("push_deferred_smb_message failed"); } add_deferred_open(lck, req->mid, request_time, state->id); + + /* + * Push the MID of this packet on the signing queue. + * We only do this once, the first time we push the packet + * onto the deferred open queue, as this has a side effect + * of incrementing the response sequence number. + */ + + srv_defer_sign_response(req->mid); } @@ -1092,6 +1050,7 @@ static void defer_open(struct share_mode_lock *lck, ****************************************************************************/ bool open_match_attributes(connection_struct *conn, + const char *path, uint32 old_dos_attr, uint32 new_dos_attr, mode_t existing_unx_mode, @@ -1110,9 +1069,10 @@ bool open_match_attributes(connection_struct *conn, *returned_unx_mode = (mode_t)0; } - DEBUG(10,("open_match_attributes: old_dos_attr = 0x%x, " + DEBUG(10,("open_match_attributes: file %s old_dos_attr = 0x%x, " "existing_unx_mode = 0%o, new_dos_attr = 0x%x " "returned_unx_mode = 0%o\n", + path, (unsigned int)old_dos_attr, (unsigned int)existing_unx_mode, (unsigned int)new_dos_attr, @@ -1142,7 +1102,7 @@ bool open_match_attributes(connection_struct *conn, NTSTATUS fcb_or_dos_open(struct smb_request *req, connection_struct *conn, files_struct *fsp_to_dup_into, - const struct smb_filename *smb_fname, + const char *fname, struct file_id id, uint16 file_pid, uint16 vuid, @@ -1153,14 +1113,14 @@ NTSTATUS fcb_or_dos_open(struct smb_request *req, files_struct *fsp; DEBUG(5,("fcb_or_dos_open: attempting old open semantics for " - "file %s.\n", smb_fname_str_dbg(smb_fname))); + "file %s.\n", fname )); for(fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) { DEBUG(10,("fcb_or_dos_open: checking file %s, fd = %d, " "vuid = %u, file_pid = %u, private_options = 0x%x " - "access_mask = 0x%x\n", fsp_str_dbg(fsp), + "access_mask = 0x%x\n", fsp->fsp_name, fsp->fh->fd, (unsigned int)fsp->vuid, (unsigned int)fsp->file_pid, (unsigned int)fsp->fh->private_options, @@ -1172,9 +1132,7 @@ NTSTATUS fcb_or_dos_open(struct smb_request *req, (fsp->fh->private_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) && (fsp->access_mask & FILE_WRITE_DATA) && - strequal(fsp->fsp_name->base_name, smb_fname->base_name) && - strequal(fsp->fsp_name->stream_name, - smb_fname->stream_name)) { + strequal(fsp->fsp_name, fname)) { DEBUG(10,("fcb_or_dos_open: file match\n")); break; } @@ -1185,23 +1143,24 @@ NTSTATUS fcb_or_dos_open(struct smb_request *req, } /* quite an insane set of semantics ... */ - if (is_executable(smb_fname->base_name) && + if (is_executable(fname) && (fsp->fh->private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) { DEBUG(10,("fcb_or_dos_open: file fail due to is_executable.\n")); return NT_STATUS_INVALID_PARAMETER; } /* We need to duplicate this fsp. */ - return dup_file_fsp(req, fsp, access_mask, share_access, - create_options, fsp_to_dup_into); + dup_file_fsp(req, fsp, access_mask, share_access, + create_options, fsp_to_dup_into); + + return NT_STATUS_OK; } /**************************************************************************** Open a file with a share mode - old openX method - map into NTCreate. ****************************************************************************/ -bool map_open_params_to_ntcreate(const struct smb_filename *smb_fname, - int deny_mode, int open_func, +bool map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func, uint32 *paccess_mask, uint32 *pshare_mode, uint32 *pcreate_disposition, @@ -1214,8 +1173,7 @@ bool map_open_params_to_ntcreate(const struct smb_filename *smb_fname, DEBUG(10,("map_open_params_to_ntcreate: fname = %s, deny_mode = 0x%x, " "open_func = 0x%x\n", - smb_fname_str_dbg(smb_fname), (unsigned int)deny_mode, - (unsigned int)open_func )); + fname, (unsigned int)deny_mode, (unsigned int)open_func )); /* Create the NT compatible access_mask. */ switch (GET_OPENX_MODE(deny_mode)) { @@ -1289,7 +1247,7 @@ bool map_open_params_to_ntcreate(const struct smb_filename *smb_fname, case DENY_DOS: create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_DOS; - if (is_executable(smb_fname->base_name)) { + if (is_executable(fname)) { share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE; } else { if (GET_OPENX_MODE(deny_mode) == DOS_OPEN_RDONLY) { @@ -1314,7 +1272,7 @@ bool map_open_params_to_ntcreate(const struct smb_filename *smb_fname, DEBUG(10,("map_open_params_to_ntcreate: file %s, access_mask = 0x%x, " "share_mode = 0x%x, create_disposition = 0x%x, " "create_options = 0x%x\n", - smb_fname_str_dbg(smb_fname), + fname, (unsigned int)access_mask, (unsigned int)share_mode, (unsigned int)create_disposition, @@ -1379,7 +1337,7 @@ static void schedule_defer_open(struct share_mode_lock *lck, ****************************************************************************/ static NTSTATUS calculate_access_mask(connection_struct *conn, - const struct smb_filename *smb_fname, + const char *fname, bool file_existed, uint32_t access_mask, uint32_t *access_mask_out) @@ -1399,7 +1357,7 @@ static NTSTATUS calculate_access_mask(connection_struct *conn, struct security_descriptor *sd; uint32_t access_granted = 0; - status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name, + status = SMB_VFS_GET_NT_ACL(conn, fname, (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION),&sd); @@ -1407,7 +1365,7 @@ static NTSTATUS calculate_access_mask(connection_struct *conn, if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("calculate_access_mask: Could not get acl " "on file %s: %s\n", - smb_fname_str_dbg(smb_fname), + fname, nt_errstr(status))); return NT_STATUS_ACCESS_DENIED; } @@ -1422,7 +1380,7 @@ static NTSTATUS calculate_access_mask(connection_struct *conn, if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("calculate_access_mask: Access denied on " "file %s: when calculating maximum access\n", - smb_fname_str_dbg(smb_fname))); + fname)); return NT_STATUS_ACCESS_DENIED; } @@ -1442,6 +1400,8 @@ static NTSTATUS calculate_access_mask(connection_struct *conn, static NTSTATUS open_file_ntcreate(connection_struct *conn, struct smb_request *req, + const char *fname, + SMB_STRUCT_STAT *psbuf, uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */ uint32 share_access, /* share constants (FILE_SHARE_READ etc) */ uint32 create_disposition, /* FILE_OPEN_IF etc. */ @@ -1452,10 +1412,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, int *pinfo, files_struct *fsp) { - struct smb_filename *smb_fname = fsp->fsp_name; int flags=0; int flags2=0; - bool file_existed = VALID_STAT(smb_fname->st); + bool file_existed = VALID_STAT(*psbuf); bool def_acl = False; bool posix_open = False; bool new_file_created = False; @@ -1471,7 +1430,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, struct share_mode_lock *lck = NULL; uint32 open_access_mask = access_mask; NTSTATUS status; + int ret_flock; char *parent_dir; + const char *newname; ZERO_STRUCT(id); @@ -1485,21 +1446,12 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, *pinfo = FILE_WAS_CREATED; } - DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", - smb_fname_str_dbg(smb_fname))); + DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname)); - if (!req) { - DEBUG(0,("open_file_ntcreate: printer open without " - "an SMB request!\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - return print_fsp_open(req, conn, smb_fname->base_name, - req->vuid, fsp); + return print_fsp_open(req, conn, fname, req->vuid, fsp, psbuf); } - if (!parent_dirname(talloc_tos(), smb_fname->base_name, &parent_dir, - NULL)) { + if (!parent_dirname(talloc_tos(), fname, &parent_dir, &newname)) { return NT_STATUS_NO_MEMORY; } @@ -1510,17 +1462,17 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } else { /* We add aARCH to this as this mode is only used if the file is * created new. */ - unx_mode = unix_mode(conn, new_dos_attributes | aARCH, - smb_fname, parent_dir); + unx_mode = unix_mode(conn, new_dos_attributes | aARCH, fname, + parent_dir); } DEBUG(10, ("open_file_ntcreate: fname=%s, dos_attrs=0x%x " "access_mask=0x%x share_access=0x%x " "create_disposition = 0x%x create_options=0x%x " "unix mode=0%o oplock_request=%d\n", - smb_fname_str_dbg(smb_fname), new_dos_attributes, - access_mask, share_access, create_disposition, - create_options, (unsigned int)unx_mode, oplock_request)); + fname, new_dos_attributes, access_mask, share_access, + create_disposition, create_options, (unsigned int)unx_mode, + oplock_request)); if ((req == NULL) && ((oplock_request & INTERNAL_OPEN_ONLY) == 0)) { DEBUG(0, ("No smb request but not an internal only open!\n")); @@ -1556,7 +1508,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, remove_deferred_open_smb_message(req->mid); } - status = check_name(conn, smb_fname->base_name); + status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -1564,19 +1516,19 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (!posix_open) { new_dos_attributes &= SAMBA_ATTRIBUTES_MASK; if (file_existed) { - existing_dos_attributes = dos_mode(conn, smb_fname); + existing_dos_attributes = dos_mode(conn, fname, psbuf); } } /* ignore any oplock requests if oplocks are disabled */ if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break || - IS_VETO_OPLOCK_PATH(conn, smb_fname->base_name)) { + IS_VETO_OPLOCK_PATH(conn, fname)) { /* Mask off everything except the private Samba bits. */ oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK; } /* this is for OS/2 long file names - say we don't support them */ - if (!lp_posix_pathnames() && strstr(smb_fname->base_name,".+,;=[].")) { + if (!lp_posix_pathnames() && strstr(fname,".+,;=[].")) { /* OS/2 Workplace shell fix may be main code stream in a later * release. */ DEBUG(5,("open_file_ntcreate: OS/2 long filenames are not " @@ -1613,8 +1565,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (!file_existed) { DEBUG(5,("open_file_ntcreate: FILE_OPEN " "requested for file %s and file " - "doesn't exist.\n", - smb_fname_str_dbg(smb_fname))); + "doesn't exist.\n", fname )); errno = ENOENT; return NT_STATUS_OBJECT_NAME_NOT_FOUND; } @@ -1626,8 +1577,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (!file_existed) { DEBUG(5,("open_file_ntcreate: FILE_OVERWRITE " "requested for file %s and file " - "doesn't exist.\n", - smb_fname_str_dbg(smb_fname) )); + "doesn't exist.\n", fname )); errno = ENOENT; return NT_STATUS_OBJECT_NAME_NOT_FOUND; } @@ -1641,9 +1591,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (file_existed) { DEBUG(5,("open_file_ntcreate: FILE_CREATE " "requested for file %s and file " - "already exists.\n", - smb_fname_str_dbg(smb_fname))); - if (S_ISDIR(smb_fname->st.st_ex_mode)) { + "already exists.\n", fname )); + if (S_ISDIR(psbuf->st_mode)) { errno = EISDIR; } else { errno = EEXIST; @@ -1668,29 +1617,29 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (!posix_open && file_existed && ((create_disposition == FILE_OVERWRITE) || (create_disposition == FILE_OVERWRITE_IF))) { - if (!open_match_attributes(conn, existing_dos_attributes, - new_dos_attributes, - smb_fname->st.st_ex_mode, + if (!open_match_attributes(conn, fname, + existing_dos_attributes, + new_dos_attributes, psbuf->st_mode, unx_mode, &new_unx_mode)) { DEBUG(5,("open_file_ntcreate: attributes missmatch " "for file %s (%x %x) (0%o, 0%o)\n", - smb_fname_str_dbg(smb_fname), - existing_dos_attributes, + fname, existing_dos_attributes, new_dos_attributes, - (unsigned int)smb_fname->st.st_ex_mode, + (unsigned int)psbuf->st_mode, (unsigned int)unx_mode )); errno = EACCES; return NT_STATUS_ACCESS_DENIED; } } - status = calculate_access_mask(conn, smb_fname, file_existed, + status = calculate_access_mask(conn, fname, file_existed, access_mask, &access_mask); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("open_file_ntcreate: calculate_access_mask " "on file %s returned %s\n", - smb_fname_str_dbg(smb_fname), nt_errstr(status))); + fname, + nt_errstr(status))); return status; } @@ -1701,8 +1650,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } DEBUG(10, ("open_file_ntcreate: fname=%s, after mapping " - "access_mask=0x%x\n", smb_fname_str_dbg(smb_fname), - access_mask)); + "access_mask=0x%x\n", fname, access_mask )); /* * Note that we ignore the append flag as append does not @@ -1755,13 +1703,12 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_attributes))) { DEBUG(5,("open_file_ntcreate: write access requested for " "file %s on read only %s\n", - smb_fname_str_dbg(smb_fname), - !CAN_WRITE(conn) ? "share" : "file" )); + fname, !CAN_WRITE(conn) ? "share" : "file" )); errno = EACCES; return NT_STATUS_ACCESS_DENIED; } - fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st); + fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); fsp->share_access = share_access; fsp->fh->private_options = create_options; fsp->access_mask = open_access_mask; /* We change this to the @@ -1777,12 +1724,12 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } if (file_existed) { - struct timespec old_write_time = smb_fname->st.st_ex_mtime; - id = vfs_file_id_from_sbuf(conn, &smb_fname->st); + struct timespec old_write_time = get_mtimespec(psbuf); + id = vfs_file_id_from_sbuf(conn, psbuf); lck = get_share_mode_lock(talloc_tos(), id, conn->connectpath, - smb_fname, &old_write_time); + fname, &old_write_time); if (lck == NULL) { DEBUG(0, ("Could not get share mode lock\n")); @@ -1800,7 +1747,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, /* Use the client requested access mask here, not the one we * open with. */ - status = open_mode_check(conn, lck, access_mask, share_access, + status = open_mode_check(conn, fname, lck, + access_mask, share_access, create_options, &file_existed); if (NT_STATUS_IS_OK(status)) { @@ -1846,7 +1794,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, status = fcb_or_dos_open(req, conn, fsp, - smb_fname, + fname, id, req->smbpid, req->vuid, @@ -1881,10 +1829,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, can_access_mask = FILE_READ_DATA; } - if (((can_access_mask & FILE_WRITE_DATA) && - !CAN_WRITE(conn)) || - !can_access_file_data(conn, smb_fname, - can_access_mask)) { + if (((can_access_mask & FILE_WRITE_DATA) && !CAN_WRITE(conn)) || + !can_access_file_data(conn,fname,psbuf,can_access_mask)) { can_access = False; } @@ -1970,7 +1916,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, * open_file strips any O_TRUNC flags itself. */ - fsp_open = open_file(fsp, conn, req, parent_dir, + fsp_open = open_file(fsp, conn, req, parent_dir, newname, fname, psbuf, flags|flags2, unx_mode, access_mask, open_access_mask); @@ -1982,7 +1928,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } if (!file_existed) { - struct timespec old_write_time = smb_fname->st.st_ex_mtime; + struct timespec old_write_time = get_mtimespec(psbuf); /* * Deal with the race condition where two smbd's detect the * file doesn't exist and do the create at the same time. One @@ -2002,12 +1948,11 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, lck = get_share_mode_lock(talloc_tos(), id, conn->connectpath, - smb_fname, &old_write_time); + fname, &old_write_time); if (lck == NULL) { DEBUG(0, ("open_file_ntcreate: Could not get share " - "mode lock for %s\n", - smb_fname_str_dbg(smb_fname))); + "mode lock for %s\n", fname)); fd_close(fsp); return NT_STATUS_SHARING_VIOLATION; } @@ -2022,7 +1967,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, return NT_STATUS_SHARING_VIOLATION; } - status = open_mode_check(conn, lck, access_mask, share_access, + status = open_mode_check(conn, fname, lck, + access_mask, share_access, create_options, &file_existed); if (NT_STATUS_IS_OK(status)) { @@ -2072,9 +2018,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, SMB_ASSERT(lck != NULL); /* Delete streams if create_disposition requires it */ - if (file_existed && clear_ads && - !is_ntfs_stream_smb_fname(smb_fname)) { - status = delete_all_streams(conn, smb_fname->base_name); + if (file_existed && clear_ads && !is_ntfs_stream_name(fname)) { + status = delete_all_streams(conn, fname); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(lck); fd_close(fsp); @@ -2091,8 +2036,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, note that GPFS supports it as well - jmcd */ if (fsp->fh->fd != -1) { - int ret_flock; - ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, share_access, access_mask); + ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, share_access); if(ret_flock == -1 ){ TALLOC_FREE(lck); @@ -2118,7 +2062,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, * struct.. */ if ((SMB_VFS_FTRUNCATE(fsp, 0) == -1) || - (SMB_VFS_FSTAT(fsp, &smb_fname->st)==-1)) { + (SMB_VFS_FSTAT(fsp, psbuf)==-1)) { status = map_nt_error_from_unix(errno); TALLOC_FREE(lck); fd_close(fsp); @@ -2173,7 +2117,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, /* Handle strange delete on close create semantics. */ if (create_options & FILE_DELETE_ON_CLOSE) { - status = can_set_delete_on_close(fsp, new_dos_attributes); + status = can_set_delete_on_close(fsp, True, new_dos_attributes); if (!NT_STATUS_IS_OK(status)) { /* Remember to delete the mode we just added. */ @@ -2192,10 +2136,14 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (lp_map_archive(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) { if (!posix_open) { - if (file_set_dosmode(conn, smb_fname, + SMB_STRUCT_STAT tmp_sbuf; + SET_STAT_INVALID(tmp_sbuf); + if (file_set_dosmode( + conn, fname, new_dos_attributes | aARCH, - parent_dir, true) == 0) { - unx_mode = smb_fname->st.st_ex_mode; + &tmp_sbuf, parent_dir, + true) == 0) { + unx_mode = tmp_sbuf.st_mode; } } } @@ -2232,8 +2180,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } else { DEBUG(5, ("open_file_ntcreate: reset " "attributes of file %s to 0%o\n", - smb_fname_str_dbg(smb_fname), - (unsigned int)new_unx_mode)); + fname, (unsigned int)new_unx_mode)); ret = 0; /* Don't do the fchmod below. */ } } @@ -2242,8 +2189,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, (SMB_VFS_FCHMOD(fsp, new_unx_mode) == -1)) DEBUG(5, ("open_file_ntcreate: failed to reset " "attributes of file %s to 0%o\n", - smb_fname_str_dbg(smb_fname), - (unsigned int)new_unx_mode)); + fname, (unsigned int)new_unx_mode)); } /* If this is a successful open, we must remove any deferred open @@ -2262,13 +2208,13 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, ****************************************************************************/ NTSTATUS open_file_fchmod(struct smb_request *req, connection_struct *conn, - struct smb_filename *smb_fname, - files_struct **result) + const char *fname, + SMB_STRUCT_STAT *psbuf, files_struct **result) { files_struct *fsp = NULL; NTSTATUS status; - if (!VALID_STAT(smb_fname->st)) { + if (!VALID_STAT(*psbuf)) { return NT_STATUS_INVALID_PARAMETER; } @@ -2277,11 +2223,12 @@ NTSTATUS open_file_fchmod(struct smb_request *req, connection_struct *conn, return status; } - status = SMB_VFS_CREATE_FILE( + status = SMB_VFS_CREATE_FILE( conn, /* conn */ NULL, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + 0, /* create_file_flags */ FILE_WRITE_DATA, /* access_mask */ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ FILE_SHARE_DELETE), @@ -2293,7 +2240,8 @@ NTSTATUS open_file_fchmod(struct smb_request *req, connection_struct *conn, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + psbuf); /* psbuf */ /* * This is not a user visible file open. @@ -2321,11 +2269,13 @@ NTSTATUS close_file_fchmod(struct smb_request *req, files_struct *fsp) } static NTSTATUS mkdir_internal(connection_struct *conn, - struct smb_filename *smb_dname, - uint32 file_attributes) + const char *name, + uint32 file_attributes, + SMB_STRUCT_STAT *psbuf) { mode_t mode; char *parent_dir; + const char *dirname; NTSTATUS status; bool posix_open = false; @@ -2335,13 +2285,12 @@ static NTSTATUS mkdir_internal(connection_struct *conn, return NT_STATUS_ACCESS_DENIED; } - status = check_name(conn, smb_dname->base_name); + status = check_name(conn, name); if (!NT_STATUS_IS_OK(status)) { return status; } - if (!parent_dirname(talloc_tos(), smb_dname->base_name, &parent_dir, - NULL)) { + if (!parent_dirname(talloc_tos(), name, &parent_dir, &dirname)) { return NT_STATUS_NO_MEMORY; } @@ -2349,65 +2298,61 @@ static NTSTATUS mkdir_internal(connection_struct *conn, posix_open = true; mode = (mode_t)(file_attributes & ~FILE_FLAG_POSIX_SEMANTICS); } else { - mode = unix_mode(conn, aDIR, smb_dname, parent_dir); + mode = unix_mode(conn, aDIR, name, parent_dir); } - if (SMB_VFS_MKDIR(conn, smb_dname->base_name, mode) != 0) { + if (SMB_VFS_MKDIR(conn, name, mode) != 0) { return map_nt_error_from_unix(errno); } /* Ensure we're checking for a symlink here.... */ /* We don't want to get caught by a symlink racer. */ - if (SMB_VFS_LSTAT(conn, smb_dname) == -1) { + if (SMB_VFS_LSTAT(conn, name, psbuf) == -1) { DEBUG(2, ("Could not stat directory '%s' just created: %s\n", - smb_fname_str_dbg(smb_dname), strerror(errno))); + name, strerror(errno))); return map_nt_error_from_unix(errno); } - if (!S_ISDIR(smb_dname->st.st_ex_mode)) { + if (!S_ISDIR(psbuf->st_mode)) { DEBUG(0, ("Directory just '%s' created is not a directory\n", - smb_fname_str_dbg(smb_dname))); + name)); return NT_STATUS_ACCESS_DENIED; } if (lp_store_dos_attributes(SNUM(conn))) { if (!posix_open) { - file_set_dosmode(conn, smb_dname, - file_attributes | aDIR, - parent_dir, true); + file_set_dosmode(conn, name, + file_attributes | aDIR, NULL, + parent_dir, + true); } } if (lp_inherit_perms(SNUM(conn))) { - inherit_access_posix_acl(conn, parent_dir, - smb_dname->base_name, mode); + inherit_access_posix_acl(conn, parent_dir, name, mode); } - if (!posix_open) { + if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) { /* * Check if high bits should have been set, * then (if bits are missing): add them. * Consider bits automagically set by UNIX, i.e. SGID bit from parent * dir. */ - if ((mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) && - (mode & ~smb_dname->st.st_ex_mode)) { - SMB_VFS_CHMOD(conn, smb_dname->base_name, - (smb_dname->st.st_ex_mode | - (mode & ~smb_dname->st.st_ex_mode))); + if (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) && (mode & ~psbuf->st_mode)) { + SMB_VFS_CHMOD(conn, name, + psbuf->st_mode | (mode & ~psbuf->st_mode)); } } /* Change the owner if required. */ if (lp_inherit_owner(SNUM(conn))) { - change_dir_owner_to_parent(conn, parent_dir, - smb_dname->base_name, - &smb_dname->st); + change_dir_owner_to_parent(conn, parent_dir, name, psbuf); } notify_fname(conn, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME, - smb_dname->base_name); + name); return NT_STATUS_OK; } @@ -2418,7 +2363,8 @@ static NTSTATUS mkdir_internal(connection_struct *conn, static NTSTATUS open_directory(connection_struct *conn, struct smb_request *req, - struct smb_filename *smb_dname, + const char *fname, + SMB_STRUCT_STAT *psbuf, uint32 access_mask, uint32 share_access, uint32 create_disposition, @@ -2428,18 +2374,16 @@ static NTSTATUS open_directory(connection_struct *conn, files_struct **result) { files_struct *fsp = NULL; - bool dir_existed = VALID_STAT(smb_dname->st) ? True : False; + bool dir_existed = VALID_STAT(*psbuf) ? True : False; struct share_mode_lock *lck = NULL; NTSTATUS status; struct timespec mtimespec; int info = 0; - SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname)); - DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, " "share_access = 0x%x create_options = 0x%x, " "create_disposition = 0x%x, file_attributes = 0x%x\n", - smb_fname_str_dbg(smb_dname), + fname, (unsigned int)access_mask, (unsigned int)share_access, (unsigned int)create_options, @@ -2448,18 +2392,18 @@ static NTSTATUS open_directory(connection_struct *conn, if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) && (conn->fs_capabilities & FILE_NAMED_STREAMS) && - is_ntfs_stream_smb_fname(smb_dname)) { - DEBUG(2, ("open_directory: %s is a stream name!\n", - smb_fname_str_dbg(smb_dname))); + is_ntfs_stream_name(fname)) { + DEBUG(2, ("open_directory: %s is a stream name!\n", fname)); return NT_STATUS_NOT_A_DIRECTORY; } - status = calculate_access_mask(conn, smb_dname, dir_existed, - access_mask, &access_mask); + status = calculate_access_mask(conn, fname, dir_existed, + access_mask, + &access_mask); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("open_directory: calculate_access_mask " "on file %s returned %s\n", - smb_fname_str_dbg(smb_dname), + fname, nt_errstr(status))); return status; } @@ -2468,7 +2412,7 @@ static NTSTATUS open_directory(connection_struct *conn, if (access_mask & SEC_FLAG_SYSTEM_SECURITY) { DEBUG(10, ("open_directory: open on %s " "failed - SEC_FLAG_SYSTEM_SECURITY denied.\n", - smb_fname_str_dbg(smb_dname))); + fname)); return NT_STATUS_PRIVILEGE_NOT_HELD; } @@ -2481,7 +2425,7 @@ static NTSTATUS open_directory(connection_struct *conn, * We want to follow symlinks here. */ - if (SMB_VFS_STAT(conn, smb_dname) != 0) { + if (SMB_VFS_STAT(conn, fname, psbuf) != 0) { return map_nt_error_from_unix(errno); } @@ -2492,13 +2436,14 @@ static NTSTATUS open_directory(connection_struct *conn, /* If directory exists error. If directory doesn't * exist create. */ - status = mkdir_internal(conn, smb_dname, - file_attributes); + status = mkdir_internal(conn, + fname, + file_attributes, + psbuf); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("open_directory: unable to create " - "%s. Error was %s\n", - smb_fname_str_dbg(smb_dname), + "%s. Error was %s\n", fname, nt_errstr(status))); return status; } @@ -2512,8 +2457,10 @@ static NTSTATUS open_directory(connection_struct *conn, * exist create. */ - status = mkdir_internal(conn, smb_dname, - file_attributes); + status = mkdir_internal(conn, + fname, + file_attributes, + psbuf); if (NT_STATUS_IS_OK(status)) { info = FILE_WAS_CREATED; @@ -2533,21 +2480,22 @@ static NTSTATUS open_directory(connection_struct *conn, default: DEBUG(5,("open_directory: invalid create_disposition " "0x%x for directory %s\n", - (unsigned int)create_disposition, - smb_fname_str_dbg(smb_dname))); + (unsigned int)create_disposition, fname)); return NT_STATUS_INVALID_PARAMETER; } - if(!S_ISDIR(smb_dname->st.st_ex_mode)) { + if(!S_ISDIR(psbuf->st_mode)) { DEBUG(5,("open_directory: %s is not a directory !\n", - smb_fname_str_dbg(smb_dname))); + fname )); return NT_STATUS_NOT_A_DIRECTORY; } if (info == FILE_WAS_OPENED) { uint32_t access_granted = 0; - status = smbd_check_open_rights(conn, smb_dname, access_mask, - &access_granted); + status = check_open_rights(conn, + fname, + access_mask, + &access_granted); /* Were we trying to do a directory open * for delete and didn't get DELETE @@ -2558,19 +2506,19 @@ static NTSTATUS open_directory(connection_struct *conn, * for details. */ if ((NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && - (access_mask & DELETE_ACCESS) && - (access_granted == DELETE_ACCESS) && - can_delete_file_in_directory(conn, smb_dname))) { + (access_mask & DELETE_ACCESS) && + (access_granted == DELETE_ACCESS) && + can_delete_file_in_directory(conn, fname))) { DEBUG(10,("open_directory: overrode ACCESS_DENIED " "on directory %s\n", - smb_fname_str_dbg(smb_dname))); + fname )); status = NT_STATUS_OK; } if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("open_directory: smbd_check_open_rights on " + DEBUG(10, ("open_directory: check_open_rights on " "file %s failed with %s\n", - smb_fname_str_dbg(smb_dname), + fname, nt_errstr(status))); return status; } @@ -2585,8 +2533,8 @@ static NTSTATUS open_directory(connection_struct *conn, * Setup the files_struct for it. */ - fsp->mode = smb_dname->st.st_ex_mode; - fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_dname->st); + fsp->mode = psbuf->st_mode; + fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); fsp->vuid = req ? req->vuid : UID_FIELD_INVALID; fsp->file_pid = req ? req->smbpid : 0; fsp->can_lock = False; @@ -2605,25 +2553,24 @@ static NTSTATUS open_directory(connection_struct *conn, fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = True; fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False; - status = fsp_set_smb_fname(fsp, smb_dname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - mtimespec = smb_dname->st.st_ex_mtime; + string_set(&fsp->fsp_name,fname); + + mtimespec = get_mtimespec(psbuf); lck = get_share_mode_lock(talloc_tos(), fsp->file_id, - conn->connectpath, smb_dname, &mtimespec); + conn->connectpath, + fname, &mtimespec); if (lck == NULL) { - DEBUG(0, ("open_directory: Could not get share mode lock for " - "%s\n", smb_fname_str_dbg(smb_dname))); + DEBUG(0, ("open_directory: Could not get share mode lock for %s\n", fname)); file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } - status = open_mode_check(conn, lck, access_mask, share_access, - create_options, &dir_existed); + status = open_mode_check(conn, fname, lck, + access_mask, share_access, + create_options, &dir_existed); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(lck); @@ -2636,7 +2583,7 @@ static NTSTATUS open_directory(connection_struct *conn, /* For directories the delete on close bit at open time seems always to be honored on close... See test 19 in Samba4 BASE-DELETE. */ if (create_options & FILE_DELETE_ON_CLOSE) { - status = can_set_delete_on_close(fsp, 0); + status = can_set_delete_on_close(fsp, True, 0); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) { TALLOC_FREE(lck); file_free(req, fsp); @@ -2660,17 +2607,20 @@ static NTSTATUS open_directory(connection_struct *conn, return NT_STATUS_OK; } -NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, - struct smb_filename *smb_dname) +NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, const char *directory) { NTSTATUS status; + SMB_STRUCT_STAT sbuf; files_struct *fsp; + SET_STAT_INVALID(sbuf); + status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_dname, /* fname */ + directory, /* fname */ + 0, /* create_file_flags */ FILE_READ_ATTRIBUTES, /* access_mask */ FILE_SHARE_NONE, /* share_access */ FILE_CREATE, /* create_disposition*/ @@ -2681,7 +2631,8 @@ NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + &sbuf); /* psbuf */ if (NT_STATUS_IS_OK(status)) { close_file(req, fsp, NORMAL_CLOSE); @@ -2705,11 +2656,8 @@ void msg_file_was_renamed(struct messaging_context *msg, char *frm = (char *)data->data; struct file_id id; const char *sharepath; - const char *base_name; - const char *stream_name; - struct smb_filename *smb_fname = NULL; - size_t sp_len, bn_len; - NTSTATUS status; + const char *newname; + size_t sp_len; if (data->data == NULL || data->length < MSG_FILE_RENAMED_MIN_SIZE + 2) { @@ -2721,37 +2669,18 @@ void msg_file_was_renamed(struct messaging_context *msg, /* Unpack the message. */ pull_file_id_24(frm, &id); sharepath = &frm[24]; + newname = sharepath + strlen(sharepath) + 1; sp_len = strlen(sharepath); - base_name = sharepath + sp_len + 1; - bn_len = strlen(base_name); - stream_name = sharepath + sp_len + 1 + bn_len + 1; - - /* stream_name must always be NULL if there is no stream. */ - if (stream_name[0] == '\0') { - stream_name = NULL; - } - - status = create_synthetic_smb_fname(talloc_tos(), base_name, - stream_name, NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return; - } DEBUG(10,("msg_file_was_renamed: Got rename message for sharepath %s, new name %s, " "file_id %s\n", - sharepath, smb_fname_str_dbg(smb_fname), - file_id_string_tos(&id))); + sharepath, newname, file_id_string_tos(&id))); for(fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) { if (memcmp(fsp->conn->connectpath, sharepath, sp_len) == 0) { - - DEBUG(10,("msg_file_was_renamed: renaming file fnum %d from %s -> %s\n", - fsp->fnum, fsp_str_dbg(fsp), - smb_fname_str_dbg(smb_fname))); - status = fsp_set_smb_fname(fsp, smb_fname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } + DEBUG(10,("msg_file_was_renamed: renaming file fnum %d from %s -> %s\n", + fsp->fnum, fsp->fsp_name, newname )); + string_set(&fsp->fsp_name, newname); } else { /* TODO. JRA. */ /* Now we have the complete path we can work out if this is @@ -2762,13 +2691,56 @@ void msg_file_was_renamed(struct messaging_context *msg, fsp->conn->connectpath, sharepath, fsp->fnum, - fsp_str_dbg(fsp), - smb_fname_str_dbg(smb_fname))); + fsp->fsp_name, + newname )); } } - out: - TALLOC_FREE(smb_fname); - return; +} + +struct case_semantics_state { + connection_struct *conn; + bool case_sensitive; + bool case_preserve; + bool short_case_preserve; +}; + +/**************************************************************************** + Restore case semantics. +****************************************************************************/ +static int restore_case_semantics(struct case_semantics_state *state) +{ + state->conn->case_sensitive = state->case_sensitive; + state->conn->case_preserve = state->case_preserve; + state->conn->short_case_preserve = state->short_case_preserve; + return 0; +} + +/**************************************************************************** + Save case semantics. +****************************************************************************/ +struct case_semantics_state *set_posix_case_semantics(TALLOC_CTX *mem_ctx, + connection_struct *conn) +{ + struct case_semantics_state *result; + + if (!(result = talloc(mem_ctx, struct case_semantics_state))) { + DEBUG(0, ("talloc failed\n")); + return NULL; + } + + result->conn = conn; + result->case_sensitive = conn->case_sensitive; + result->case_preserve = conn->case_preserve; + result->short_case_preserve = conn->short_case_preserve; + + /* Set to POSIX. */ + conn->case_sensitive = True; + conn->case_preserve = True; + conn->short_case_preserve = True; + + talloc_set_destructor(result, restore_case_semantics); + + return result; } /* @@ -2819,30 +2791,28 @@ NTSTATUS open_streams_for_delete(connection_struct *conn, } for (i=0; i<num_streams; i++) { - struct smb_filename *smb_fname = NULL; + char *streamname; if (strequal(stream_info[i].name, "::$DATA")) { streams[i] = NULL; continue; } - status = create_synthetic_smb_fname(talloc_tos(), fname, - stream_info[i].name, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } + streamname = talloc_asprintf(talloc_tos(), "%s%s", fname, + stream_info[i].name); - if (SMB_VFS_STAT(conn, smb_fname) == -1) { - DEBUG(10, ("Unable to stat stream: %s\n", - smb_fname_str_dbg(smb_fname))); + if (streamname == NULL) { + DEBUG(0, ("talloc_aprintf failed\n")); + status = NT_STATUS_NO_MEMORY; + goto fail; } status = SMB_VFS_CREATE_FILE( conn, /* conn */ NULL, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + streamname, /* fname */ + 0, /* create_file_flags */ DELETE_ACCESS, /* access_mask */ (FILE_SHARE_READ | /* share_access */ FILE_SHARE_WRITE | FILE_SHARE_DELETE), @@ -2854,17 +2824,16 @@ NTSTATUS open_streams_for_delete(connection_struct *conn, NULL, /* sd */ NULL, /* ea_list */ &streams[i], /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + NULL); /* psbuf */ + + TALLOC_FREE(streamname); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Could not open stream %s: %s\n", - smb_fname_str_dbg(smb_fname), - nt_errstr(status))); - - TALLOC_FREE(smb_fname); + streamname, nt_errstr(status))); break; } - TALLOC_FREE(smb_fname); } /* @@ -2877,7 +2846,7 @@ NTSTATUS open_streams_for_delete(connection_struct *conn, } DEBUG(10, ("Closing stream # %d, %s\n", i, - fsp_str_dbg(streams[i]))); + streams[i]->fsp_name)); close_file(NULL, streams[i], NORMAL_CLOSE); } @@ -2892,7 +2861,7 @@ NTSTATUS open_streams_for_delete(connection_struct *conn, static NTSTATUS create_file_unixpath(connection_struct *conn, struct smb_request *req, - struct smb_filename *smb_fname, + const char *fname, uint32_t access_mask, uint32_t share_access, uint32_t create_disposition, @@ -2904,8 +2873,10 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, struct ea_list *ea_list, files_struct **result, - int *pinfo) + int *pinfo, + SMB_STRUCT_STAT *psbuf) { + SMB_STRUCT_STAT sbuf; int info = FILE_WAS_OPENED; files_struct *base_fsp = NULL; files_struct *fsp = NULL; @@ -2922,7 +2893,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, (unsigned int)create_disposition, (unsigned int)create_options, (unsigned int)oplock_request, - ea_list, sd, smb_fname_str_dbg(smb_fname))); + ea_list, sd, fname)); if (create_options & FILE_OPEN_BY_FILE_ID) { status = NT_STATUS_NOT_SUPPORTED; @@ -2938,14 +2909,23 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, oplock_request |= INTERNAL_OPEN_ONLY; } + if (psbuf != NULL) { + sbuf = *psbuf; + } + else { + if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) { + SET_STAT_INVALID(sbuf); + } + } + if ((conn->fs_capabilities & FILE_NAMED_STREAMS) && (access_mask & DELETE_ACCESS) - && !is_ntfs_stream_smb_fname(smb_fname)) { + && !is_ntfs_stream_name(fname)) { /* * We can't open a file with DELETE access if any of the * streams is open without FILE_SHARE_DELETE */ - status = open_streams_for_delete(conn, smb_fname->base_name); + status = open_streams_for_delete(conn, fname); if (!NT_STATUS_IS_OK(status)) { goto fail; @@ -2965,12 +2945,11 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, && (create_disposition != FILE_CREATE) && (share_access & FILE_SHARE_DELETE) && (access_mask & DELETE_ACCESS) - && (!(can_delete_file_in_directory(conn, smb_fname) || - can_access_file_acl(conn, smb_fname, DELETE_ACCESS)))) { + && (!(can_delete_file_in_directory(conn, fname) || + can_access_file_acl(conn, fname, DELETE_ACCESS)))) { status = NT_STATUS_ACCESS_DENIED; DEBUG(10,("create_file_unixpath: open file %s " - "for delete ACCESS_DENIED\n", - smb_fname_str_dbg(smb_fname))); + "for delete ACCESS_DENIED\n", fname )); goto fail; } @@ -2990,7 +2969,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, } /* Don't allow a SACL set from an NTtrans create until we * support SeSecurityPrivilege. */ - if (!VALID_STAT(smb_fname->st) && + if (!VALID_STAT(sbuf) && lp_nt_acl_support(SNUM(conn)) && sd && (sd->sacl != NULL)) { status = NT_STATUS_PRIVILEGE_NOT_HELD; @@ -2999,16 +2978,27 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, #endif if ((conn->fs_capabilities & FILE_NAMED_STREAMS) - && is_ntfs_stream_smb_fname(smb_fname) + && is_ntfs_stream_name(fname) && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) { + char *base; uint32 base_create_disposition; - struct smb_filename *smb_fname_base = NULL; if (create_options & FILE_DIRECTORY_FILE) { status = NT_STATUS_NOT_A_DIRECTORY; goto fail; } + status = split_ntfs_stream_name(talloc_tos(), fname, + &base, NULL); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("create_file_unixpath: " + "split_ntfs_stream_name failed: %s\n", + nt_errstr(status))); + goto fail; + } + + SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */ + switch (create_disposition) { case FILE_OPEN: base_create_disposition = FILE_OPEN; @@ -3018,34 +3008,16 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, break; } - /* Create an smb_filename with stream_name == NULL. */ - status = create_synthetic_smb_fname(talloc_tos(), - smb_fname->base_name, - NULL, NULL, - &smb_fname_base); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - if (SMB_VFS_STAT(conn, smb_fname_base) == -1) { - DEBUG(10, ("Unable to stat stream: %s\n", - smb_fname_str_dbg(smb_fname_base))); - } - - /* Open the base file. */ - status = create_file_unixpath(conn, NULL, smb_fname_base, 0, + status = create_file_unixpath(conn, NULL, base, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, base_create_disposition, 0, 0, 0, 0, NULL, NULL, - &base_fsp, NULL); - TALLOC_FREE(smb_fname_base); - + &base_fsp, NULL, NULL); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("create_file_unixpath for base %s failed: " - "%s\n", smb_fname->base_name, - nt_errstr(status))); + "%s\n", base, nt_errstr(status))); goto fail; } /* we don't need to low level fd */ @@ -3078,7 +3050,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, oplock_request = 0; status = open_directory( - conn, req, smb_fname, access_mask, share_access, + conn, req, fname, &sbuf, access_mask, share_access, create_disposition, create_options, file_attributes, &info, &fsp); } else { @@ -3092,11 +3064,6 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, goto fail; } - status = fsp_set_smb_fname(fsp, smb_fname); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - /* * We're opening the stream element of a base_fsp * we already opened. Set up the base_fsp pointer. @@ -3107,6 +3074,8 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, status = open_file_ntcreate(conn, req, + fname, + &sbuf, access_mask, share_access, create_disposition, @@ -3142,7 +3111,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, oplock_request = 0; status = open_directory( - conn, req, smb_fname, access_mask, + conn, req, fname, &sbuf, access_mask, share_access, create_disposition, create_options, file_attributes, &info, &fsp); @@ -3195,14 +3164,14 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, } if ((ea_list != NULL) && - ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN))) { - status = set_ea(conn, fsp, fsp->fsp_name, ea_list); + ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN))) { + status = set_ea(conn, fsp, fname, ea_list); if (!NT_STATUS_IS_OK(status)) { goto fail; } } - if (!fsp->is_directory && S_ISDIR(fsp->fsp_name->st.st_ex_mode)) { + if (!fsp->is_directory && S_ISDIR(sbuf.st_mode)) { status = NT_STATUS_ACCESS_DENIED; goto fail; } @@ -3210,7 +3179,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, /* Save the requested allocation size. */ if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { if (allocation_size - && (allocation_size > fsp->fsp_name->st.st_ex_size)) { + && (allocation_size > sbuf.st_size)) { fsp->initial_allocation_size = smb_roundup( fsp->conn, allocation_size); if (fsp->is_directory) { @@ -3225,7 +3194,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, } } else { fsp->initial_allocation_size = smb_roundup( - fsp->conn, (uint64_t)fsp->fsp_name->st.st_ex_size); + fsp->conn, (uint64_t)sbuf.st_size); } } @@ -3235,9 +3204,14 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, if (pinfo != NULL) { *pinfo = info; } - - smb_fname->st = fsp->fsp_name->st; - + if (psbuf != NULL) { + if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) { + *psbuf = sbuf; + } + else { + SMB_VFS_FSTAT(fsp, psbuf); + } + } return NT_STATUS_OK; fail: @@ -3267,28 +3241,19 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, NTSTATUS get_relative_fid_filename(connection_struct *conn, struct smb_request *req, uint16_t root_dir_fid, - struct smb_filename *smb_fname) + const char *fname, char **new_fname) { files_struct *dir_fsp; char *parent_fname = NULL; - char *new_base_name = NULL; - NTSTATUS status; - if (root_dir_fid == 0 || !smb_fname) { - status = NT_STATUS_INTERNAL_ERROR; - goto out; + if (root_dir_fid == 0 || !fname || !new_fname) { + return NT_STATUS_INTERNAL_ERROR; } dir_fsp = file_fsp(req, root_dir_fid); if (dir_fsp == NULL) { - status = NT_STATUS_INVALID_HANDLE; - goto out; - } - - if (is_ntfs_stream_smb_fname(dir_fsp->fsp_name)) { - status = NT_STATUS_INVALID_HANDLE; - goto out; + return NT_STATUS_INVALID_HANDLE; } if (!dir_fsp->is_directory) { @@ -3298,9 +3263,8 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn, */ if ((conn->fs_capabilities & FILE_NAMED_STREAMS) && - is_ntfs_stream_smb_fname(smb_fname)) { - status = NT_STATUS_OBJECT_PATH_NOT_FOUND; - goto out; + is_ntfs_stream_name(fname)) { + return NT_STATUS_OBJECT_PATH_NOT_FOUND; } /* @@ -3310,11 +3274,10 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn, (hint from demyn plantenberg) */ - status = NT_STATUS_INVALID_HANDLE; - goto out; + return NT_STATUS_INVALID_HANDLE; } - if (ISDOT(dir_fsp->fsp_name->base_name)) { + if (ISDOT(dir_fsp->fsp_name)) { /* * We're at the toplevel dir, the final file name * must not contain ./, as this is filtered out @@ -3323,11 +3286,10 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn, */ parent_fname = talloc_strdup(talloc_tos(), ""); if (parent_fname == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; + return NT_STATUS_NO_MEMORY; } } else { - size_t dir_name_len = strlen(dir_fsp->fsp_name->base_name); + size_t dir_name_len = strlen(dir_fsp->fsp_name); /* * Copy in the base directory name. @@ -3336,10 +3298,9 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn, parent_fname = TALLOC_ARRAY(talloc_tos(), char, dir_name_len+2); if (parent_fname == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; + return NT_STATUS_NO_MEMORY; } - memcpy(parent_fname, dir_fsp->fsp_name->base_name, + memcpy(parent_fname, dir_fsp->fsp_name, dir_name_len+1); /* @@ -3355,26 +3316,20 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn, } } - new_base_name = talloc_asprintf(smb_fname, "%s%s", parent_fname, - smb_fname->base_name); - if (new_base_name == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; + *new_fname = talloc_asprintf(talloc_tos(), "%s%s", parent_fname, + fname); + if (*new_fname == NULL) { + return NT_STATUS_NO_MEMORY; } - TALLOC_FREE(smb_fname->base_name); - smb_fname->base_name = new_base_name; - status = NT_STATUS_OK; - - out: - TALLOC_FREE(parent_fname); - return status; + return NT_STATUS_OK; } NTSTATUS create_file_default(connection_struct *conn, struct smb_request *req, uint16_t root_dir_fid, - struct smb_filename *smb_fname, + const char *fname, + uint32_t create_file_flags, uint32_t access_mask, uint32_t share_access, uint32_t create_disposition, @@ -3384,9 +3339,12 @@ NTSTATUS create_file_default(connection_struct *conn, uint64_t allocation_size, struct security_descriptor *sd, struct ea_list *ea_list, + files_struct **result, - int *pinfo) + int *pinfo, + SMB_STRUCT_STAT *psbuf) { + SMB_STRUCT_STAT sbuf; int info = FILE_WAS_OPENED; files_struct *fsp = NULL; NTSTATUS status; @@ -3396,7 +3354,7 @@ NTSTATUS create_file_default(connection_struct *conn, "create_disposition = 0x%x create_options = 0x%x " "oplock_request = 0x%x " "root_dir_fid = 0x%x, ea_list = 0x%p, sd = 0x%p, " - "fname = %s\n", + "create_file_flags = 0x%x, fname = %s\n", (unsigned int)access_mask, (unsigned int)file_attributes, (unsigned int)share_access, @@ -3404,28 +3362,55 @@ NTSTATUS create_file_default(connection_struct *conn, (unsigned int)create_options, (unsigned int)oplock_request, (unsigned int)root_dir_fid, - ea_list, sd, smb_fname_str_dbg(smb_fname))); + ea_list, sd, create_file_flags, fname)); + + /* MSDFS pathname processing must be done FIRST. + MSDFS pathnames containing IPv6 addresses can + be confused with NTFS stream names (they contain + ":" characters. JRA. */ + + if ((req != NULL) && (req->flags2 & FLAGS2_DFS_PATHNAMES)) { + char *resolved_fname; + + status = resolve_dfspath(talloc_tos(), conn, true, fname, + &resolved_fname); + + if (!NT_STATUS_IS_OK(status)) { + /* + * For PATH_NOT_COVERED we had + * reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, + * ERRSRV, ERRbadpath); + * Need to fix in callers + */ + goto fail; + } + fname = resolved_fname; + } /* * Calculate the filename from the root_dir_if if necessary. */ if (root_dir_fid != 0) { + char *new_fname; + status = get_relative_fid_filename(conn, req, root_dir_fid, - smb_fname); + fname, &new_fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } + + fname = new_fname; } /* * Check to see if this is a mac fork of some kind. */ - if (is_ntfs_stream_smb_fname(smb_fname)) { + if (is_ntfs_stream_name(fname)) { enum FAKE_FILE_TYPE fake_file_type; - fake_file_type = is_fake_file(smb_fname); + fake_file_type = is_fake_file(fname); if (fake_file_type != FAKE_FILE_TYPE_NONE) { @@ -3441,34 +3426,56 @@ NTSTATUS create_file_default(connection_struct *conn, * close it */ status = open_fake_file(req, conn, req->vuid, - fake_file_type, smb_fname, + fake_file_type, fname, access_mask, &fsp); if (!NT_STATUS_IS_OK(status)) { goto fail; } - ZERO_STRUCT(smb_fname->st); + ZERO_STRUCT(sbuf); goto done; } if (!(conn->fs_capabilities & FILE_NAMED_STREAMS)) { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + status = NT_STATUS_OBJECT_PATH_NOT_FOUND; + goto fail; + } + } + + if (create_file_flags & CFF_DOS_PATH) { + char *converted_fname; + + SET_STAT_INVALID(sbuf); + + status = unix_convert(talloc_tos(), conn, fname, False, + &converted_fname, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { goto fail; } + fname = converted_fname; + } else { + if (psbuf != NULL) { + sbuf = *psbuf; + } else { + if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) { + SET_STAT_INVALID(sbuf); + } + } + } /* All file access must go through check_name() */ - status = check_name(conn, smb_fname->base_name); + status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } status = create_file_unixpath( - conn, req, smb_fname, access_mask, share_access, + conn, req, fname, access_mask, share_access, create_disposition, create_options, file_attributes, oplock_request, allocation_size, sd, ea_list, - &fsp, &info); + &fsp, &info, &sbuf); if (!NT_STATUS_IS_OK(status)) { goto fail; @@ -3481,6 +3488,9 @@ NTSTATUS create_file_default(connection_struct *conn, if (pinfo != NULL) { *pinfo = info; } + if (psbuf != NULL) { + *psbuf = sbuf; + } return NT_STATUS_OK; fail: diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index cdb6093fe9..086ce1ac23 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -81,7 +81,7 @@ bool set_file_oplock(files_struct *fsp, int oplock_type) DEBUG(5,("set_file_oplock: granted oplock on file %s, %s/%lu, " "tv_sec = %x, tv_usec = %x\n", - fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), + fsp->fsp_name, file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, (int)fsp->open_time.tv_sec, (int)fsp->open_time.tv_usec )); @@ -158,15 +158,14 @@ bool remove_oplock(files_struct *fsp) NULL); if (lck == NULL) { DEBUG(0,("remove_oplock: failed to lock share entry for " - "file %s\n", fsp_str_dbg(fsp))); + "file %s\n", fsp->fsp_name )); return False; } ret = remove_share_oplock(lck, fsp); if (!ret) { DEBUG(0,("remove_oplock: failed to remove share oplock for " "file %s fnum %d, %s\n", - fsp_str_dbg(fsp), fsp->fnum, - file_id_string_tos(&fsp->file_id))); + fsp->fsp_name, fsp->fnum, file_id_string_tos(&fsp->file_id))); } release_file_oplock(fsp); TALLOC_FREE(lck); @@ -185,15 +184,14 @@ bool downgrade_oplock(files_struct *fsp) NULL); if (lck == NULL) { DEBUG(0,("downgrade_oplock: failed to lock share entry for " - "file %s\n", fsp_str_dbg(fsp))); + "file %s\n", fsp->fsp_name )); return False; } ret = downgrade_share_oplock(lck, fsp); if (!ret) { DEBUG(0,("downgrade_oplock: failed to downgrade share oplock " "for file %s fnum %d, file_id %s\n", - fsp_str_dbg(fsp), fsp->fnum, - file_id_string_tos(&fsp->file_id))); + fsp->fsp_name, fsp->fnum, file_id_string_tos(&fsp->file_id))); } downgrade_file_oplock(fsp); @@ -296,8 +294,7 @@ static files_struct *initial_break_processing(struct file_id id, unsigned long f if(fsp->oplock_type == NO_OPLOCK) { if( DEBUGLVL( 3 ) ) { - dbgtext( "initial_break_processing: file %s ", - fsp_str_dbg(fsp)); + dbgtext( "initial_break_processing: file %s ", fsp->fsp_name ); dbgtext( "(file_id = %s gen_id = %lu) has no oplock.\n", file_id_string_tos(&id), fsp->fh->gen_id ); dbgtext( "Allowing break to succeed regardless.\n" ); @@ -317,8 +314,7 @@ static void oplock_timeout_handler(struct event_context *ctx, /* Remove the timed event handler. */ TALLOC_FREE(fsp->oplock_timeout); - DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n", - fsp_str_dbg(fsp))); + DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n", fsp->fsp_name)); global_client_failed_oplock_break = True; remove_oplock(fsp); reply_to_oplock_break_requests(fsp); @@ -357,6 +353,7 @@ static void add_oplock_timeout_handler(files_struct *fsp) void break_level2_to_none_async(files_struct *fsp) { char *break_msg; + bool sign_state; if (fsp->oplock_type == NO_OPLOCK) { /* We already got a "break to none" message and we've handled @@ -379,7 +376,7 @@ void break_level2_to_none_async(files_struct *fsp) DEBUG(10,("process_oplock_async_level2_break_message: sending break " "to none message for fid %d, file %s\n", fsp->fnum, - fsp_str_dbg(fsp))); + fsp->fsp_name)); /* Now send a break to none message to our client. */ break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE); @@ -387,14 +384,20 @@ void break_level2_to_none_async(files_struct *fsp) exit_server("Could not talloc break_msg\n"); } + /* Save the server smb signing state. */ + sign_state = srv_oplock_set_signing(False); + show_msg(break_msg); if (!srv_send_smb(smbd_server_fd(), - break_msg, false, 0, + break_msg, IS_CONN_ENCRYPTED(fsp->conn), NULL)) { exit_server_cleanly("oplock_break: srv_send_smb failed."); } + /* Restore the sign state to what it was. */ + srv_oplock_set_signing(sign_state); + TALLOC_FREE(break_msg); /* Async level2 request, don't send a reply, just remove the oplock. */ @@ -433,7 +436,7 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx message_to_share_mode_entry(&msg, (char *)data->data); DEBUG(10, ("Got oplock async level 2 break message from pid %s: " - "%s/%lu\n", procid_str(talloc_tos(), &src), + "%s/%lu\n", procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), msg.share_file_id)); fsp = initial_break_processing(msg.id, msg.share_file_id); @@ -463,6 +466,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, files_struct *fsp; char *break_msg; bool break_to_level2 = False; + bool sign_state; if (data->data == NULL) { DEBUG(0, ("Got NULL buffer\n")); @@ -478,7 +482,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, message_to_share_mode_entry(&msg, (char *)data->data); DEBUG(10, ("Got oplock break message from pid %s: %s/%lu\n", - procid_str(talloc_tos(), &src), file_id_string_tos(&msg.id), + procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), msg.share_file_id)); fsp = initial_break_processing(msg.id, msg.share_file_id); @@ -510,7 +514,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, !EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { DEBUG(3, ("Already downgraded oplock on %s: %s\n", file_id_string_tos(&fsp->file_id), - fsp_str_dbg(fsp))); + fsp->fsp_name)); /* We just send the same message back. */ messaging_send_buf(msg_ctx, src, MSG_SMB_BREAK_RESPONSE, (uint8 *)data->data, @@ -536,14 +540,20 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, wait_before_sending_break(); } + /* Save the server smb signing state. */ + sign_state = srv_oplock_set_signing(False); + show_msg(break_msg); if (!srv_send_smb(smbd_server_fd(), - break_msg, false, 0, + break_msg, IS_CONN_ENCRYPTED(fsp->conn), NULL)) { exit_server_cleanly("oplock_break: srv_send_smb failed."); } + /* Restore the sign state to what it was. */ + srv_oplock_set_signing(sign_state); + TALLOC_FREE(break_msg); fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT; @@ -570,6 +580,7 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, unsigned long file_id; files_struct *fsp; char *break_msg; + bool sign_state; if (data->data == NULL) { DEBUG(0, ("Got NULL buffer\n")); @@ -586,7 +597,7 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, file_id = (unsigned long)IVAL(data->data, 24); DEBUG(10, ("Got kernel oplock break message from pid %s: %s/%u\n", - procid_str(talloc_tos(), &src), file_id_string_tos(&id), + procid_str(debug_ctx(), &src), file_id_string_tos(&id), (unsigned int)file_id)); fsp = initial_break_processing(id, file_id); @@ -609,14 +620,20 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, exit_server("Could not talloc break_msg\n"); } + /* Save the server smb signing state. */ + sign_state = srv_oplock_set_signing(False); + show_msg(break_msg); if (!srv_send_smb(smbd_server_fd(), - break_msg, false, 0, + break_msg, IS_CONN_ENCRYPTED(fsp->conn), NULL)) { exit_server_cleanly("oplock_break: srv_send_smb failed."); } + /* Restore the sign state to what it was. */ + srv_oplock_set_signing(sign_state); + TALLOC_FREE(break_msg); fsp->sent_oplock_break = BREAK_TO_NONE_SENT; @@ -682,7 +699,7 @@ static void process_oplock_break_response(struct messaging_context *msg_ctx, message_to_share_mode_entry(&msg, (char *)data->data); DEBUG(10, ("Got oplock break response from pid %s: %s/%lu mid %u\n", - procid_str(talloc_tos(), &src), file_id_string_tos(&msg.id), + procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), msg.share_file_id, (unsigned int)msg.op_mid)); /* Here's the hack from open.c, store the mid in the 'port' field */ @@ -711,7 +728,7 @@ static void process_open_retry_message(struct messaging_context *msg_ctx, message_to_share_mode_entry(&msg, (char *)data->data); DEBUG(10, ("Got open retry msg from pid %s: %s mid %u\n", - procid_str(talloc_tos(), &src), file_id_string_tos(&msg.id), + procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), (unsigned int)msg.op_mid)); schedule_deferred_open_smb_message(msg.op_mid); @@ -744,7 +761,7 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp, NULL); if (lck == NULL) { DEBUG(0,("release_level_2_oplocks_on_change: failed to lock " - "share mode entry for file %s.\n", fsp_str_dbg(fsp))); + "share mode entry for file %s.\n", fsp->fsp_name )); return; } diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c index dd32177988..89b8e0f7b5 100644 --- a/source3/smbd/oplock_irix.c +++ b/source3/smbd/oplock_irix.c @@ -212,8 +212,7 @@ static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx, DEBUG(0,("irix_set_kernel_oplock: Unable to get " "kernel oplock on file %s, file_id %s " "gen_id = %ul. Error was %s\n", - fsp_str_dbg(fsp), - file_id_string_tos(&fsp->file_id), + fsp->fsp_name, file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, strerror(errno) )); } else { @@ -221,7 +220,7 @@ static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx, "file %s, fd = %d, file_id = %s, " "gen_id = %ul. Another process had the file " "open.\n", - fsp_str_dbg(fsp), fsp->fh->fd, + fsp->fsp_name, fsp->fh->fd, file_id_string_tos(&fsp->file_id), fsp->fh->gen_id )); } @@ -230,7 +229,7 @@ static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx, DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s " "gen_id = %ul\n", - fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), + fsp->fsp_name, file_id_string_tos(&fsp->file_id), fsp->fh->gen_id)); return True; @@ -251,8 +250,7 @@ static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx, int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1); dbgtext("irix_release_kernel_oplock: file %s, file_id = %s" "gen_id = %ul, has kernel oplock state " - "of %x.\n", fsp_str_dbg(fsp), - file_id_string_tos(&fsp->file_id), + "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, state ); } @@ -265,8 +263,7 @@ static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx, "removing kernel oplock on file " ); dbgtext("%s, file_id = %s gen_id = %ul. " "Error was %s\n", - fsp_str_dbg(fsp), - file_id_string_tos(&fsp->file_id), + fsp->fsp_name, file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, strerror(errno) ); } diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c index c60c745177..2bc0a55518 100644 --- a/source3/smbd/oplock_linux.c +++ b/source3/smbd/oplock_linux.c @@ -115,7 +115,7 @@ static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx, if ( SMB_VFS_LINUX_SETLEASE(fsp, F_WRLCK) == -1) { DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, " "fd = %d, file_id = %s. (%s)\n", - fsp_str_dbg(fsp), fsp->fh->fd, + fsp->fsp_name, fsp->fh->fd, file_id_string_tos(&fsp->file_id), strerror(errno))); return False; @@ -123,7 +123,7 @@ static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx, DEBUG(3,("linux_set_kernel_oplock: got kernel oplock on file %s, " "file_id = %s gen_id = %lu\n", - fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), + fsp->fsp_name, file_id_string_tos(&fsp->file_id), fsp->fh->gen_id)); return True; @@ -144,8 +144,7 @@ static void linux_release_kernel_oplock(struct kernel_oplocks *ctx, int state = fcntl(fsp->fh->fd, F_GETLEASE, 0); dbgtext("linux_release_kernel_oplock: file %s, file_id = %s " "gen_id = %lu has kernel oplock state " - "of %x.\n", fsp_str_dbg(fsp), - file_id_string_tos(&fsp->file_id), + "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, state ); } @@ -157,7 +156,7 @@ static void linux_release_kernel_oplock(struct kernel_oplocks *ctx, dbgtext("linux_release_kernel_oplock: Error when " "removing kernel oplock on file " ); dbgtext("%s, file_id = %s, gen_id = %lu. " - "Error was %s\n", fsp_str_dbg(fsp), + "Error was %s\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, strerror(errno) ); } diff --git a/source3/smbd/oplock_onefs.c b/source3/smbd/oplock_onefs.c index c80925ced3..d359f9c6f2 100644 --- a/source3/smbd/oplock_onefs.c +++ b/source3/smbd/oplock_onefs.c @@ -60,30 +60,29 @@ struct onefs_callback_record { struct onefs_callback_record *callback_recs; /** - * Convert a onefs_callback_record to a debug string using the dbg_ctx(). + * Convert a onefs_callback_record to a string. */ -const char *onefs_cb_record_str_dbg(const struct onefs_callback_record *r) +static char *onefs_callback_record_str_static(const struct onefs_callback_record *r) { - char *result; + static fstring result; if (r == NULL) { - result = talloc_strdup(talloc_tos(), "NULL callback record"); + fstrcpy(result, "NULL callback record"); return result; } switch (r->state) { case ONEFS_OPEN_FILE: - result = talloc_asprintf(talloc_tos(), "cb record %llu for " - "file %s", r->id, - fsp_str_dbg(r->data.fsp)); + fstr_sprintf(result, "cb record %llu for file %s", + r->id, r->data.fsp->fsp_name); + break; case ONEFS_WAITING_FOR_OPLOCK: - result = talloc_asprintf(talloc_tos(), "cb record %llu for " - "pending mid %d", r->id, - (int)r->data.mid); + fstr_sprintf(result, "cb record %llu for pending mid %d", + r->id, (int)r->data.mid); break; default: - result = talloc_asprintf(talloc_tos(), "cb record %llu unknown " - "state %d", r->id, r->state); + fstr_sprintf(result, "cb record %llu unknown state %d", + r->id, r->state); break; } @@ -103,7 +102,7 @@ static void debug_cb_records(const char *fn) DEBUG(10, ("cb records (%s):\n", fn)); for (rec = callback_recs; rec; rec = rec->next) { - DEBUGADD(10, ("%s\n", onefs_cb_record_str_dbg(rec))); + DEBUGADD(10, ("%s\n", onefs_callback_record_str_static(rec))); } } @@ -128,7 +127,7 @@ static struct onefs_callback_record *onefs_find_cb(uint64_t id, for (rec = callback_recs; rec; rec = rec->next) { if (rec->id == id) { DEBUG(10, ("found %s\n", - onefs_cb_record_str_dbg(rec))); + onefs_callback_record_str_static(rec))); break; } } @@ -140,7 +139,7 @@ static struct onefs_callback_record *onefs_find_cb(uint64_t id, if (rec->state != expected_state) { DEBUG(0, ("Expected cb type %d, got %s", expected_state, - onefs_cb_record_str_dbg(rec))); + onefs_callback_record_str_static(rec))); SMB_ASSERT(0); return NULL; } @@ -300,7 +299,7 @@ static void oplock_break_to_none_handler(uint64_t id) } DEBUG(10, ("oplock_break_to_none_handler called for file %s\n", - fsp_str_dbg(cb->data.fsp))); + cb->data.fsp->fsp_name)); init_share_mode_entry(&sme, cb, FORCE_OPLOCK_BREAK_TO_NONE); share_mode_entry_to_message(msg, &sme); @@ -337,7 +336,7 @@ static void oplock_break_to_level_two_handler(uint64_t id) } DEBUG(10, ("oplock_break_to_level_two_handler called for file %s\n", - fsp_str_dbg(cb->data.fsp))); + cb->data.fsp->fsp_name)); init_share_mode_entry(&sme, cb, LEVEL_II_OPLOCK); share_mode_entry_to_message(msg, &sme); @@ -378,7 +377,7 @@ static void oplock_revoked_handler(uint64_t id) SMB_ASSERT(fsp->oplock_timeout == NULL); DEBUG(0,("Level 1 oplock break failed for file %s. Forcefully " - "revoking oplock\n", fsp_str_dbg(fsp))); + "revoking oplock\n", fsp->fsp_name)); global_client_failed_oplock_break = True; remove_oplock(fsp); @@ -414,7 +413,7 @@ static void semlock_available_handler(uint64_t id) char *msg; if (asprintf(&msg, "Semlock available on an open that wasn't " "deferred: %s\n", - onefs_cb_record_str_dbg(cb)) != -1) { + onefs_callback_record_str_static(cb)) != -1) { smb_panic(msg); } smb_panic("Semlock available on an open that wasn't " @@ -458,7 +457,7 @@ static void semlock_async_failure_handler(uint64_t id) char *msg; if (asprintf(&msg, "Semlock failure on an open that wasn't " "deferred: %s\n", - onefs_cb_record_str_dbg(cb)) != -1) { + onefs_callback_record_str_static(cb)) != -1) { smb_panic(msg); } smb_panic("Semlock failure on an open that wasn't deferred\n"); @@ -502,7 +501,7 @@ static void onefs_release_kernel_oplock(struct kernel_oplocks *_ctx, enum oplock_type oplock = onefs_samba_oplock_to_oplock(oplock_type); DEBUG(10, ("onefs_release_kernel_oplock: Releasing %s to type %s\n", - fsp_str_dbg(fsp), onefs_oplock_str(oplock))); + fsp->fsp_name, onefs_oplock_str(oplock))); if (fsp->fh->fd == -1) { DEBUG(1, ("no fd\n")); diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 755ff5d6cd..15d120a79c 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -25,9 +25,7 @@ enum server_allocated_state { SERVER_ALLOCATED_REQUIRED_YES, SERVER_ALLOCATED_REQUIRED_NO, SERVER_ALLOCATED_REQUIRED_ANY}; -static user_struct *get_valid_user_struct_internal( - struct smbd_server_connection *sconn, - uint16 vuid, +static user_struct *get_valid_user_struct_internal(uint16 vuid, enum server_allocated_state server_allocated) { user_struct *usp; @@ -36,8 +34,7 @@ static user_struct *get_valid_user_struct_internal( if (vuid == UID_FIELD_INVALID) return NULL; - usp=sconn->smb1.sessions.validated_users; - for (;usp;usp=usp->next,count++) { + for (usp=validated_users;usp;usp=usp->next,count++) { if (vuid == usp->vuid) { switch (server_allocated) { case SERVER_ALLOCATED_REQUIRED_YES: @@ -53,8 +50,7 @@ static user_struct *get_valid_user_struct_internal( break; } if (count > 10) { - DLIST_PROMOTE(sconn->smb1.sessions.validated_users, - usp); + DLIST_PROMOTE(validated_users, usp); } return usp; } @@ -69,26 +65,24 @@ static user_struct *get_valid_user_struct_internal( tell random client vuid's (normally zero) from valid vuids. ****************************************************************************/ -user_struct *get_valid_user_struct(struct smbd_server_connection *sconn, - uint16 vuid) +user_struct *get_valid_user_struct(uint16 vuid) { - return get_valid_user_struct_internal(sconn, vuid, + return get_valid_user_struct_internal(vuid, SERVER_ALLOCATED_REQUIRED_YES); } -bool is_partial_auth_vuid(struct smbd_server_connection *sconn, uint16 vuid) +bool is_partial_auth_vuid(uint16 vuid) { - return (get_partial_auth_user_struct(sconn, vuid) != NULL); + return (get_partial_auth_user_struct(vuid) != NULL); } /**************************************************************************** Get the user struct of a partial NTLMSSP login ****************************************************************************/ -user_struct *get_partial_auth_user_struct(struct smbd_server_connection *sconn, - uint16 vuid) +user_struct *get_partial_auth_user_struct(uint16 vuid) { - return get_valid_user_struct_internal(sconn, vuid, + return get_valid_user_struct_internal(vuid, SERVER_ALLOCATED_REQUIRED_NO); } @@ -96,11 +90,11 @@ user_struct *get_partial_auth_user_struct(struct smbd_server_connection *sconn, Invalidate a uid. ****************************************************************************/ -void invalidate_vuid(struct smbd_server_connection *sconn, uint16 vuid) +void invalidate_vuid(uint16 vuid) { user_struct *vuser = NULL; - vuser = get_valid_user_struct_internal(sconn, vuid, + vuser = get_valid_user_struct_internal(vuid, SERVER_ALLOCATED_REQUIRED_ANY); if (vuser == NULL) { return; @@ -112,29 +106,24 @@ void invalidate_vuid(struct smbd_server_connection *sconn, uint16 vuid) auth_ntlmssp_end(&vuser->auth_ntlmssp_state); } - DLIST_REMOVE(sconn->smb1.sessions.validated_users, vuser); + DLIST_REMOVE(validated_users, vuser); /* clear the vuid from the 'cache' on each connection, and from the vuid 'owner' of connections */ - conn_clear_vuid_caches(sconn, vuid); + conn_clear_vuid_caches(vuid); TALLOC_FREE(vuser); - sconn->smb1.sessions.num_validated_vuids--; + num_validated_vuids--; } /**************************************************************************** Invalidate all vuid entries for this process. ****************************************************************************/ -void invalidate_all_vuids(struct smbd_server_connection *sconn) +void invalidate_all_vuids(void) { - if (sconn->allow_smb2) { - return; - } - - while (sconn->smb1.sessions.validated_users != NULL) { - invalidate_vuid(sconn, - sconn->smb1.sessions.validated_users->vuid); + while (validated_users != NULL) { + invalidate_vuid(validated_users->vuid); } } @@ -152,7 +141,7 @@ static void increment_next_vuid(uint16_t *vuid) Create a new partial auth user struct. *****************************************************/ -int register_initial_vuid(struct smbd_server_connection *sconn) +int register_initial_vuid(void) { user_struct *vuser; @@ -163,7 +152,7 @@ int register_initial_vuid(struct smbd_server_connection *sconn) } /* Limit allowed vuids to 16bits - VUID_OFFSET. */ - if (sconn->smb1.sessions.num_validated_vuids >= 0xFFFF-VUID_OFFSET) { + if (num_validated_vuids >= 0xFFFF-VUID_OFFSET) { return UID_FIELD_INVALID; } @@ -174,26 +163,25 @@ int register_initial_vuid(struct smbd_server_connection *sconn) } /* Allocate a free vuid. Yes this is a linear search... */ - while( get_valid_user_struct_internal(sconn, - sconn->smb1.sessions.next_vuid, + while( get_valid_user_struct_internal(next_vuid, SERVER_ALLOCATED_REQUIRED_ANY) != NULL ) { - increment_next_vuid(&sconn->smb1.sessions.next_vuid); + increment_next_vuid(&next_vuid); } DEBUG(10,("register_initial_vuid: allocated vuid = %u\n", - (unsigned int)sconn->smb1.sessions.next_vuid )); + (unsigned int)next_vuid )); - vuser->vuid = sconn->smb1.sessions.next_vuid; + vuser->vuid = next_vuid; /* * This happens in an unfinished NTLMSSP session setup. We * need to allocate a vuid between the first and second calls * to NTLMSSP. */ - increment_next_vuid(&sconn->smb1.sessions.next_vuid); - sconn->smb1.sessions.num_validated_vuids++; + increment_next_vuid(&next_vuid); + num_validated_vuids++; - DLIST_ADD(sconn->smb1.sessions.validated_users, vuser); + DLIST_ADD(validated_users, vuser); return vuser->vuid; } @@ -246,8 +234,7 @@ static int register_homes_share(const char *username) * */ -int register_existing_vuid(struct smbd_server_connection *sconn, - uint16 vuid, +int register_existing_vuid(uint16 vuid, auth_serversupplied_info *server_info, DATA_BLOB response_blob, const char *smb_name) @@ -255,7 +242,7 @@ int register_existing_vuid(struct smbd_server_connection *sconn, fstring tmp; user_struct *vuser; - vuser = get_partial_auth_user_struct(sconn, vuid); + vuser = get_partial_auth_user_struct(vuid); if (!vuser) { goto fail; } @@ -311,13 +298,11 @@ int register_existing_vuid(struct smbd_server_connection *sconn, vuser->server_info->unix_name); } - if (srv_is_signing_negotiated(smbd_server_conn) && - !vuser->server_info->guest) { + if (srv_is_signing_negotiated() && !vuser->server_info->guest && + !srv_signing_started()) { /* Try and turn on server signing on the first non-guest * sessionsetup. */ - srv_set_signing(smbd_server_conn, - vuser->server_info->user_session_key, - response_blob); + srv_set_signing(vuser->server_info->user_session_key, response_blob); } /* fill in the current_user_info struct */ @@ -331,7 +316,7 @@ int register_existing_vuid(struct smbd_server_connection *sconn, fail: if (vuser) { - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); } return UID_FIELD_INVALID; } @@ -340,8 +325,7 @@ int register_existing_vuid(struct smbd_server_connection *sconn, Add a name to the session users list. ****************************************************************************/ -void add_session_user(struct smbd_server_connection *sconn, - const char *user) +void add_session_user(const char *user) { struct passwd *pw; char *tmp; @@ -352,29 +336,28 @@ void add_session_user(struct smbd_server_connection *sconn, return; } - if (sconn->smb1.sessions.session_userlist == NULL) { - sconn->smb1.sessions.session_userlist = SMB_STRDUP(pw->pw_name); + if (session_userlist == NULL) { + session_userlist = SMB_STRDUP(pw->pw_name); goto done; } - if (in_list(pw->pw_name,sconn->smb1.sessions.session_userlist,false)) { + if (in_list(pw->pw_name,session_userlist,False) ) { goto done; } - if (strlen(sconn->smb1.sessions.session_userlist) > 128 * 1024) { + if (strlen(session_userlist) > 128 * 1024) { DEBUG(3,("add_session_user: session userlist already " "too large.\n")); goto done; } - if (asprintf(&tmp, "%s %s", - sconn->smb1.sessions.session_userlist, pw->pw_name) == -1) { + if (asprintf(&tmp, "%s %s", session_userlist, pw->pw_name) == -1) { DEBUG(3, ("asprintf failed\n")); goto done; } - SAFE_FREE(sconn->smb1.sessions.session_userlist); - sconn->smb1.sessions.session_userlist = tmp; + SAFE_FREE(session_userlist); + session_userlist = tmp; done: TALLOC_FREE(pw); } @@ -384,13 +367,12 @@ void add_session_user(struct smbd_server_connection *sconn, what Vista uses for the NTLMv2 calculation. ****************************************************************************/ -void add_session_workgroup(struct smbd_server_connection *sconn, - const char *workgroup) +void add_session_workgroup(const char *workgroup) { - if (sconn->smb1.sessions.session_workgroup) { - SAFE_FREE(sconn->smb1.sessions.session_workgroup); + if (session_workgroup) { + SAFE_FREE(session_workgroup); } - sconn->smb1.sessions.session_workgroup = smb_xstrdup(workgroup); + session_workgroup = smb_xstrdup(workgroup); } /**************************************************************************** @@ -398,9 +380,9 @@ void add_session_workgroup(struct smbd_server_connection *sconn, what Vista uses for the NTLMv2 calculation. ****************************************************************************/ -const char *get_session_workgroup(struct smbd_server_connection *sconn) +const char *get_session_workgroup(void) { - return sconn->smb1.sessions.session_workgroup; + return session_workgroup; } /**************************************************************************** @@ -408,57 +390,45 @@ const char *get_session_workgroup(struct smbd_server_connection *sconn) try lower case. ****************************************************************************/ -bool user_in_netgroup(struct smbd_server_connection *sconn, - const char *user, const char *ngname) +bool user_in_netgroup(const char *user, const char *ngname) { #ifdef HAVE_NETGROUP fstring lowercase_user; - if (sconn->smb1.sessions.my_yp_domain == NULL) { - yp_get_default_domain(&sconn->smb1.sessions.my_yp_domain); - } + if (my_yp_domain == NULL) + yp_get_default_domain(&my_yp_domain); - if (sconn->smb1.sessions.my_yp_domain == NULL) { + if(my_yp_domain == NULL) { DEBUG(5,("Unable to get default yp domain, " "let's try without specifying it\n")); } DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", - user, - sconn->smb1.sessions.my_yp_domain? - sconn->smb1.sessions.my_yp_domain:"(ANY)", - ngname)); + user, my_yp_domain?my_yp_domain:"(ANY)", ngname)); - if (innetgr(ngname, NULL, user, sconn->smb1.sessions.my_yp_domain)) { + if (innetgr(ngname, NULL, user, my_yp_domain)) { DEBUG(5,("user_in_netgroup: Found\n")); - return true; - } + return (True); + } else { - /* - * Ok, innetgr is case sensitive. Try once more with lowercase - * just in case. Attempt to fix #703. JRA. - */ - fstrcpy(lowercase_user, user); - strlower_m(lowercase_user); + /* + * Ok, innetgr is case sensitive. Try once more with lowercase + * just in case. Attempt to fix #703. JRA. + */ - if (strcmp(user,lowercase_user) == 0) { - /* user name was already lower case! */ - return false; - } + fstrcpy(lowercase_user, user); + strlower_m(lowercase_user); - DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", - lowercase_user, - sconn->smb1.sessions.my_yp_domain? - sconn->smb1.sessions.my_yp_domain:"(ANY)", - ngname)); + DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", + lowercase_user, my_yp_domain?my_yp_domain:"(ANY)", ngname)); - if (innetgr(ngname, NULL, lowercase_user, - sconn->smb1.sessions.my_yp_domain)) { - DEBUG(5,("user_in_netgroup: Found\n")); - return true; + if (innetgr(ngname, NULL, lowercase_user, my_yp_domain)) { + DEBUG(5,("user_in_netgroup: Found\n")); + return (True); + } } #endif /* HAVE_NETGROUP */ - return false; + return False; } /**************************************************************************** @@ -466,8 +436,7 @@ bool user_in_netgroup(struct smbd_server_connection *sconn, and netgroup lists. ****************************************************************************/ -bool user_in_list(struct smbd_server_connection *sconn, - const char *user,const char **list) +bool user_in_list(const char *user,const char **list) { if (!list || !*list) return False; @@ -495,7 +464,7 @@ bool user_in_list(struct smbd_server_connection *sconn, * Old behaviour. Check netgroup list * followed by UNIX list. */ - if(user_in_netgroup(sconn, user, *list +1)) + if(user_in_netgroup(user, *list +1)) return True; if(user_in_group(user, *list +1)) return True; @@ -507,7 +476,7 @@ bool user_in_list(struct smbd_server_connection *sconn, */ if(user_in_group(user, *list +2)) return True; - if(user_in_netgroup(sconn, user, *list +2)) + if(user_in_netgroup(user, *list +2)) return True; } else { @@ -526,7 +495,7 @@ bool user_in_list(struct smbd_server_connection *sconn, /* * Search netgroup list followed by UNIX list. */ - if(user_in_netgroup(sconn, user, *list +2)) + if(user_in_netgroup(user, *list +2)) return True; if(user_in_group(user, *list +2)) return True; @@ -534,7 +503,7 @@ bool user_in_list(struct smbd_server_connection *sconn, /* * Just search netgroup list. */ - if(user_in_netgroup(sconn, user, *list +1)) + if(user_in_netgroup(user, *list +1)) return True; } } @@ -548,16 +517,16 @@ bool user_in_list(struct smbd_server_connection *sconn, Check if a username is valid. ****************************************************************************/ -static bool user_ok(struct smbd_server_connection *sconn, - const char *user, int snum) +static bool user_ok(const char *user, int snum) { + char **valid, **invalid; bool ret; + valid = invalid = NULL; ret = True; if (lp_invalid_users(snum)) { - char **invalid = str_list_copy(talloc_tos(), - lp_invalid_users(snum)); + invalid = str_list_copy(talloc_tos(), lp_invalid_users(snum)); if (invalid && str_list_substitute(invalid, "%S", lp_servicename(snum))) { @@ -565,16 +534,15 @@ static bool user_ok(struct smbd_server_connection *sconn, * around to pass to str_list_sub_basic() */ if ( invalid && str_list_sub_basic(invalid, "", "") ) { - ret = !user_in_list(sconn, user, + ret = !user_in_list(user, (const char **)invalid); } } - TALLOC_FREE(invalid); } + TALLOC_FREE(invalid); if (ret && lp_valid_users(snum)) { - char **valid = str_list_copy(talloc_tos(), - lp_valid_users(snum)); + valid = str_list_copy(talloc_tos(), lp_valid_users(snum)); if ( valid && str_list_substitute(valid, "%S", lp_servicename(snum)) ) { @@ -582,12 +550,11 @@ static bool user_ok(struct smbd_server_connection *sconn, * around to pass to str_list_sub_basic() */ if ( valid && str_list_sub_basic(valid, "", "") ) { - ret = user_in_list(sconn, user, - (const char **)valid); + ret = user_in_list(user, (const char **)valid); } } - TALLOC_FREE(valid); } + TALLOC_FREE(valid); if (ret && lp_onlyuser(snum)) { char **user_list = str_list_make_v3( @@ -595,8 +562,7 @@ static bool user_ok(struct smbd_server_connection *sconn, if (user_list && str_list_substitute(user_list, "%S", lp_servicename(snum))) { - ret = user_in_list(sconn, user, - (const char **)user_list); + ret = user_in_list(user, (const char **)user_list); } TALLOC_FREE(user_list); } @@ -608,21 +574,16 @@ static bool user_ok(struct smbd_server_connection *sconn, Validate a group username entry. Return the username or NULL. ****************************************************************************/ -static char *validate_group(struct smbd_server_connection *sconn, - char *group, DATA_BLOB password,int snum) +static char *validate_group(char *group, DATA_BLOB password,int snum) { #ifdef HAVE_NETGROUP { char *host, *user, *domain; - struct auth_context *actx = sconn->smb1.negprot.auth_context; - bool enc = sconn->smb1.negprot.encrypted_passwords; setnetgrent(group); while (getnetgrent(&host, &user, &domain)) { if (user) { - if (user_ok(sconn, user, snum) && - password_ok(actx, enc, - get_session_workgroup(sconn), - user,password)) { + if (user_ok(user, snum) && + password_ok(user,password)) { endnetgrent(); return(user); } @@ -635,9 +596,6 @@ static char *validate_group(struct smbd_server_connection *sconn, #ifdef HAVE_GETGRENT { struct group *gptr; - struct auth_context *actx = sconn->smb1.negprot.auth_context; - bool enc = sconn->smb1.negprot.encrypted_passwords; - setgrent(); while ((gptr = (struct group *)getgrent())) { if (strequal(gptr->gr_name,group)) @@ -685,10 +643,8 @@ static char *validate_group(struct smbd_server_connection *sconn, member = member_list; while (*member) { - if (user_ok(sconn, member,snum) && - password_ok(actx, enc, - get_session_workgroup(sconn), - member,password)) { + if (user_ok(member,snum) && + password_ok(member,password)) { char *name = talloc_strdup(talloc_tos(), member); SAFE_FREE(member_list); @@ -716,13 +672,10 @@ static char *validate_group(struct smbd_server_connection *sconn, Note this is *NOT* used when logging on using sessionsetup_and_X. ****************************************************************************/ -bool authorise_login(struct smbd_server_connection *sconn, - int snum, fstring user, DATA_BLOB password, +bool authorise_login(int snum, fstring user, DATA_BLOB password, bool *guest) { bool ok = False; - struct auth_context *actx = sconn->smb1.negprot.auth_context; - bool enc = sconn->smb1.negprot.encrypted_passwords; #ifdef DEBUG_PASSWORD DEBUG(100,("authorise_login: checking authorisation on " @@ -751,8 +704,8 @@ bool authorise_login(struct smbd_server_connection *sconn, char *user_list = NULL; char *saveptr; - if (sconn->smb1.sessions.session_userlist) - user_list = SMB_STRDUP(sconn->smb1.sessions.session_userlist); + if ( session_userlist ) + user_list = SMB_STRDUP(session_userlist); else user_list = SMB_STRDUP(""); @@ -764,12 +717,10 @@ bool authorise_login(struct smbd_server_connection *sconn, auser = strtok_r(NULL, LIST_SEP, &saveptr)) { fstring user2; fstrcpy(user2,auser); - if (!user_ok(sconn,user2,snum)) + if (!user_ok(user2,snum)) continue; - if (password_ok(actx, enc, - get_session_workgroup(sconn), - user2,password)) { + if (password_ok(user2,password)) { ok = True; fstrcpy(user,user2); DEBUG(3,("authorise_login: ACCEPTED: session " @@ -805,8 +756,7 @@ bool authorise_login(struct smbd_server_connection *sconn, auser && !ok; auser = strtok_r(NULL, LIST_SEP, &saveptr)) { if (*auser == '@') { - auser = validate_group(sconn,auser+1, - password,snum); + auser = validate_group(auser+1,password,snum); if (auser) { ok = True; fstrcpy(user,auser); @@ -817,10 +767,8 @@ bool authorise_login(struct smbd_server_connection *sconn, } else { fstring user2; fstrcpy(user2,auser); - if (user_ok(sconn,user2,snum) && - password_ok(actx, enc, - get_session_workgroup(sconn), - user2,password)) { + if (user_ok(user2,snum) && + password_ok(user2,password)) { ok = True; fstrcpy(user,user2); DEBUG(3,("authorise_login: ACCEPTED: " @@ -853,7 +801,7 @@ bool authorise_login(struct smbd_server_connection *sconn, *guest = True; } - if (ok && !user_ok(sconn, user, snum)) { + if (ok && !user_ok(user, snum)) { DEBUG(0,("authorise_login: rejected invalid user %s\n",user)); ok = False; } diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c index 9bc3fdfdf6..878d171073 100644 --- a/source3/smbd/pipes.c +++ b/source3/smbd/pipes.c @@ -37,7 +37,6 @@ NTSTATUS open_np_file(struct smb_request *smb_req, const char *name, { struct connection_struct *conn = smb_req->conn; struct files_struct *fsp; - struct smb_filename *smb_fname = NULL; NTSTATUS status; status = file_new(smb_req, conn, &fsp); @@ -51,19 +50,7 @@ NTSTATUS open_np_file(struct smb_request *smb_req, const char *name, fsp->vuid = smb_req->vuid; fsp->can_lock = false; fsp->access_mask = FILE_READ_DATA | FILE_WRITE_DATA; - - status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - file_free(smb_req, fsp); - return status; - } - status = fsp_set_smb_fname(fsp, smb_fname); - TALLOC_FREE(smb_fname); - if (!NT_STATUS_IS_OK(status)) { - file_free(smb_req, fsp); - return status; - } + string_set(&fsp->fsp_name, name); status = np_open(NULL, name, conn->client_address, conn->server_info, &fsp->fake_file_handle); @@ -105,7 +92,7 @@ void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req) /* 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_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRSRV, ERRaccess); return; } @@ -119,7 +106,7 @@ void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req) * Hack for NT printers... JRA. */ if(should_fail_next_srvsvc_open(fname)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRSRV, ERRaccess); return; } #endif @@ -171,7 +158,7 @@ void reply_pipe_write(struct smb_request *req) struct tevent_req *subreq; if (!fsp_is_np(fsp)) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); + reply_doserror(req, ERRDOS, ERRbadfid); return; } @@ -192,7 +179,7 @@ void reply_pipe_write(struct smb_request *req) data = req->buf + 3; DEBUG(6, ("reply_pipe_write: %x name: %s len: %d\n", (int)fsp->fnum, - fsp_str_dbg(fsp), (int)state->numtowrite)); + fsp->fsp_name, (int)state->numtowrite)); subreq = np_write_send(state, smbd_event_context(), fsp->fake_file_handle, data, state->numtowrite); @@ -216,14 +203,8 @@ static void pipe_write_done(struct tevent_req *subreq) status = np_write_recv(subreq, &nwritten); TALLOC_FREE(subreq); - if (nwritten < 0) { - reply_nterror(req, status); - goto send; - } - - /* Looks bogus to me now. Needs to be removed ? JRA. */ - if ((nwritten == 0 && state->numtowrite != 0)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + if ((nwritten == 0 && state->numtowrite != 0) || (nwritten < 0)) { + reply_unixerror(req, ERRDOS, ERRnoaccess); goto send; } @@ -235,7 +216,6 @@ static void pipe_write_done(struct tevent_req *subreq) send: if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(req->conn)||req->encrypted, &req->pcd)) { exit_server_cleanly("construct_reply: srv_send_smb failed."); @@ -266,7 +246,7 @@ void reply_pipe_write_and_X(struct smb_request *req) struct tevent_req *subreq; if (!fsp_is_np(fsp)) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); + reply_doserror(req, ERRDOS, ERRbadfid); return; } @@ -288,7 +268,7 @@ void reply_pipe_write_and_X(struct smb_request *req) == (PIPE_START_MESSAGE|PIPE_RAW_MODE)); DEBUG(6, ("reply_pipe_write_and_X: %x name: %s len: %d\n", - (int)fsp->fnum, fsp_str_dbg(fsp), (int)state->numtowrite)); + (int)fsp->fnum, fsp->fsp_name, (int)state->numtowrite)); data = (uint8_t *)smb_base(req->inbuf) + smb_doff; @@ -302,7 +282,7 @@ void reply_pipe_write_and_X(struct smb_request *req) DEBUG(0,("reply_pipe_write_and_X: start of message " "set and not enough data sent.(%u)\n", (unsigned int)state->numtowrite )); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_unixerror(req, ERRDOS, ERRnoaccess); return; } @@ -332,15 +312,8 @@ static void pipe_write_andx_done(struct tevent_req *subreq) status = np_write_recv(subreq, &nwritten); TALLOC_FREE(subreq); - - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto done; - } - - /* Looks bogus to me now. Is this error message correct ? JRA. */ - if (nwritten != state->numtowrite) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + if (!NT_STATUS_IS_OK(status) || (nwritten != state->numtowrite)) { + reply_unixerror(req, ERRDOS,ERRnoaccess); goto done; } @@ -389,7 +362,7 @@ void reply_pipe_read_and_X(struct smb_request *req) #endif if (!fsp_is_np(fsp)) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); + reply_doserror(req, ERRDOS, ERRbadfid); return; } diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 7342420a89..43edf21f7d 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -273,16 +273,15 @@ static void store_inheritance_attributes(files_struct *fsp, ret = SMB_VFS_FSETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME, pai_buf, store_size, 0); } else { - ret = SMB_VFS_SETXATTR(fsp->conn, fsp->fsp_name->base_name, - SAMBA_POSIX_INHERITANCE_EA_NAME, - pai_buf, store_size, 0); + ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME, + pai_buf, store_size, 0); } SAFE_FREE(pai_buf); DEBUG(10,("store_inheritance_attribute: type 0x%x for file %s\n", (unsigned int)sd_type, - fsp_str_dbg(fsp))); + fsp->fsp_name)); if (ret == -1 && !no_acl_syscall_error(errno)) { DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) )); @@ -621,10 +620,8 @@ static struct pai_val *fload_inherited_info(files_struct *fsp) ret = SMB_VFS_FGETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME, pai_buf, pai_buf_size); } else { - ret = SMB_VFS_GETXATTR(fsp->conn, - fsp->fsp_name->base_name, - SAMBA_POSIX_INHERITANCE_EA_NAME, - pai_buf, pai_buf_size); + ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME, + pai_buf, pai_buf_size); } if (ret == -1) { @@ -642,8 +639,7 @@ static struct pai_val *fload_inherited_info(files_struct *fsp) } } while (ret == -1); - DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", - (unsigned long)ret, fsp_str_dbg(fsp))); + DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fsp->fsp_name)); if (ret == -1) { /* No attribute or not supported. */ @@ -662,7 +658,8 @@ static struct pai_val *fload_inherited_info(files_struct *fsp) if (paiv) { DEBUG(10,("load_inherited_info: ACL type is 0x%x for file %s\n", - (unsigned int)paiv->sd_type, fsp_str_dbg(fsp))); + (unsigned int)paiv->sd_type, + fsp->fsp_name)); } SAFE_FREE(pai_buf); @@ -908,8 +905,29 @@ static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_AC void create_file_sids(const SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid) { - uid_to_sid( powner_sid, psbuf->st_ex_uid ); - gid_to_sid( pgroup_sid, psbuf->st_ex_gid ); + uid_to_sid( powner_sid, psbuf->st_uid ); + gid_to_sid( pgroup_sid, psbuf->st_gid ); +} + +/**************************************************************************** + Is the identity in two ACEs equal ? Check both SID and uid/gid. +****************************************************************************/ + +static bool identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2) +{ + if (sid_equal(&ace1->trustee, &ace2->trustee)) { + return True; + } + if (ace1->owner_type == ace2->owner_type) { + if (ace1->owner_type == UID_ACE && + ace1->unix_ug.uid == ace2->unix_ug.uid) { + return True; + } else if (ace1->owner_type == GID_ACE && + ace1->unix_ug.gid == ace2->unix_ug.gid) { + return True; + } + } + return False; } /**************************************************************************** @@ -918,7 +936,7 @@ void create_file_sids(const SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID if the permissions become zero, delete the deny if the permissions are non zero. ****************************************************************************/ -static void merge_aces( canon_ace **pp_list_head, bool dir_acl) +static void merge_aces( canon_ace **pp_list_head ) { canon_ace *l_head = *pp_list_head; canon_ace *curr_ace_outer; @@ -936,24 +954,12 @@ static void merge_aces( canon_ace **pp_list_head, bool dir_acl) curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */ for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) { - bool can_merge = false; curr_ace_next = curr_ace->next; /* Save the link in case of delete. */ - /* For file ACLs we can merge if the SIDs and ALLOW/DENY - * types are the same. For directory acls we must also - * ensure the POSIX ACL types are the same. */ + if (identity_in_ace_equal(curr_ace, curr_ace_outer) && + (curr_ace->attr == curr_ace_outer->attr)) { - if (!dir_acl) { - can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) && - (curr_ace->attr == curr_ace_outer->attr)); - } else { - can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) && - (curr_ace->type == curr_ace_outer->type) && - (curr_ace->attr == curr_ace_outer->attr)); - } - - if (can_merge) { if( DEBUGLVL( 10 )) { dbgtext("merge_aces: Merging ACE's\n"); print_canon_ace( curr_ace_outer, 0); @@ -962,13 +968,7 @@ static void merge_aces( canon_ace **pp_list_head, bool dir_acl) /* Merge two allow or two deny ACE's. */ - /* Theoretically we shouldn't merge a dir ACE if - * one ACE has the CI flag set, and the other - * ACE has the OI flag set, but this is rare - * enough we can ignore it. */ - curr_ace_outer->perms |= curr_ace->perms; - curr_ace_outer->ace_flags |= curr_ace->ace_flags; DLIST_REMOVE(l_head, curr_ace); SAFE_FREE(curr_ace); curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */ @@ -997,7 +997,7 @@ static void merge_aces( canon_ace **pp_list_head, bool dir_acl) * we've put on the ACL, we know the deny must be the first one. */ - if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) && + if (identity_in_ace_equal(curr_ace, curr_ace_outer) && (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) { if( DEBUGLVL( 10 )) { @@ -1068,7 +1068,7 @@ bool nt4_compatible_acls(void) not get. Deny entries are implicit on get with ace->perms = 0. ****************************************************************************/ -uint32_t map_canon_ace_perms(int snum, +static uint32_t map_canon_ace_perms(int snum, enum security_ace_type *pacl_type, mode_t perms, bool directory_ace) @@ -1107,10 +1107,9 @@ uint32_t map_canon_ace_perms(int snum, nt_mask |= ((perms & S_IWUSR) ? UNIX_ACCESS_W : 0 ); nt_mask |= ((perms & S_IXUSR) ? UNIX_ACCESS_X : 0 ); } - } - - if ((perms & S_IWUSR) && lp_dos_filemode(snum)) { - nt_mask |= (SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|DELETE_ACCESS); + if ((perms & S_IWUSR) && lp_dos_filemode(snum)) { + nt_mask |= (SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER); + } } DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n", @@ -1394,7 +1393,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, ZERO_STRUCTP(pace); pace->type = SMB_ACL_USER_OBJ; pace->owner_type = UID_ACE; - pace->unix_ug.uid = pst->st_ex_uid; + pace->unix_ug.uid = pst->st_uid; pace->trustee = *pfile_owner_sid; pace->attr = ALLOW_ACE; @@ -1424,7 +1423,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, apply_default_perms(params, is_directory, pace, S_IRUSR); } else { - pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR); + pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); } DLIST_ADD(*pp_ace, pace); @@ -1439,7 +1438,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, ZERO_STRUCTP(pace); pace->type = SMB_ACL_GROUP_OBJ; pace->owner_type = GID_ACE; - pace->unix_ug.uid = pst->st_ex_gid; + pace->unix_ug.uid = pst->st_gid; pace->trustee = *pfile_grp_sid; pace->attr = ALLOW_ACE; if (setting_acl) { @@ -1450,7 +1449,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, pace->perms = 0; apply_default_perms(params, is_directory, pace, S_IRGRP); } else { - pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRGRP, S_IWGRP, S_IXGRP); + pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); } DLIST_ADD(*pp_ace, pace); @@ -1472,7 +1471,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, pace->perms = 0; apply_default_perms(params, is_directory, pace, S_IROTH); } else - pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IROTH, S_IWOTH, S_IXOTH); + pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH); DLIST_ADD(*pp_ace, pace); } @@ -1526,55 +1525,11 @@ static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID } /**************************************************************************** - If an ACE entry is SMB_ACL_USER_OBJ and not CREATOR_OWNER, map to SMB_ACL_USER. - If an ACE entry is SMB_ACL_GROUP_OBJ and not CREATOR_GROUP, map to SMB_ACL_GROUP -****************************************************************************/ - -static bool dup_owning_ace(canon_ace *dir_ace, canon_ace *ace) -{ - /* dir ace must be followings. - SMB_ACL_USER_OBJ : trustee(CREATOR_OWNER) -> Posix ACL d:u::perm - SMB_ACL_USER : not trustee -> Posix ACL u:user:perm - SMB_ACL_USER_OBJ : trustee -> convert to SMB_ACL_USER : trustee - Posix ACL u:trustee:perm - - SMB_ACL_GROUP_OBJ: trustee(CREATOR_GROUP) -> Posix ACL d:g::perm - SMB_ACL_GROUP : not trustee -> Posix ACL g:group:perm - SMB_ACL_GROUP_OBJ: trustee -> convert to SMB_ACL_GROUP : trustee - Posix ACL g:trustee:perm - */ - - if (ace->type == SMB_ACL_USER_OBJ && - !(sid_equal(&ace->trustee, &global_sid_Creator_Owner))) { - canon_ace *dup_ace = dup_canon_ace(ace); - - if (dup_ace == NULL) { - return false; - } - dup_ace->type = SMB_ACL_USER; - DLIST_ADD_END(dir_ace, dup_ace, canon_ace *); - } - - if (ace->type == SMB_ACL_GROUP_OBJ && - !(sid_equal(&ace->trustee, &global_sid_Creator_Group))) { - canon_ace *dup_ace = dup_canon_ace(ace); - - if (dup_ace == NULL) { - return false; - } - dup_ace->type = SMB_ACL_GROUP; - DLIST_ADD_END(dir_ace, dup_ace, canon_ace *); - } - - return true; -} - -/**************************************************************************** Unpack a SEC_DESC into two canonical ace lists. ****************************************************************************/ static bool create_canon_ace_lists(files_struct *fsp, - const SMB_STRUCT_STAT *pst, + SMB_STRUCT_STAT *pst, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid, canon_ace **ppfile_ace, @@ -1694,34 +1649,35 @@ static bool create_canon_ace_lists(files_struct *fsp, current_ace->type = SMB_ACL_OTHER; } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) { current_ace->owner_type = UID_ACE; - current_ace->unix_ug.uid = pst->st_ex_uid; + current_ace->unix_ug.uid = pst->st_uid; current_ace->type = SMB_ACL_USER_OBJ; /* * The Creator Owner entry only specifies inheritable permissions, * never access permissions. WinNT doesn't always set the ACE to - * INHERIT_ONLY, though. + *INHERIT_ONLY, though. */ - psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY; - + if (nt4_compatible_acls()) + psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY; } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) { current_ace->owner_type = GID_ACE; - current_ace->unix_ug.gid = pst->st_ex_gid; + current_ace->unix_ug.gid = pst->st_gid; current_ace->type = SMB_ACL_GROUP_OBJ; /* * The Creator Group entry only specifies inheritable permissions, * never access permissions. WinNT doesn't always set the ACE to - * INHERIT_ONLY, though. + *INHERIT_ONLY, though. */ - psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY; + if (nt4_compatible_acls()) + psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY; } else if (sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid)) { current_ace->owner_type = UID_ACE; /* If it's the owning user, this is a user_obj, not * a user. */ - if (current_ace->unix_ug.uid == pst->st_ex_uid) { + if (current_ace->unix_ug.uid == pst->st_uid) { current_ace->type = SMB_ACL_USER_OBJ; } else { current_ace->type = SMB_ACL_USER; @@ -1730,7 +1686,7 @@ static bool create_canon_ace_lists(files_struct *fsp, current_ace->owner_type = GID_ACE; /* If it's the primary group, this is a group_obj, not * a group. */ - if (current_ace->unix_ug.gid == pst->st_ex_gid) { + if (current_ace->unix_ug.gid == pst->st_gid) { current_ace->type = SMB_ACL_GROUP_OBJ; } else { current_ace->type = SMB_ACL_GROUP; @@ -1795,12 +1751,8 @@ static bool create_canon_ace_lists(files_struct *fsp, got_dir_allow = True; if ((current_ace->attr == DENY_ACE) && got_dir_allow) { - DEBUG(0,("create_canon_ace_lists: " - "malformed ACL in " - "inheritable ACL! Deny entry " - "after Allow entry. Failing " - "to set on file %s.\n", - fsp_str_dbg(fsp))); + DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \ +Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); return False; @@ -1812,34 +1764,6 @@ static bool create_canon_ace_lists(files_struct *fsp, } /* - * We have a lossy mapping: directory ACE entries - * CREATOR_OWNER ------\ - * (map to) +---> SMB_ACL_USER_OBJ - * owning sid ------/ - * - * CREATOR_GROUP ------\ - * (map to) +---> SMB_ACL_GROUP_OBJ - * primary group sid --/ - * - * on set. And on read of a directory ACL - * - * SMB_ACL_USER_OBJ ----> CREATOR_OWNER - * SMB_ACL_GROUP_OBJ ---> CREATOR_GROUP. - * - * Deal with this on set by duplicating - * owning sid and primary group sid ACE - * entries into the directory ACL. - * Fix from Tsukasa Hamano <hamano@osstech.co.jp>. - */ - - if (!dup_owning_ace(dir_ace, current_ace)) { - DEBUG(0,("create_canon_ace_lists: malloc fail !\n")); - free_canon_ace_list(file_ace); - free_canon_ace_list(dir_ace); - return false; - } - - /* * If this is not an inherit only ACE we need to add a duplicate * to the file acl. */ @@ -1859,13 +1783,6 @@ static bool create_canon_ace_lists(files_struct *fsp, * pointer is now owned by the dir_ace list. */ current_ace = dup_ace; - /* We've essentially split this ace into two, - * and added the ace with inheritance request - * bits to the directory ACL. Drop those bits for - * the ACE we're adding to the file list. */ - current_ace->ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT| - SEC_ACE_FLAG_CONTAINER_INHERIT| - SEC_ACE_FLAG_INHERIT_ONLY); } else { /* * We must not free current_ace here as its @@ -1892,10 +1809,8 @@ static bool create_canon_ace_lists(files_struct *fsp, got_file_allow = True; if ((current_ace->attr == DENY_ACE) && got_file_allow) { - DEBUG(0,("create_canon_ace_lists: malformed " - "ACL in file ACL ! Deny entry after " - "Allow entry. Failing to set on file " - "%s.\n", fsp_str_dbg(fsp))); + DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \ +Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); return False; @@ -2275,14 +2190,10 @@ static mode_t create_default_mode(files_struct *fsp, bool interitable_mode) int snum = SNUM(fsp->conn); mode_t and_bits = (mode_t)0; mode_t or_bits = (mode_t)0; - mode_t mode; - - if (interitable_mode) { - mode = unix_mode(fsp->conn, FILE_ATTRIBUTE_ARCHIVE, - fsp->fsp_name, NULL); - } else { - mode = S_IRUSR; - } + mode_t mode = interitable_mode + ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name, + NULL ) + : S_IRUSR; if (fsp->is_directory) mode |= (S_IWUSR|S_IXUSR); @@ -2309,7 +2220,7 @@ static mode_t create_default_mode(files_struct *fsp, bool interitable_mode) ****************************************************************************/ static bool unpack_canon_ace(files_struct *fsp, - const SMB_STRUCT_STAT *pst, + SMB_STRUCT_STAT *pst, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid, canon_ace **ppfile_ace, @@ -2317,7 +2228,6 @@ static bool unpack_canon_ace(files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd) { - SMB_STRUCT_STAT st; canon_ace *file_ace = NULL; canon_ace *dir_ace = NULL; @@ -2357,10 +2267,10 @@ static bool unpack_canon_ace(files_struct *fsp, */ print_canon_ace_list( "file ace - before merge", file_ace); - merge_aces( &file_ace, false); + merge_aces( &file_ace ); print_canon_ace_list( "dir ace - before merge", dir_ace); - merge_aces( &dir_ace, true); + merge_aces( &dir_ace ); /* * NT ACLs are order dependent. Go through the acl lists and @@ -2381,17 +2291,14 @@ static bool unpack_canon_ace(files_struct *fsp, print_canon_ace_list( "file ace - before valid", file_ace); - st = *pst; - /* * A default 3 element mode entry for a file should be r-- --- ---. * A default 3 element mode entry for a directory should be rwx --- ---. */ - st.st_ex_mode = create_default_mode(fsp, False); + pst->st_mode = create_default_mode(fsp, False); - if (!ensure_canon_entry_valid(&file_ace, fsp->conn->params, - fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) { + if (!ensure_canon_entry_valid(&file_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) { free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); return False; @@ -2405,10 +2312,9 @@ static bool unpack_canon_ace(files_struct *fsp, * it's a directory. */ - st.st_ex_mode = create_default_mode(fsp, True); + pst->st_mode = create_default_mode(fsp, True); - if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp->conn->params, - fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) { + if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) { free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); return False; @@ -2520,7 +2426,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn, case SMB_ACL_USER_OBJ: /* Get the SID from the owner. */ sid_copy(&sid, powner); - unix_ug.uid = psbuf->st_ex_uid; + unix_ug.uid = psbuf->st_uid; owner_type = UID_ACE; break; case SMB_ACL_USER: @@ -2530,6 +2436,17 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn, DEBUG(0,("canonicalise_acl: Failed to get uid.\n")); continue; } + /* + * A SMB_ACL_USER entry for the owner is shadowed by the + * SMB_ACL_USER_OBJ entry and Windows also cannot represent + * that entry, so we ignore it. We also don't create such + * entries out of the blue when setting ACLs, so a get/set + * cycle will drop them. + */ + if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) { + SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype); + continue; + } uid_to_sid( &sid, *puid); unix_ug.uid = *puid; owner_type = UID_ACE; @@ -2539,7 +2456,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn, case SMB_ACL_GROUP_OBJ: /* Get the SID from the owning group. */ sid_copy(&sid, pgroup); - unix_ug.gid = psbuf->st_ex_gid; + unix_ug.gid = psbuf->st_gid; owner_type = GID_ACE; break; case SMB_ACL_GROUP: @@ -2593,7 +2510,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn, */ if (!ensure_canon_entry_valid(&l_head, conn->params, - S_ISDIR(psbuf->st_ex_mode), powner, pgroup, + S_ISDIR(psbuf->st_mode), powner, pgroup, psbuf, False)) goto fail; @@ -2654,7 +2571,8 @@ static bool current_user_in_group(gid_t gid) ****************************************************************************/ static bool acl_group_override(connection_struct *conn, - const struct smb_filename *smb_fname) + SMB_STRUCT_STAT *psbuf, + const char *fname) { if ((errno != EPERM) && (errno != EACCES)) { return false; @@ -2662,13 +2580,13 @@ static bool acl_group_override(connection_struct *conn, /* file primary group == user primary or supplementary group */ if (lp_acl_group_control(SNUM(conn)) && - current_user_in_group(smb_fname->st.st_ex_gid)) { + current_user_in_group(psbuf->st_gid)) { return true; } /* user has writeable permission */ if (lp_dos_filemode(SNUM(conn)) && - can_write_to_file(conn, smb_fname)) { + can_write_to_file(conn, fname, psbuf)) { return true; } @@ -2679,11 +2597,7 @@ static bool acl_group_override(connection_struct *conn, Attempt to apply an ACL to a file or directory. ****************************************************************************/ -static bool set_canon_ace_list(files_struct *fsp, - canon_ace *the_ace, - bool default_ace, - const SMB_STRUCT_STAT *psbuf, - bool *pacl_set_support) +static bool set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, bool default_ace, SMB_STRUCT_STAT *psbuf, bool *pacl_set_support) { connection_struct *conn = fsp->conn; bool ret = False; @@ -2697,9 +2611,6 @@ static bool set_canon_ace_list(files_struct *fsp, bool needs_mask = False; mode_t mask_perms = 0; - /* Use the psbuf that was passed in. */ - fsp->fsp_name->st = *psbuf; - #if defined(POSIX_ACL_NEEDS_MASK) /* HP-UX always wants to have a mask (called "class" there). */ needs_mask = True; @@ -2716,7 +2627,7 @@ static bool set_canon_ace_list(files_struct *fsp, default_ace ? "default" : "file", strerror(errno) )); } *pacl_set_support = False; - goto fail; + return False; } if( DEBUGLVL( 10 )) { @@ -2856,8 +2767,7 @@ static bool set_canon_ace_list(files_struct *fsp, */ if(default_ace || fsp->is_directory || fsp->fh->fd == -1) { - if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name->base_name, - the_acl_type, the_acl) == -1) { + if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) { /* * Some systems allow all the above calls and only fail with no ACL support * when attempting to apply the acl. HPUX with HFS is an example of this. JRA. @@ -2866,18 +2776,14 @@ static bool set_canon_ace_list(files_struct *fsp, *pacl_set_support = False; } - if (acl_group_override(conn, fsp->fsp_name)) { + if (acl_group_override(conn, psbuf, fsp->fsp_name)) { int sret; - DEBUG(5,("set_canon_ace_list: acl group " - "control on and current user in file " - "%s primary group.\n", - fsp_str_dbg(fsp))); + DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n", + fsp->fsp_name )); become_root(); - sret = SMB_VFS_SYS_ACL_SET_FILE(conn, - fsp->fsp_name->base_name, the_acl_type, - the_acl); + sret = SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl); unbecome_root(); if (sret == 0) { ret = True; @@ -2885,12 +2791,9 @@ static bool set_canon_ace_list(files_struct *fsp, } if (ret == False) { - DEBUG(2,("set_canon_ace_list: " - "sys_acl_set_file type %s failed for " - "file %s (%s).\n", - the_acl_type == SMB_ACL_TYPE_DEFAULT ? - "directory default" : "file", - fsp_str_dbg(fsp), strerror(errno))); + DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n", + the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file", + fsp->fsp_name, strerror(errno) )); goto fail; } } @@ -2904,13 +2807,11 @@ static bool set_canon_ace_list(files_struct *fsp, *pacl_set_support = False; } - if (acl_group_override(conn, fsp->fsp_name)) { + if (acl_group_override(conn, psbuf, fsp->fsp_name)) { int sret; - DEBUG(5,("set_canon_ace_list: acl group " - "control on and current user in file " - "%s primary group.\n", - fsp_str_dbg(fsp))); + DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n", + fsp->fsp_name )); become_root(); sret = SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl); @@ -2921,10 +2822,8 @@ static bool set_canon_ace_list(files_struct *fsp, } if (ret == False) { - DEBUG(2,("set_canon_ace_list: " - "sys_acl_set_file failed for file %s " - "(%s).\n", - fsp_str_dbg(fsp), strerror(errno))); + DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n", + fsp->fsp_name, strerror(errno) )); goto fail; } } @@ -2992,9 +2891,8 @@ static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file mode_t or_bits; if (ace_count != 3) { - DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE " - "entries for file %s to convert to posix perms.\n", - fsp_str_dbg(fsp))); + DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \ +posix perms.\n", fsp->fsp_name )); return False; } @@ -3008,8 +2906,8 @@ static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file } if (!owner_ace || !group_ace || !other_ace) { - DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get " - "standard entries for file %s.\n", fsp_str_dbg(fsp))); + DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n", + fsp->fsp_name )); return False; } @@ -3043,10 +2941,9 @@ static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file *posix_perms = (((*posix_perms) & and_bits)|or_bits); - DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o " - "to perm=0%o for file %s.\n", (int)owner_ace->perms, - (int)group_ace->perms, (int)other_ace->perms, - (int)*posix_perms, fsp_str_dbg(fsp))); + DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n", + (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms, + fsp->fsp_name )); return True; } @@ -3222,7 +3119,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn, goto done; } - if (S_ISDIR(sbuf->st_ex_mode) && def_acl) { + if (S_ISDIR(sbuf->st_mode) && def_acl) { dir_ace = canonicalise_acl(conn, name, def_acl, sbuf, &global_sid_Creator_Owner, @@ -3306,7 +3203,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn, uint32_t acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, ace->perms, - S_ISDIR(sbuf->st_ex_mode)); + S_ISDIR(sbuf->st_mode)); init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, @@ -3327,7 +3224,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn, uint32_t acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, ace->perms, - S_ISDIR(sbuf->st_ex_mode)); + S_ISDIR(sbuf->st_mode)); init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, @@ -3439,12 +3336,11 @@ NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info, *ppdesc = NULL; - DEBUG(10,("posix_fget_nt_acl: called for file %s\n", - fsp_str_dbg(fsp))); + DEBUG(10,("posix_fget_nt_acl: called for file %s\n", fsp->fsp_name )); /* can it happen that fsp_name == NULL ? */ if (fsp->is_directory || fsp->fh->fd == -1) { - return posix_get_nt_acl(fsp->conn, fsp->fsp_name->base_name, + return posix_get_nt_acl(fsp->conn, fsp->fsp_name, security_info, ppdesc); } @@ -3458,35 +3354,30 @@ NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info, pal = fload_inherited_info(fsp); - return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name, - &sbuf, pal, posix_acl, NULL, - security_info, ppdesc); + return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name, &sbuf, pal, + posix_acl, NULL, security_info, ppdesc); } NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name, uint32_t security_info, SEC_DESC **ppdesc) { + SMB_STRUCT_STAT sbuf; SMB_ACL_T posix_acl = NULL; SMB_ACL_T def_acl = NULL; struct pai_val *pal; - struct smb_filename smb_fname; int ret; *ppdesc = NULL; DEBUG(10,("posix_get_nt_acl: called for file %s\n", name )); - ZERO_STRUCT(smb_fname); - smb_fname.base_name = discard_const_p(char, name); - /* Get the stat struct for the owner info. */ if (lp_posix_pathnames()) { - ret = SMB_VFS_LSTAT(conn, &smb_fname); + ret = SMB_VFS_LSTAT(conn, name, &sbuf); } else { - ret = SMB_VFS_STAT(conn, &smb_fname); + ret = SMB_VFS_STAT(conn, name, &sbuf); } - - if (ret == -1) { + if(ret != 0) { return map_nt_error_from_unix(errno); } @@ -3494,16 +3385,15 @@ NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name, posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_ACCESS); /* If it's a directory get the default POSIX ACL. */ - if(S_ISDIR(smb_fname.st.st_ex_mode)) { + if(S_ISDIR(sbuf.st_mode)) { def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_DEFAULT); def_acl = free_empty_sys_acl(conn, def_acl); } pal = load_inherited_info(conn, name); - return posix_get_nt_acl_common(conn, name, &smb_fname.st, pal, - posix_acl, def_acl, security_info, - ppdesc); + return posix_get_nt_acl_common(conn, name, &sbuf, pal, posix_acl, + def_acl, security_info, ppdesc); } /**************************************************************************** @@ -3516,11 +3406,12 @@ NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name, then allow chown to the currently authenticated user. ****************************************************************************/ -int try_chown(connection_struct *conn, struct smb_filename *smb_fname, - uid_t uid, gid_t gid) +int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) { int ret; files_struct *fsp; + SMB_STRUCT_STAT st; + bool posix_paths = lp_posix_pathnames(); if(!CAN_WRITE(conn)) { return -1; @@ -3528,12 +3419,11 @@ int try_chown(connection_struct *conn, struct smb_filename *smb_fname, /* Case (1). */ /* try the direct way first */ - if (lp_posix_pathnames()) { - ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid, gid); + if (posix_paths) { + ret = SMB_VFS_LCHOWN(conn, fname, uid, gid); } else { - ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid, gid); + ret = SMB_VFS_CHOWN(conn, fname, uid, gid); } - if (ret == 0) return 0; @@ -3552,13 +3442,7 @@ int try_chown(connection_struct *conn, struct smb_filename *smb_fname, become_root(); /* Keep the current file gid the same - take ownership doesn't imply group change. */ - if (lp_posix_pathnames()) { - ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid, - (gid_t)-1); - } else { - ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid, - (gid_t)-1); - } + ret = SMB_VFS_CHOWN(conn, fname, uid, (gid_t)-1); unbecome_root(); return ret; } @@ -3579,33 +3463,22 @@ int try_chown(connection_struct *conn, struct smb_filename *smb_fname, return -1; } - if (lp_posix_pathnames()) { - ret = SMB_VFS_LSTAT(conn, smb_fname); + if (posix_paths) { + ret = SMB_VFS_LSTAT(conn,fname,&st); } else { - ret = SMB_VFS_STAT(conn, smb_fname); + ret = SMB_VFS_STAT(conn,fname,&st); } - - if (ret == -1) { + if (ret != 0) { return -1; } - if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname, &fsp))) { + if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, &st, &fsp))) { return -1; } become_root(); /* Keep the current file gid the same. */ - if (fsp->fh->fd == -1) { - if (lp_posix_pathnames()) { - ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid, - (gid_t)-1); - } else { - ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid, - (gid_t)-1); - } - } else { - ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1); - } + ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1); unbecome_root(); close_file_fchmod(NULL, fsp); @@ -3624,39 +3497,35 @@ NTSTATUS append_parent_acl(files_struct *fsp, const SEC_DESC *pcsd, SEC_DESC **pp_new_sd) { - struct smb_filename *smb_dname = NULL; SEC_DESC *parent_sd = NULL; files_struct *parent_fsp = NULL; TALLOC_CTX *mem_ctx = talloc_tos(); char *parent_name = NULL; SEC_ACE *new_ace = NULL; unsigned int num_aces = pcsd->dacl->num_aces; + SMB_STRUCT_STAT sbuf; NTSTATUS status; int info; unsigned int i, j; SEC_DESC *psd = dup_sec_desc(talloc_tos(), pcsd); bool is_dacl_protected = (pcsd->type & SEC_DESC_DACL_PROTECTED); + ZERO_STRUCT(sbuf); + if (psd == NULL) { return NT_STATUS_NO_MEMORY; } - if (!parent_dirname(mem_ctx, fsp->fsp_name->base_name, &parent_name, - NULL)) { + if (!parent_dirname(mem_ctx, fsp->fsp_name, &parent_name, NULL)) { return NT_STATUS_NO_MEMORY; } - status = create_synthetic_smb_fname(mem_ctx, parent_name, NULL, NULL, - &smb_dname); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - status = SMB_VFS_CREATE_FILE( fsp->conn, /* conn */ NULL, /* req */ 0, /* root_dir_fid */ - smb_dname, /* fname */ + parent_name, /* fname */ + 0, /* create_file_flags */ FILE_READ_ATTRIBUTES, /* access_mask */ FILE_SHARE_NONE, /* share_access */ FILE_OPEN, /* create_disposition*/ @@ -3667,18 +3536,17 @@ NTSTATUS append_parent_acl(files_struct *fsp, NULL, /* sd */ NULL, /* ea_list */ &parent_fsp, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + &sbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(smb_dname); return status; } - status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, smb_dname->base_name, + status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, parent_fsp->fsp_name, DACL_SECURITY_INFORMATION, &parent_sd ); close_file(NULL, parent_fsp, NORMAL_CLOSE); - TALLOC_FREE(smb_dname); if (!NT_STATUS_IS_OK(status)) { return status; @@ -3724,7 +3592,7 @@ NTSTATUS append_parent_acl(files_struct *fsp, "ignoring non container " "inherit flags %u on ACE with sid %s " "from parent %s\n", - fsp_str_dbg(fsp), + fsp->fsp_name, (unsigned int)se->flags, sid_string_dbg(&se->trustee), parent_name)); @@ -3737,7 +3605,7 @@ NTSTATUS append_parent_acl(files_struct *fsp, "ignoring non object " "inherit flags %u on ACE with sid %s " "from parent %s\n", - fsp_str_dbg(fsp), + fsp->fsp_name, (unsigned int)se->flags, sid_string_dbg(&se->trustee), parent_name)); @@ -3761,7 +3629,7 @@ NTSTATUS append_parent_acl(files_struct *fsp, DEBUG(10,("append_parent_acl: path %s " "ignoring ACE with protected sid %s " "from parent %s\n", - fsp_str_dbg(fsp), + fsp->fsp_name, sid_string_dbg(&se->trustee), parent_name)); continue; @@ -3799,7 +3667,7 @@ NTSTATUS append_parent_acl(files_struct *fsp, DEBUG(10,("append_parent_acl: path %s " "inheriting ACE with sid %s " "from parent %s\n", - fsp_str_dbg(fsp), + fsp->fsp_name, sid_string_dbg(&se->trustee), parent_name)); } @@ -3825,6 +3693,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC connection_struct *conn = fsp->conn; uid_t user = (uid_t)-1; gid_t grp = (gid_t)-1; + SMB_STRUCT_STAT sbuf; DOM_SID file_owner_sid; DOM_SID file_grp_sid; canon_ace *file_ace_list = NULL; @@ -3835,9 +3704,10 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC bool set_acl_as_root = false; bool acl_set_support = false; bool ret = false; + bool posix_paths = lp_posix_pathnames(); + int sret; - DEBUG(10,("set_nt_acl: called for file %s\n", - fsp_str_dbg(fsp))); + DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name )); if (!CAN_WRITE(conn)) { DEBUG(10,("set acl rejected on read-only share\n")); @@ -3848,13 +3718,22 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC * Get the current state of the file. */ - status = vfs_stat_fsp(fsp); - if (!NT_STATUS_IS_OK(status)) { - return status; + if(fsp->is_directory || fsp->fh->fd == -1) { + if (posix_paths) { + sret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); + } else { + sret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + } + if (sret != 0) { + return map_nt_error_from_unix(errno); + } + } else { + if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) + return map_nt_error_from_unix(errno); } /* Save the original element we check against. */ - orig_mode = fsp->fsp_name->st.st_ex_mode; + orig_mode = sbuf.st_mode; /* * Unpack the user/group/world id's. @@ -3871,18 +3750,14 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC * Noticed by Simo. */ - if (((user != (uid_t)-1) && (fsp->fsp_name->st.st_ex_uid != user)) || - (( grp != (gid_t)-1) && (fsp->fsp_name->st.st_ex_gid != grp))) { + if (((user != (uid_t)-1) && (sbuf.st_uid != user)) || (( grp != (gid_t)-1) && (sbuf.st_gid != grp))) { DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", - fsp_str_dbg(fsp), (unsigned int)user, - (unsigned int)grp)); - - if(try_chown(fsp->conn, fsp->fsp_name, user, grp) == -1) { - DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error " - "= %s.\n", fsp_str_dbg(fsp), - (unsigned int)user, (unsigned int)grp, - strerror(errno))); + fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); + + if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { + DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n", + fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) )); if (errno == EPERM) { return NT_STATUS_INVALID_OWNER; } @@ -3894,13 +3769,32 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC * (suid/sgid bits, for instance) */ - status = vfs_stat_fsp(fsp); - if (!NT_STATUS_IS_OK(status)) { - return status; + if(fsp->is_directory) { + if (posix_paths) { + sret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name, &sbuf); + } else { + sret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf); + } + if (sret != 0) { + return map_nt_error_from_unix(errno); + } + } else { + if(fsp->fh->fd == -1) { + if (posix_paths) { + sret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name, &sbuf); + } else { + sret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf); + } + } else { + sret = SMB_VFS_FSTAT(fsp, &sbuf); + } + + if(sret != 0) + return map_nt_error_from_unix(errno); } /* Save the original element we check against. */ - orig_mode = fsp->fsp_name->st.st_ex_mode; + orig_mode = sbuf.st_mode; /* If we successfully chowned, we know we must * be able to set the acl, so do it as root. @@ -3908,11 +3802,10 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC set_acl_as_root = true; } - create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid); + create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid); - acl_perms = unpack_canon_ace(fsp, &fsp->fsp_name->st, &file_owner_sid, - &file_grp_sid, &file_ace_list, - &dir_ace_list, security_info_sent, psd); + acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid, + &file_ace_list, &dir_ace_list, security_info_sent, psd); /* Ignore W2K traverse DACL set. */ if (!file_ace_list && !dir_ace_list) { @@ -3945,15 +3838,12 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC if (set_acl_as_root) { become_root(); } - ret = set_canon_ace_list(fsp, file_ace_list, false, - &fsp->fsp_name->st, &acl_set_support); + ret = set_canon_ace_list(fsp, file_ace_list, False, &sbuf, &acl_set_support); if (set_acl_as_root) { unbecome_root(); } if (acl_set_support && ret == false) { - DEBUG(3,("set_nt_acl: failed to set file acl on file " - "%s (%s).\n", fsp_str_dbg(fsp), - strerror(errno))); + DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) )); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); return map_nt_error_from_unix(errno); @@ -3965,23 +3855,17 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC if (set_acl_as_root) { become_root(); } - ret = set_canon_ace_list(fsp, dir_ace_list, true, - &fsp->fsp_name->st, - &acl_set_support); + ret = set_canon_ace_list(fsp, dir_ace_list, True, &sbuf, &acl_set_support); if (set_acl_as_root) { unbecome_root(); } if (ret == false) { - DEBUG(3,("set_nt_acl: failed to set default " - "acl on directory %s (%s).\n", - fsp_str_dbg(fsp), strerror(errno))); + DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) )); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); return map_nt_error_from_unix(errno); } } else { - int sret = -1; - /* * No default ACL - delete one if it exists. */ @@ -3989,24 +3873,18 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC if (set_acl_as_root) { become_root(); } - sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, - fsp->fsp_name->base_name); + sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name); if (set_acl_as_root) { unbecome_root(); } if (sret == -1) { - if (acl_group_override(conn, fsp->fsp_name)) { - DEBUG(5,("set_nt_acl: acl group " - "control on and current user " - "in file %s primary group. " - "Override delete_def_acl\n", - fsp_str_dbg(fsp))); + if (acl_group_override(conn, &sbuf, fsp->fsp_name)) { + DEBUG(5,("set_nt_acl: acl group control on and " + "current user in file %s primary group. Override delete_def_acl\n", + fsp->fsp_name )); become_root(); - sret = - SMB_VFS_SYS_ACL_DELETE_DEF_FILE( - conn, - fsp->fsp_name->base_name); + sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name); unbecome_root(); } @@ -4043,47 +3921,36 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) { free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - DEBUG(3,("set_nt_acl: failed to convert file acl to " - "posix permissions for file %s.\n", - fsp_str_dbg(fsp))); + DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n", + fsp->fsp_name )); return NT_STATUS_ACCESS_DENIED; } if (orig_mode != posix_perms) { - int sret = -1; - DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n", - fsp_str_dbg(fsp), (unsigned int)posix_perms)); + fsp->fsp_name, (unsigned int)posix_perms )); if (set_acl_as_root) { become_root(); } - sret = SMB_VFS_CHMOD(conn, fsp->fsp_name->base_name, - posix_perms); + sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms); if (set_acl_as_root) { unbecome_root(); } if(sret == -1) { - if (acl_group_override(conn, fsp->fsp_name)) { - DEBUG(5,("set_nt_acl: acl group " - "control on and current user " - "in file %s primary group. " - "Override chmod\n", - fsp_str_dbg(fsp))); + if (acl_group_override(conn, &sbuf, fsp->fsp_name)) { + DEBUG(5,("set_nt_acl: acl group control on and " + "current user in file %s primary group. Override chmod\n", + fsp->fsp_name )); become_root(); - sret = SMB_VFS_CHMOD(conn, - fsp->fsp_name->base_name, - posix_perms); + sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms); unbecome_root(); } if (sret == -1) { - DEBUG(3,("set_nt_acl: chmod %s, 0%o " - "failed. Error = %s.\n", - fsp_str_dbg(fsp), - (unsigned int)posix_perms, - strerror(errno))); + DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n", + fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) )); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); return map_nt_error_from_unix(errno); @@ -4095,9 +3962,6 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - /* Ensure the stat struct in the fsp is correct. */ - status = vfs_stat_fsp(fsp); - return NT_STATUS_OK; } @@ -4465,12 +4329,12 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_ on the directory. ****************************************************************************/ -bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf, +bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint16 num_def_acls, const char *pdata) { SMB_ACL_T def_acl = NULL; - if (!S_ISDIR(psbuf->st_ex_mode)) { + if (!S_ISDIR(psbuf->st_mode)) { if (num_def_acls) { DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname )); errno = EISDIR; @@ -4701,7 +4565,6 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) connection_struct *conn; files_struct finfo; struct fd_handle fh; - NTSTATUS status; conn = TALLOC_ZERO_P(ctx, connection_struct); if (conn == NULL) { @@ -4721,7 +4584,7 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) if (!smbd_vfs_init(conn)) { DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n")); - conn_free(conn); + conn_free_internal( conn ); return NULL; } @@ -4732,25 +4595,17 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) finfo.conn = conn; finfo.fh = &fh; finfo.fh->fd = -1; - - status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, NULL, - &finfo.fsp_name); - if (!NT_STATUS_IS_OK(status)) { - conn_free(conn); - return NULL; - } + finfo.fsp_name = CONST_DISCARD(char *,fname); if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, DACL_SECURITY_INFORMATION, &psd))) { DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n")); - TALLOC_FREE(finfo.fsp_name); - conn_free(conn); + conn_free_internal( conn ); return NULL; } ret_sd = dup_sec_desc( ctx, psd ); - TALLOC_FREE(finfo.fsp_name); - conn_free(conn); + conn_free_internal( conn ); return ret_sd; } diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 572f37dbbe..b4976f77f8 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -20,20 +20,6 @@ #include "includes.h" #include "smbd/globals.h" -#include "../librpc/gen_ndr/srv_dfs.h" -#include "../librpc/gen_ndr/srv_dssetup.h" -#include "../librpc/gen_ndr/srv_echo.h" -#include "../librpc/gen_ndr/srv_eventlog.h" -#include "../librpc/gen_ndr/srv_initshutdown.h" -#include "../librpc/gen_ndr/srv_lsa.h" -#include "../librpc/gen_ndr/srv_netlogon.h" -#include "../librpc/gen_ndr/srv_ntsvcs.h" -#include "../librpc/gen_ndr/srv_samr.h" -#include "../librpc/gen_ndr/srv_spoolss.h" -#include "../librpc/gen_ndr/srv_srvsvc.h" -#include "../librpc/gen_ndr/srv_svcctl.h" -#include "../librpc/gen_ndr/srv_winreg.h" -#include "../librpc/gen_ndr/srv_wkssvc.h" extern bool global_machine_password_needs_changing; @@ -46,20 +32,16 @@ static void construct_reply_common(struct smb_request *req, const char *inbuf, Send an smb to a fd. ****************************************************************************/ -bool srv_send_smb(int fd, char *buffer, - bool do_signing, uint32_t seqnum, - bool do_encrypt, - struct smb_perfcount_data *pcd) +bool srv_send_smb(int fd, char *buffer, bool do_encrypt, + struct smb_perfcount_data *pcd) { size_t len = 0; size_t nwritten=0; ssize_t ret; char *buf_out = buffer; - if (do_signing) { - /* Sign the outgoing packet if required. */ - srv_calculate_sign_mac(smbd_server_conn, buf_out, seqnum); - } + /* Sign the outgoing packet if required. */ + srv_calculate_sign_mac(buf_out); if (do_encrypt) { NTSTATUS status = srv_encrypt_buffer(buffer, &buf_out); @@ -73,12 +55,15 @@ bool srv_send_smb(int fd, char *buffer, len = smb_len(buf_out) + 4; - ret = write_data(fd,buf_out+nwritten,len - nwritten); - if (ret <= 0) { - DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n", - (int)len,(int)ret, strerror(errno) )); - srv_free_enc_buffer(buf_out); - goto out; + while (nwritten < len) { + ret = write_data(fd,buf_out+nwritten,len - nwritten); + if (ret <= 0) { + DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n", + (int)len,(int)ret, strerror(errno) )); + srv_free_enc_buffer(buf_out); + goto out; + } + nwritten += ret; } SMB_PERFCOUNT_SET_MSGLEN_OUT(pcd, len); @@ -290,7 +275,7 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, int fd, if (CVAL(lenbuf,0) == 0 && min_recv_size && (smb_len_large(lenbuf) > /* Could be a UNIX large writeX. */ (min_recv_size + STANDARD_WRITE_AND_X_HEADER_SIZE)) && - !srv_is_signing_active(smbd_server_conn)) { + !srv_is_signing_active()) { return receive_smb_raw_talloc_partial_read( mem_ctx, lenbuf, fd, buffer, timeout, p_unread, plen); @@ -326,8 +311,7 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, int fd, static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer, unsigned int timeout, size_t *p_unread, bool *p_encrypted, - size_t *p_len, - uint32_t *seqnum) + size_t *p_len) { size_t len = 0; NTSTATUS status; @@ -352,7 +336,7 @@ static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, } /* Check the incoming SMB signature. */ - if (!srv_check_sign_mac(smbd_server_conn, *buffer, seqnum)) { + if (!srv_check_sign_mac(*buffer, true)) { DEBUG(0, ("receive_smb: SMB Signature verification failed on " "incoming packet!\n")); return NT_STATUS_INVALID_NETWORK_RESPONSE; @@ -371,7 +355,6 @@ void init_smb_request(struct smb_request *req, size_t unread_bytes, bool encrypted) { - struct smbd_server_connection *sconn = smbd_server_conn; size_t req_size = smb_len(inbuf) + 4; /* Ensure we have at least smb_size bytes. */ if (req_size < smb_size) { @@ -383,7 +366,6 @@ void init_smb_request(struct smb_request *req, req->flags2 = SVAL(inbuf, smb_flg2); req->smbpid = SVAL(inbuf, smb_pid); req->mid = SVAL(inbuf, smb_mid); - req->seqnum = 0; req->vuid = SVAL(inbuf, smb_uid); req->tid = SVAL(inbuf, smb_tid); req->wct = CVAL(inbuf, smb_wct); @@ -392,7 +374,7 @@ void init_smb_request(struct smb_request *req, req->buf = (const uint8_t *)smb_buf(inbuf); req->unread_bytes = unread_bytes; req->encrypted = encrypted; - req->conn = conn_find(sconn,req->tid); + req->conn = conn_find(req->tid); req->chain_fsp = NULL; req->chain_outbuf = NULL; req->done = false; @@ -420,8 +402,7 @@ void init_smb_request(struct smb_request *req, static void process_smb(struct smbd_server_connection *conn, uint8_t *inbuf, size_t nread, size_t unread_bytes, - uint32_t seqnum, bool encrypted, - struct smb_perfcount_data *deferred_pcd); + bool encrypted, struct smb_perfcount_data *deferred_pcd); static void smbd_deferred_open_timer(struct event_context *ev, struct timed_event *te, @@ -444,7 +425,7 @@ static void smbd_deferred_open_timer(struct event_context *ev, /* We leave this message on the queue so the open code can know this is a retry. */ DEBUG(5,("smbd_deferred_open_timer: trigger mid %u.\n", - (unsigned int)mid )); + (unsigned int)mid)); /* Mark the message as processed so this is not * re-processed in error. */ @@ -452,7 +433,7 @@ static void smbd_deferred_open_timer(struct event_context *ev, process_smb(smbd_server_conn, inbuf, msg->buf.length, 0, - msg->seqnum, msg->encrypted, &msg->pcd); + msg->encrypted, &msg->pcd); /* If it's still there and was processed, remove it. */ msg = get_open_deferred_message(mid); @@ -489,7 +470,6 @@ static bool push_queued_message(struct smb_request *req, } msg->request_time = request_time; - msg->seqnum = req->seqnum; msg->encrypted = req->encrypted; msg->processed = false; SMB_PERFCOUNT_DEFER_OP(&req->pcd, &msg->pcd); @@ -1263,7 +1243,6 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in int flags; uint16 session_tag; connection_struct *conn = NULL; - struct smbd_server_connection *sconn = smbd_server_conn; errno = 0; @@ -1307,12 +1286,12 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in * JRA. */ - if (session_tag != sconn->smb1.sessions.last_session_tag) { + if (session_tag != last_session_tag) { user_struct *vuser = NULL; - sconn->smb1.sessions.last_session_tag = session_tag; + last_session_tag = session_tag; if(session_tag != UID_FIELD_INVALID) { - vuser = get_valid_user_struct(sconn, session_tag); + vuser = get_valid_user_struct(session_tag); if (vuser) { set_current_user_info( vuser->server_info->sanitized_username, @@ -1335,15 +1314,13 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in if (type == SMBntcreateX) { reply_nterror(req, NT_STATUS_INVALID_HANDLE); } else { - reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED); + reply_doserror(req, ERRSRV, ERRinvnid); } return NULL; } if (!change_to_user(conn,session_tag)) { - DEBUG(0, ("Error: Could not change to user. Removing " - "deferred open, mid=%d.\n", req->mid)); - reply_force_doserror(req, ERRSRV, ERRbaduid); + reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRbaduid)); return conn; } @@ -1357,7 +1334,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in /* IPC services are limited */ if (IS_IPC(conn) && !(flags & CAN_IPC)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRSRV,ERRaccess); return conn; } } else { @@ -1382,7 +1359,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in if (!set_current_service(conn,SVAL(req->inbuf,smb_flg), (flags & (AS_USER|DO_CHDIR) ?True:False))) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRSRV, ERRaccess); return conn; } conn->num_smb_operations++; @@ -1393,7 +1370,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in && (!change_to_guest() || !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRSRV, ERRaccess); return conn; } @@ -1406,7 +1383,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in ****************************************************************************/ static void construct_reply(char *inbuf, int size, size_t unread_bytes, - uint32_t seqnum, bool encrypted, + bool encrypted, struct smb_perfcount_data *deferred_pcd) { connection_struct *conn; @@ -1418,7 +1395,6 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes, init_smb_request(req, (uint8 *)inbuf, unread_bytes, encrypted); req->inbuf = (uint8_t *)talloc_move(req, &inbuf); - req->seqnum = seqnum; /* we popped this message off the queue - keep original perf data */ if (deferred_pcd) @@ -1455,7 +1431,6 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes, if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(conn)||req->encrypted, &req->pcd)) { exit_server_cleanly("construct_reply: srv_send_smb failed."); @@ -1471,8 +1446,7 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes, ****************************************************************************/ static void process_smb(struct smbd_server_connection *conn, uint8_t *inbuf, size_t nread, size_t unread_bytes, - uint32_t seqnum, bool encrypted, - struct smb_perfcount_data *deferred_pcd) + bool encrypted, struct smb_perfcount_data *deferred_pcd) { int msg_type = CVAL(inbuf,0); @@ -1492,21 +1466,13 @@ static void process_smb(struct smbd_server_connection *conn, goto done; } - if (smbd_server_conn->allow_smb2) { - if (smbd_is_smb2_header(inbuf, nread)) { - smbd_smb2_first_negprot(smbd_server_conn, inbuf, nread); - return; - } - smbd_server_conn->allow_smb2 = false; - } - show_msg((char *)inbuf); - construct_reply((char *)inbuf,nread,unread_bytes,seqnum,encrypted,deferred_pcd); + construct_reply((char *)inbuf,nread,unread_bytes,encrypted,deferred_pcd); trans_num++; done: - conn->smb1.num_requests++; + conn->num_requests++; /* The timeout_processing function isn't run nearly often enough to implement 'max log size' without @@ -1515,7 +1481,7 @@ done: level 10. Checking every 50 SMBs is a nice tradeoff of performance vs log file size overrun. */ - if ((conn->smb1.num_requests % 50) == 0 && + if ((conn->num_requests % 50) == 0 && need_to_check_log_size()) { change_to_root_user(); check_log_size(); @@ -1608,180 +1574,6 @@ static void fixup_chain_error_packet(struct smb_request *req) SCVAL(req->outbuf, smb_vwv0, 0xff); } -/** - * @brief Find the smb_cmd offset of the last command pushed - * @param[in] buf The buffer we're building up - * @retval Where can we put our next andx cmd? - * - * While chaining requests, the "next" request we're looking at needs to put - * its SMB_Command before the data the previous request already built up added - * to the chain. Find the offset to the place where we have to put our cmd. - */ - -static bool find_andx_cmd_ofs(uint8_t *buf, size_t *pofs) -{ - uint8_t cmd; - size_t ofs; - - cmd = CVAL(buf, smb_com); - - SMB_ASSERT(is_andx_req(cmd)); - - ofs = smb_vwv0; - - while (CVAL(buf, ofs) != 0xff) { - - if (!is_andx_req(CVAL(buf, ofs))) { - return false; - } - - /* - * ofs is from start of smb header, so add the 4 length - * bytes. The next cmd is right after the wct field. - */ - ofs = SVAL(buf, ofs+2) + 4 + 1; - - SMB_ASSERT(ofs+4 < talloc_get_size(buf)); - } - - *pofs = ofs; - return true; -} - -/** - * @brief Do the smb chaining at a buffer level - * @param[in] poutbuf Pointer to the talloc'ed buffer to be modified - * @param[in] smb_command The command that we want to issue - * @param[in] wct How many words? - * @param[in] vwv The words, already in network order - * @param[in] bytes_alignment How shall we align "bytes"? - * @param[in] num_bytes How many bytes? - * @param[in] bytes The data the request ships - * - * smb_splice_chain() adds the vwv and bytes to the request already present in - * *poutbuf. - */ - -static bool smb_splice_chain(uint8_t **poutbuf, uint8_t smb_command, - uint8_t wct, const uint16_t *vwv, - size_t bytes_alignment, - uint32_t num_bytes, const uint8_t *bytes) -{ - uint8_t *outbuf; - size_t old_size, new_size; - size_t ofs; - size_t chain_padding = 0; - size_t bytes_padding = 0; - bool first_request; - - old_size = talloc_get_size(*poutbuf); - - /* - * old_size == smb_wct means we're pushing the first request in for - * libsmb/ - */ - - first_request = (old_size == smb_wct); - - if (!first_request && ((old_size % 4) != 0)) { - /* - * Align the wct field of subsequent requests to a 4-byte - * boundary - */ - chain_padding = 4 - (old_size % 4); - } - - /* - * After the old request comes the new wct field (1 byte), the vwv's - * and the num_bytes field. After at we might need to align the bytes - * given to us to "bytes_alignment", increasing the num_bytes value. - */ - - new_size = old_size + chain_padding + 1 + wct * sizeof(uint16_t) + 2; - - if ((bytes_alignment != 0) && ((new_size % bytes_alignment) != 0)) { - bytes_padding = bytes_alignment - (new_size % bytes_alignment); - } - - new_size += bytes_padding + num_bytes; - - if ((smb_command != SMBwriteX) && (new_size > 0xffff)) { - DEBUG(1, ("splice_chain: %u bytes won't fit\n", - (unsigned)new_size)); - return false; - } - - outbuf = TALLOC_REALLOC_ARRAY(NULL, *poutbuf, uint8_t, new_size); - if (outbuf == NULL) { - DEBUG(0, ("talloc failed\n")); - return false; - } - *poutbuf = outbuf; - - if (first_request) { - SCVAL(outbuf, smb_com, smb_command); - } else { - size_t andx_cmd_ofs; - - if (!find_andx_cmd_ofs(outbuf, &andx_cmd_ofs)) { - DEBUG(1, ("invalid command chain\n")); - *poutbuf = TALLOC_REALLOC_ARRAY( - NULL, *poutbuf, uint8_t, old_size); - return false; - } - - if (chain_padding != 0) { - memset(outbuf + old_size, 0, chain_padding); - old_size += chain_padding; - } - - SCVAL(outbuf, andx_cmd_ofs, smb_command); - SSVAL(outbuf, andx_cmd_ofs + 2, old_size - 4); - } - - ofs = old_size; - - /* - * Push the chained request: - * - * wct field - */ - - SCVAL(outbuf, ofs, wct); - ofs += 1; - - /* - * vwv array - */ - - memcpy(outbuf + ofs, vwv, sizeof(uint16_t) * wct); - ofs += sizeof(uint16_t) * wct; - - /* - * bcc (byte count) - */ - - SSVAL(outbuf, ofs, num_bytes + bytes_padding); - ofs += sizeof(uint16_t); - - /* - * padding - */ - - if (bytes_padding != 0) { - memset(outbuf + ofs, 0, bytes_padding); - ofs += bytes_padding; - } - - /* - * The bytes field - */ - - memcpy(outbuf + ofs, bytes, num_bytes); - - return true; -} - /**************************************************************************** Construct a chained reply and add it to the already made reply ****************************************************************************/ @@ -1878,7 +1670,6 @@ void chain_reply(struct smb_request *req) talloc_get_size(req->chain_outbuf) - 4); if (!srv_send_smb(smbd_server_fd(), (char *)req->chain_outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(req->conn) ||req->encrypted, &req->pcd)) { @@ -1983,25 +1774,10 @@ void chain_reply(struct smb_request *req) * We end up here if there's any error in the chain syntax. Report a * DOS error, just like Windows does. */ - reply_force_doserror(req, ERRSRV, ERRerror); + reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRerror)); fixup_chain_error_packet(req); done: - /* - * This scary statement intends to set the - * FLAGS2_32_BIT_ERROR_CODES flg2 field in req->chain_outbuf - * to the value req->outbuf carries - */ - SSVAL(req->chain_outbuf, smb_flg2, - (SVAL(req->chain_outbuf, smb_flg2) & ~FLAGS2_32_BIT_ERROR_CODES) - | (SVAL(req->outbuf, smb_flg2) & FLAGS2_32_BIT_ERROR_CODES)); - - /* - * Transfer the error codes from the subrequest to the main one - */ - SSVAL(req->chain_outbuf, smb_rcls, SVAL(req->outbuf, smb_rcls)); - SSVAL(req->chain_outbuf, smb_err, SVAL(req->outbuf, smb_err)); - if (!smb_splice_chain(&req->chain_outbuf, CVAL(req->outbuf, smb_com), CVAL(req->outbuf, smb_wct), @@ -2018,7 +1794,6 @@ void chain_reply(struct smb_request *req) show_msg((char *)(req->chain_outbuf)); if (!srv_send_smb(smbd_server_fd(), (char *)req->chain_outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(req->conn)||req->encrypted, &req->pcd)) { exit_server_cleanly("construct_reply: srv_send_smb failed."); @@ -2089,7 +1864,6 @@ static void smbd_server_connection_read_handler(struct smbd_server_connection *c bool encrypted = false; TALLOC_CTX *mem_ctx = talloc_tos(); NTSTATUS status; - uint32_t seqnum; /* TODO: make this completely nonblocking */ @@ -2098,7 +1872,7 @@ static void smbd_server_connection_read_handler(struct smbd_server_connection *c 0, /* timeout */ &unread_bytes, &encrypted, - &inbuf_len, &seqnum); + &inbuf_len); if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { goto process; } @@ -2110,8 +1884,7 @@ static void smbd_server_connection_read_handler(struct smbd_server_connection *c } process: - process_smb(conn, inbuf, inbuf_len, unread_bytes, - seqnum, encrypted, NULL); + process_smb(conn, inbuf, inbuf_len, unread_bytes, encrypted, NULL); } static void smbd_server_connection_handler(struct event_context *ev, @@ -2201,9 +1974,8 @@ static bool keepalive_fn(const struct timeval *now, void *private_data) */ static bool deadtime_fn(const struct timeval *now, void *private_data) { - struct smbd_server_connection *sconn = smbd_server_conn; - if ((conn_num_open(sconn) == 0) - || (conn_idle_all(sconn, now->tv_sec))) { + if ((conn_num_open() == 0) + || (conn_idle_all(now->tv_sec))) { DEBUG( 2, ( "Closing idle connection\n" ) ); messaging_send(smbd_messaging_context(), procid_self(), MSG_SHUTDOWN, &data_blob_null); @@ -2247,9 +2019,9 @@ void smbd_process(void) TALLOC_CTX *frame = talloc_stackframe(); char remaddr[INET6_ADDRSTRLEN]; - if (lp_maxprotocol() == PROTOCOL_SMB2 && - lp_security() != SEC_SHARE) { - smbd_server_conn->allow_smb2 = true; + smbd_server_conn = talloc_zero(smbd_event_context(), struct smbd_server_connection); + if (!smbd_server_conn) { + exit_server("failed to create smbd_server_connection"); } /* Ensure child is set to blocking mode */ @@ -2284,8 +2056,7 @@ void smbd_process(void) unsigned char buf[5] = {0x83, 0, 0, 1, 0x81}; DEBUG( 1, ("Connection denied from %s\n", client_addr(get_client_fd(),addr,sizeof(addr)) ) ); - (void)srv_send_smb(smbd_server_fd(),(char *)buf, false, - 0, false, NULL); + (void)srv_send_smb(smbd_server_fd(),(char *)buf,false, NULL); exit_server_cleanly("connection denied"); } @@ -2311,10 +2082,6 @@ void smbd_process(void) DEBUG(0,("Changed root to %s\n", lp_rootdir())); } - if (!srv_init_signing(smbd_server_conn)) { - exit_server("Failed to init smb_signing"); - } - /* Setup oplocks */ if (!init_oplocks(smbd_messaging_context())) exit_server("Failed to init oplocks"); @@ -2330,15 +2097,6 @@ void smbd_process(void) messaging_register(smbd_messaging_context(), NULL, MSG_SMB_CLOSE_FILE, msg_close_file); - /* - * Use the default MSG_DEBUG handler to avoid rebroadcasting - * MSGs to all child processes - */ - messaging_deregister(smbd_messaging_context(), - MSG_DEBUG, NULL); - messaging_register(smbd_messaging_context(), NULL, - MSG_DEBUG, debug_message); - if ((lp_keepalive() != 0) && !(event_add_idle(smbd_event_context(), NULL, timeval_set(lp_keepalive(), 0), @@ -2396,37 +2154,15 @@ void smbd_process(void) #endif - smbd_server_conn->nbt.got_session = false; - - smbd_server_conn->smb1.negprot.max_recv = MIN(lp_maxxmit(),BUFFER_SIZE); - - smbd_server_conn->smb1.sessions.done_sesssetup = false; - smbd_server_conn->smb1.sessions.max_send = BUFFER_SIZE; - smbd_server_conn->smb1.sessions.last_session_tag = UID_FIELD_INVALID; - /* users from session setup */ - smbd_server_conn->smb1.sessions.session_userlist = NULL; - /* workgroup from session setup. */ - smbd_server_conn->smb1.sessions.session_workgroup = NULL; - /* this holds info on user ids that are already validated for this VC */ - smbd_server_conn->smb1.sessions.validated_users = NULL; - smbd_server_conn->smb1.sessions.next_vuid = VUID_OFFSET; - smbd_server_conn->smb1.sessions.num_validated_vuids = 0; -#ifdef HAVE_NETGROUP - smbd_server_conn->smb1.sessions.my_yp_domain = NULL; -#endif - - conn_init(smbd_server_conn); - if (!init_dptrs(smbd_server_conn)) { - exit_server("init_dptrs() failed"); - } + max_recv = MIN(lp_maxxmit(),BUFFER_SIZE); - smbd_server_conn->smb1.fde = event_add_fd(smbd_event_context(), - smbd_server_conn, - smbd_server_fd(), - EVENT_FD_READ, - smbd_server_connection_handler, - smbd_server_conn); - if (!smbd_server_conn->smb1.fde) { + smbd_server_conn->fde = event_add_fd(smbd_event_context(), + smbd_server_conn, + smbd_server_fd(), + EVENT_FD_READ, + smbd_server_connection_handler, + smbd_server_conn); + if (!smbd_server_conn->fde) { exit_server("failed to create smbd_server_connection fde"); } diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c index 1ad2b937b1..c4664e71cf 100644 --- a/source3/smbd/quotas.c +++ b/source3/smbd/quotas.c @@ -224,10 +224,10 @@ bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *d /* find the block device file */ - if (sys_stat(path, &S, false) == -1 ) + if ( sys_stat(path, &S) == -1 ) return(False) ; - devno = S.st_ex_dev ; + devno = S.st_dev ; if ((fp = setmntent(MOUNTED,"r")) == NULL) return(False) ; @@ -235,10 +235,10 @@ bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *d found = False ; while ((mnt = getmntent(fp))) { - if (sys_stat(mnt->mnt_dir, &S, false) == -1) + if ( sys_stat(mnt->mnt_dir,&S) == -1 ) continue ; - if (S.st_ex_dev == devno) { + if (S.st_dev == devno) { found = True ; break; } @@ -317,21 +317,21 @@ bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *d int quota_default = 0 ; bool found = false; - if (sys_stat(path, &sbuf, false) == -1) { + if (sys_stat(path,&sbuf) == -1) { return false; } - devno = sbuf.st_ex_dev ; + devno = sbuf.st_dev ; if ((fd = setmntent(KMTAB)) == NULL) { return false; } while ((mnt = getmntent(fd)) != NULL) { - if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) { + if (sys_stat(mnt->mnt_dir,&sbuf) == -1) { continue; } - if (sbuf.st_ex_dev == devno) { + if (sbuf.st_dev == devno) { found = frue ; break; } @@ -599,11 +599,11 @@ bool disk_quotas(const char *path, euser_id = geteuid(); - if (sys_stat(path, &sbuf, false) == -1) { + if (sys_stat(path,&sbuf) == -1) { return false; } - devno = sbuf.st_ex_dev ; + devno = sbuf.st_dev ; DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path, (unsigned int)devno)); #if defined(SUNOS5) @@ -612,7 +612,7 @@ bool disk_quotas(const char *path, } while (getmntent(fd, &mnt) == 0) { - if (sys_stat(mnt.mnt_mountp, &sbuf, false) == -1) { + if (sys_stat(mnt.mnt_mountp, &sbuf) == -1) { continue; } @@ -620,7 +620,7 @@ bool disk_quotas(const char *path, mnt.mnt_mountp, (unsigned int)devno)); /* quotas are only on vxfs, UFS or NFS */ - if ((sbuf.st_ex_dev == devno) && ( + if ((sbuf.st_dev == devno) && ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 || strcmp( mnt.mnt_fstype, "nfs" ) == 0 || strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) { @@ -639,13 +639,13 @@ bool disk_quotas(const char *path, } while ((mnt = getmntent(fd)) != NULL) { - if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) { + if (sys_stat(mnt->mnt_dir,&sbuf) == -1) { continue; } DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir, - (unsigned int)sbuf.st_ex_dev)); - if (sbuf.st_ex_dev == devno) { + (unsigned int)sbuf.st_dev)); + if (sbuf.st_dev == devno) { found = true; name = talloc_strdup(talloc_tos(), mnt->mnt_fsname); @@ -832,19 +832,19 @@ bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *d /* find the block device file */ - if ( sys_stat(path, &S, false) == -1 ) { + if ( sys_stat(path, &S) == -1 ) { return(False) ; } - devno = S.st_ex_dev ; + devno = S.st_dev ; fp = setmntent(MOUNTED,"r"); found = False ; while ((mnt = getmntent(fp))) { - if ( sys_stat(mnt->mnt_dir, &S, false) == -1 ) + if ( sys_stat(mnt->mnt_dir,&S) == -1 ) continue ; - if (S.st_ex_dev == devno) { + if (S.st_dev == devno) { found = True ; break ; } @@ -1154,11 +1154,9 @@ bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *d * to have a significant performance boost when * lstat calls on /dev access this function. */ - if ((sys_stat(path, &S, false)<0) - || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0)) + if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0)) #else - if ((sys_stat(path, &S, false)<0) - || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0)) + if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False); #endif /* ifdef HPUX */ @@ -1185,18 +1183,18 @@ bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *d SMB_STRUCT_STAT st; int mntsize, i; - if (sys_stat(path, &st, false) < 0) + if (sys_stat(path,&st) < 0) return False; - devno = st.st_ex_dev; + devno = st.st_dev; mntsize = getmntinfo(&mnts,MNT_NOWAIT); if (mntsize <= 0) return False; for (i = 0; i < mntsize; i++) { - if (sys_stat(mnts[i].f_mntonname, &st, false) < 0) + if (sys_stat(mnts[i].f_mntonname,&st) < 0) return False; - if (st.st_ex_dev == devno) + if (st.st_dev == devno) break; } if (i == mntsize) diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index b1a4e31951..23fa3e885b 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -27,6 +27,8 @@ #include "includes.h" #include "smbd/globals.h" +extern enum protocol_types Protocol; + /**************************************************************************** Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext path or anything including wildcards. @@ -44,9 +46,9 @@ static NTSTATUS check_path_syntax_internal(char *path, { char *d = path; const char *s = path; - NTSTATUS ret = NT_STATUS_OK; bool start_of_name_component = True; bool stream_started = false; + bool check_quota = false; *p_last_component_contains_wcard = False; @@ -63,11 +65,14 @@ static NTSTATUS check_path_syntax_internal(char *path, if (strchr_m(&s[1], ':')) { return NT_STATUS_OBJECT_NAME_INVALID; } + if (StrCaseCmp(s, ":$DATA") != 0) { + check_quota = true; + } break; } } - if ((*s == ':') && !posix_path && !stream_started) { + if (!posix_path && !stream_started && *s == ':') { if (*p_last_component_contains_wcard) { return NT_STATUS_OBJECT_NAME_INVALID; } @@ -122,8 +127,7 @@ static NTSTATUS check_path_syntax_internal(char *path, /* Are we at the start ? Can't go back further if so. */ if (d <= path) { - ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; - break; + return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } /* Go back one level... */ /* We know this is safe as '/' cannot be part of a mb sequence. */ @@ -196,7 +200,13 @@ static NTSTATUS check_path_syntax_internal(char *path, *d = '\0'; - return ret; + if (check_quota) { + if (StrCaseCmp(path, FAKE_FILE_NAME_QUOTA_UNIX) != 0) { + return NT_STATUS_INVALID_PARAMETER; + } + } + + return NT_STATUS_OK; } /**************************************************************************** @@ -402,95 +412,6 @@ bool fsp_belongs_conn(connection_struct *conn, struct smb_request *req, return False; } -static bool netbios_session_retarget(const char *name, int name_type) -{ - char *trim_name; - char *trim_name_type; - const char *retarget_parm; - char *retarget; - char *p; - int retarget_type = 0x20; - int retarget_port = 139; - struct sockaddr_storage retarget_addr; - struct sockaddr_in *in_addr; - bool ret = false; - uint8_t outbuf[10]; - - if (get_socket_port(smbd_server_fd()) != 139) { - return false; - } - - trim_name = talloc_strdup(talloc_tos(), name); - if (trim_name == NULL) { - goto fail; - } - trim_char(trim_name, ' ', ' '); - - trim_name_type = talloc_asprintf(trim_name, "%s#%2.2x", trim_name, - name_type); - if (trim_name_type == NULL) { - goto fail; - } - - retarget_parm = lp_parm_const_string(-1, "netbios retarget", - trim_name_type, NULL); - if (retarget_parm == NULL) { - retarget_parm = lp_parm_const_string(-1, "netbios retarget", - trim_name, NULL); - } - if (retarget_parm == NULL) { - goto fail; - } - - retarget = talloc_strdup(trim_name, retarget_parm); - if (retarget == NULL) { - goto fail; - } - - DEBUG(10, ("retargeting %s to %s\n", trim_name_type, retarget)); - - p = strchr(retarget, ':'); - if (p != NULL) { - *p++ = '\0'; - retarget_port = atoi(p); - } - - p = strchr_m(retarget, '#'); - if (p != NULL) { - *p++ = '\0'; - sscanf(p, "%x", &retarget_type); - } - - ret = resolve_name(retarget, &retarget_addr, retarget_type, false); - if (!ret) { - DEBUG(10, ("could not resolve %s\n", retarget)); - goto fail; - } - - if (retarget_addr.ss_family != AF_INET) { - DEBUG(10, ("Retarget target not an IPv4 addr\n")); - goto fail; - } - - in_addr = (struct sockaddr_in *)(void *)&retarget_addr; - - _smb_setlen(outbuf, 6); - SCVAL(outbuf, 0, 0x84); - *(uint32_t *)(outbuf+4) = in_addr->sin_addr.s_addr; - *(uint16_t *)(outbuf+8) = htons(retarget_port); - - if (!srv_send_smb(smbd_server_fd(), (char *)outbuf, false, 0, false, - NULL)) { - exit_server_cleanly("netbios_session_regarget: srv_send_smb " - "failed."); - } - - ret = true; - fail: - TALLOC_FREE(trim_name); - return ret; -} - /**************************************************************************** Reply to a (netbios-level) special message. ****************************************************************************/ @@ -500,8 +421,7 @@ void reply_special(char *inbuf) int msg_type = CVAL(inbuf,0); int msg_flags = CVAL(inbuf,1); fstring name1,name2; - char name_type1, name_type2; - struct smbd_server_connection *sconn = smbd_server_conn; + char name_type = 0; /* * We only really use 4 bytes of the outbuf, but for the smb_setlen @@ -519,7 +439,7 @@ void reply_special(char *inbuf) switch (msg_type) { case 0x81: /* session request */ - if (sconn->nbt.got_session) { + if (already_got_session) { exit_server_cleanly("multiple session request not permitted"); } @@ -530,23 +450,19 @@ void reply_special(char *inbuf) DEBUG(0,("Invalid name length in session request\n")); return; } - name_type1 = name_extract(inbuf,4,name1); - name_type2 = name_extract(inbuf,4 + name_len(inbuf + 4),name2); - DEBUG(2,("netbios connect: name1=%s0x%x name2=%s0x%x\n", - name1, name_type1, name2, name_type2)); - - if (netbios_session_retarget(name1, name_type1)) { - exit_server_cleanly("retargeted client"); - } + name_extract(inbuf,4,name1); + name_type = name_extract(inbuf,4 + name_len(inbuf + 4),name2); + DEBUG(2,("netbios connect: name1=%s name2=%s\n", + name1,name2)); set_local_machine_name(name1, True); set_remote_machine_name(name2, True); DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n", get_local_machine_name(), get_remote_machine_name(), - name_type2)); + name_type)); - if (name_type2 == 'R') { + if (name_type == 'R') { /* We are being asked for a pathworks session --- no thanks! */ SCVAL(outbuf, 0,0x83); @@ -557,13 +473,13 @@ void reply_special(char *inbuf) of possibly valid usernames if we are operating in share mode security */ if (lp_security() == SEC_SHARE) { - add_session_user(sconn, get_remote_machine_name()); + add_session_user(get_remote_machine_name()); } reload_services(True); reopen_logs(); - sconn->nbt.got_session = true; + already_got_session = True; break; case 0x89: /* session keepalive request @@ -586,7 +502,7 @@ void reply_special(char *inbuf) DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n", msg_type, msg_flags)); - srv_send_smb(smbd_server_fd(), outbuf, false, 0, false, NULL); + srv_send_smb(smbd_server_fd(), outbuf, false, NULL); return; } @@ -607,7 +523,6 @@ void reply_tcon(struct smb_request *req) const char *p; DATA_BLOB password_blob; TALLOC_CTX *ctx = talloc_tos(); - struct smbd_server_connection *sconn = smbd_server_conn; START_PROFILE(SMBtcon); @@ -639,8 +554,7 @@ void reply_tcon(struct smb_request *req) password_blob = data_blob(password, pwlen+1); - conn = make_connection(sconn,service,password_blob,dev, - req->vuid,&nt_status); + conn = make_connection(service,password_blob,dev,req->vuid,&nt_status); req->conn = conn; data_blob_clear_free(&password_blob); @@ -652,7 +566,7 @@ void reply_tcon(struct smb_request *req) } reply_outbuf(req, 2, 0); - SSVAL(req->outbuf,smb_vwv0,sconn->smb1.negprot.max_recv); + SSVAL(req->outbuf,smb_vwv0,max_recv); SSVAL(req->outbuf,smb_vwv1,conn->cnum); SSVAL(req->outbuf,smb_tid,conn->cnum); @@ -683,7 +597,6 @@ void reply_tcon_and_X(struct smb_request *req) char *path = NULL; const char *p, *q; uint16 tcon_flags; - struct smbd_server_connection *sconn = smbd_server_conn; START_PROFILE(SMBtconX); @@ -704,12 +617,12 @@ void reply_tcon_and_X(struct smb_request *req) } if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) { - reply_force_doserror(req, ERRDOS, ERRbuftoosmall); + reply_doserror(req, ERRDOS, ERRbuftoosmall); END_PROFILE(SMBtconX); return; } - if (sconn->smb1.negprot.encrypted_passwords) { + if (global_encrypted_passwords_negotiated) { password = data_blob_talloc(talloc_tos(), req->buf, passlen); if (lp_security() == SEC_SHARE) { /* @@ -744,7 +657,7 @@ void reply_tcon_and_X(struct smb_request *req) q = strchr_m(path+2,'\\'); if (!q) { data_blob_clear_free(&password); - reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME); + reply_doserror(req, ERRDOS, ERRnosuchshare); END_PROFILE(SMBtconX); return; } @@ -766,7 +679,7 @@ void reply_tcon_and_X(struct smb_request *req) DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service)); - conn = make_connection(sconn, service, password, client_devicetype, + conn = make_connection(service, password, client_devicetype, req->vuid, &nt_status); req->conn =conn; @@ -785,7 +698,7 @@ void reply_tcon_and_X(struct smb_request *req) else server_devicetype = "A:"; - if (get_Protocol() < PROTOCOL_NT1) { + if (Protocol < PROTOCOL_NT1) { reply_outbuf(req, 2, 0); if (message_push_string(&req->outbuf, server_devicetype, STR_TERMINATE|STR_ASCII) == -1) { @@ -864,7 +777,7 @@ void reply_unknown_new(struct smb_request *req, uint8 type) { DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n", smb_fn_name(type), type, type)); - reply_force_doserror(req, ERRSRV, ERRunknownsmb); + reply_doserror(req, ERRSRV, ERRunknownsmb); return; } @@ -901,7 +814,7 @@ void reply_ioctl(struct smb_request *req) replysize = 32; break; default: - reply_force_doserror(req, ERRSRV, ERRnosupport); + reply_doserror(req, ERRSRV, ERRnosupport); END_PROFILE(SMBioctl); return; } @@ -920,7 +833,7 @@ void reply_ioctl(struct smb_request *req) files_struct *fsp = file_fsp( req, SVAL(req->vwv+0, 0)); if (!fsp) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); + reply_doserror(req, ERRDOS, ERRbadfid); END_PROFILE(SMBioctl); return; } @@ -966,8 +879,8 @@ static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status) void reply_checkpath(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname = NULL; char *name = NULL; + SMB_STRUCT_STAT sbuf; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); @@ -983,16 +896,10 @@ void reply_checkpath(struct smb_request *req) return; } - DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0))); - - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - name, - 0, - NULL, - &smb_fname); - + status = resolve_dfspath(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + name, + &name); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -1003,23 +910,50 @@ void reply_checkpath(struct smb_request *req) goto path_err; } - if (!VALID_STAT(smb_fname->st) && - (SMB_VFS_STAT(conn, smb_fname) != 0)) { - DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), strerror(errno))); - status = map_nt_error_from_unix(errno); + DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0))); + + status = unix_convert(ctx, conn, name, False, &name, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + goto path_err; + } + + status = check_name(conn, name); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3,("reply_checkpath: check_name of %s failed (%s)\n",name,nt_errstr(status))); goto path_err; } - if (!S_ISDIR(smb_fname->st.st_ex_mode)) { + if (!VALID_STAT(sbuf)) { + int ret; + + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(conn,name,&sbuf); + } else { + ret = SMB_VFS_STAT(conn,name,&sbuf); + } + if (ret != 0) { + DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno))); + status = map_nt_error_from_unix(errno); + goto path_err; + } + } + + if (!S_ISDIR(sbuf.st_mode)) { reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY, ERRDOS, ERRbadpath); - goto out; + END_PROFILE(SMBcheckpath); + return; } reply_outbuf(req, 0, 0); - path_err: + END_PROFILE(SMBcheckpath); + return; + + path_err: + + END_PROFILE(SMBcheckpath); + /* We special case this - as when a Windows machine is parsing a path is steps through the components one at a time - if a component fails it expects @@ -1036,15 +970,10 @@ void reply_checkpath(struct smb_request *req) */ reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERRbadpath); - goto out; + return; } reply_nterror(req, status); - - out: - TALLOC_FREE(smb_fname); - END_PROFILE(SMBcheckpath); - return; } /**************************************************************************** @@ -1054,15 +983,14 @@ void reply_checkpath(struct smb_request *req) void reply_getatr(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname = NULL; char *fname = NULL; + SMB_STRUCT_STAT sbuf; int mode=0; SMB_OFF_T size=0; time_t mtime=0; const char *p; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); - bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); START_PROFILE(SMBgetatr); @@ -1070,7 +998,24 @@ void reply_getatr(struct smb_request *req) p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBgetatr); + return; + } + + status = resolve_dfspath(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &fname); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + END_PROFILE(SMBgetatr); + return; + } + reply_nterror(req, status); + END_PROFILE(SMBgetatr); + return; } /* dos smetimes asks for a stat of "" - it returns a "hidden directory" @@ -1083,47 +1028,38 @@ void reply_getatr(struct smb_request *req) size = 0; mtime = 0; } else { - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); + status = unix_convert(ctx, conn, fname, False, &fname, NULL,&sbuf); if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - goto out; - } reply_nterror(req, status); - goto out; + END_PROFILE(SMBgetatr); + return; } - if (!VALID_STAT(smb_fname->st) && - (SMB_VFS_STAT(conn, smb_fname) != 0)) { - DEBUG(3,("reply_getatr: stat of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_nterror(req, map_nt_error_from_unix(errno)); - goto out; + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status))); + reply_nterror(req, status); + END_PROFILE(SMBgetatr); + return; } + if (!VALID_STAT(sbuf)) { + int ret; - mode = dos_mode(conn, smb_fname); - size = smb_fname->st.st_ex_size; - - if (ask_sharemode) { - struct timespec write_time_ts; - struct file_id fileid; - - ZERO_STRUCT(write_time_ts); - fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); - get_file_infos(fileid, NULL, &write_time_ts); - if (!null_timespec(write_time_ts)) { - update_stat_ex_mtime(&smb_fname->st, write_time_ts); + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(conn,fname,&sbuf); + } else { + ret = SMB_VFS_STAT(conn,fname,&sbuf); + } + if (ret != 0) { + DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req, ERRDOS,ERRbadfile); + END_PROFILE(SMBgetatr); + return; } } - mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime); + mode = dos_mode(conn,fname,&sbuf); + size = sbuf.st_size; + mtime = sbuf.st_mtime; if (mode & aDIR) { size = 0; } @@ -1139,17 +1075,13 @@ void reply_getatr(struct smb_request *req) } SIVAL(req->outbuf,smb_vwv3,(uint32)size); - if (get_Protocol() >= PROTOCOL_NT1) { + if (Protocol >= PROTOCOL_NT1) { SSVAL(req->outbuf, smb_flg2, SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME); } - DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", - smb_fname_str_dbg(smb_fname), mode, (unsigned int)size)); + DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) ); - out: - TALLOC_FREE(smb_fname); - TALLOC_FREE(fname); END_PROFILE(SMBgetatr); return; } @@ -1162,10 +1094,10 @@ void reply_setatr(struct smb_request *req) { struct smb_file_time ft; connection_struct *conn = req->conn; - struct smb_filename *smb_fname = NULL; char *fname = NULL; int mode; time_t mtime; + SMB_STRUCT_STAT sbuf; const char *p; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); @@ -1176,72 +1108,86 @@ void reply_setatr(struct smb_request *req) if (req->wct < 2) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } p = (const char *)req->buf + 1; p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBsetatr); + return; } - status = filename_convert(ctx, - conn, + status = resolve_dfspath(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - 0, - NULL, - &smb_fname); + &fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBsetatr); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBsetatr); + return; + } + + status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBsetatr); + return; + } + + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBsetatr); + return; } - if (smb_fname->base_name[0] == '.' && - smb_fname->base_name[1] == '\0') { + if (fname[0] == '.' && fname[1] == '\0') { /* * Not sure here is the right place to catch this * condition. Might be moved to somewhere else later -- vl */ reply_nterror(req, NT_STATUS_ACCESS_DENIED); - goto out; + END_PROFILE(SMBsetatr); + return; } mode = SVAL(req->vwv+0, 0); mtime = srv_make_unix_date3(req->vwv+1); ft.mtime = convert_time_t_to_timespec(mtime); - status = smb_set_file_time(conn, NULL, smb_fname, &ft, true); + status = smb_set_file_time(conn, NULL, fname, + &sbuf, &ft, true); if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; + reply_unixerror(req, ERRDOS, ERRnoaccess); + END_PROFILE(SMBsetatr); + return; } if (mode != FILE_ATTRIBUTE_NORMAL) { - if (VALID_STAT_OF_DIR(smb_fname->st)) + if (VALID_STAT_OF_DIR(sbuf)) mode |= aDIR; else mode &= ~aDIR; - if (file_set_dosmode(conn, smb_fname, mode, NULL, - false) != 0) { - reply_nterror(req, map_nt_error_from_unix(errno)); - goto out; + if (file_set_dosmode(conn,fname,mode,&sbuf,NULL,false) != 0) { + reply_unixerror(req, ERRDOS, ERRnoaccess); + END_PROFILE(SMBsetatr); + return; } } reply_outbuf(req, 0, 0); - DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname), - mode)); - out: - TALLOC_FREE(smb_fname); + DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) ); + END_PROFILE(SMBsetatr); return; } @@ -1257,14 +1203,14 @@ void reply_dskattr(struct smb_request *req) START_PROFILE(SMBdskattr); if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (uint64_t)-1) { - reply_nterror(req, map_nt_error_from_unix(errno)); + reply_unixerror(req, ERRHRD, ERRgeneral); END_PROFILE(SMBdskattr); return; } reply_outbuf(req, 5, 0); - if (get_Protocol() <= PROTOCOL_LANMAN2) { + if (Protocol <= PROTOCOL_LANMAN2) { double total_space, free_space; /* we need to scale this to a number that DOS6 can handle. We use floating point so we can handle large drives on systems @@ -1298,38 +1244,6 @@ void reply_dskattr(struct smb_request *req) return; } -/* - * Utility function to split the filename from the directory. - */ -static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in, - char **fname_dir_out, - char **fname_mask_out) -{ - const char *p = NULL; - char *fname_dir = NULL; - char *fname_mask = NULL; - - p = strrchr_m(fname_in, '/'); - if (!p) { - fname_dir = talloc_strdup(ctx, "."); - fname_mask = talloc_strdup(ctx, fname_in); - } else { - fname_dir = talloc_strndup(ctx, fname_in, - PTR_DIFF(p, fname_in)); - fname_mask = talloc_strdup(ctx, p+1); - } - - if (!fname_dir || !fname_mask) { - TALLOC_FREE(fname_dir); - TALLOC_FREE(fname_mask); - return NT_STATUS_NO_MEMORY; - } - - *fname_dir_out = fname_dir; - *fname_mask_out = fname_mask; - return NT_STATUS_OK; -} - /**************************************************************************** Reply to a search. Can be called from SMBsearch, SMBffirst or SMBfunique. @@ -1338,20 +1252,19 @@ static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in, void reply_search(struct smb_request *req) { connection_struct *conn = req->conn; - char *path = NULL; const char *mask = NULL; char *directory = NULL; - struct smb_filename *smb_fname = NULL; char *fname = NULL; SMB_OFF_T size; uint32 mode; - struct timespec date; + time_t date; uint32 dirtype; unsigned int numentries = 0; unsigned int maxentries = 0; bool finished = False; const char *p; int status_len; + char *path = NULL; char status[21]; int dptr_num= -1; bool check_descend = False; @@ -1361,19 +1274,19 @@ void reply_search(struct smb_request *req) bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False; TALLOC_CTX *ctx = talloc_tos(); bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); - struct dptr_struct *dirptr = NULL; - struct smbd_server_connection *sconn = smbd_server_conn; START_PROFILE(SMBsearch); if (req->wct < 2) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBsearch); + return; } if (lp_posix_pathnames()) { reply_unknown_new(req, req->cmd); - goto out; + END_PROFILE(SMBsearch); + return; } /* If we were called as SMBffirst then we must expect close. */ @@ -1389,7 +1302,25 @@ void reply_search(struct smb_request *req) &nt_status, &mask_contains_wcard); if (!NT_STATUS_IS_OK(nt_status)) { reply_nterror(req, nt_status); - goto out; + END_PROFILE(SMBsearch); + return; + } + + nt_status = resolve_dfspath_wcard(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + path, + &path, + &mask_contains_wcard); + if (!NT_STATUS_IS_OK(nt_status)) { + if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + END_PROFILE(SMBsearch); + return; + } + reply_nterror(req, nt_status); + END_PROFILE(SMBsearch); + return; } p++; @@ -1399,23 +1330,22 @@ void reply_search(struct smb_request *req) /* dirtype &= ~aDIR; */ if (status_len == 0) { - nt_status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - path, - UCF_ALWAYS_ALLOW_WCARD_LCOMP, - &mask_contains_wcard, - &smb_fname); + SMB_STRUCT_STAT sbuf; + + nt_status = unix_convert(ctx, conn, path, True, + &directory, NULL, &sbuf); if (!NT_STATUS_IS_OK(nt_status)) { - if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - goto out; - } reply_nterror(req, nt_status); - goto out; + END_PROFILE(SMBsearch); + return; } - directory = smb_fname->base_name; + nt_status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(nt_status)) { + reply_nterror(req, nt_status); + END_PROFILE(SMBsearch); + return; + } p = strrchr_m(directory,'/'); if ((p != NULL) && (*directory != '/')) { @@ -1429,7 +1359,8 @@ void reply_search(struct smb_request *req) if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBsearch); + return; } memset((char *)status,'\0',21); @@ -1443,15 +1374,15 @@ void reply_search(struct smb_request *req) mask, mask_contains_wcard, dirtype, - &dirptr); + &conn->dirptr); if (!NT_STATUS_IS_OK(nt_status)) { reply_nterror(req, nt_status); - goto out; + END_PROFILE(SMBsearch); + return; } - dptr_num = dptr_dnum(dirptr); + dptr_num = dptr_dnum(conn->dirptr); } else { int status_dirtype; - const char *dirpath; memcpy(status,p,21); status_dirtype = CVAL(status,0) & 0x1F; @@ -1459,18 +1390,12 @@ void reply_search(struct smb_request *req) dirtype = status_dirtype; } - dirptr = dptr_fetch(sconn, status+12,&dptr_num); - if (!dirptr) { + conn->dirptr = dptr_fetch(status+12,&dptr_num); + if (!conn->dirptr) { goto SearchEmpty; } - dirpath = dptr_path(sconn, dptr_num); - directory = talloc_strdup(ctx, dirpath); - if (!directory) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; - } - - mask = dptr_wcard(sconn, dptr_num); + string_set(&conn->dirpath,dptr_path(dptr_num)); + mask = dptr_wcard(dptr_num); if (!mask) { goto SearchEmpty; } @@ -1479,13 +1404,13 @@ void reply_search(struct smb_request *req) * check from the initial saved string. */ mask_contains_wcard = ms_has_wild(mask); - dirtype = dptr_attr(sconn, dptr_num); + dirtype = dptr_attr(dptr_num); } DEBUG(4,("dptr_num is %d\n",dptr_num)); /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */ - dptr_init_search_op(dirptr); + dptr_init_search_op(conn->dirptr); if ((dirtype&0x1F) == aVOLID) { char buf[DIR_STRUCT_SIZE]; @@ -1493,9 +1418,10 @@ void reply_search(struct smb_request *req) if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)), 0,aVOLID,0,!allow_long_path_components)) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBsearch); + return; } - dptr_fill(sconn, buf+12,dptr_num); + dptr_fill(buf+12,dptr_num); if (dptr_zero(buf+12) && (status_len==0)) { numentries = 1; } else { @@ -1505,7 +1431,8 @@ void reply_search(struct smb_request *req) data_blob_const(buf, sizeof(buf))) == -1) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBsearch); + return; } } else { unsigned int i; @@ -1516,14 +1443,14 @@ void reply_search(struct smb_request *req) /DIR_STRUCT_SIZE)); DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", - directory,lp_dontdescend(SNUM(conn)))); - if (in_list(directory, lp_dontdescend(SNUM(conn)),True)) { + conn->dirpath,lp_dontdescend(SNUM(conn)))); + if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True)) { check_descend = True; } for (i=numentries;(i<maxentries) && !finished;i++) { finished = !get_dir_entry(ctx, - dirptr, + conn, mask, dirtype, &fname, @@ -1541,19 +1468,21 @@ void reply_search(struct smb_request *req) fname, size, mode, - convert_timespec_to_time_t(date), + date, !allow_long_path_components)) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBsearch); + return; } - if (!dptr_fill(sconn, buf+12,dptr_num)) { + if (!dptr_fill(buf+12,dptr_num)) { break; } if (message_push_blob(&req->outbuf, data_blob_const(buf, sizeof(buf))) == -1) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBsearch); + return; } numentries++; } @@ -1567,20 +1496,21 @@ void reply_search(struct smb_request *req) (X/Open spec) */ if (numentries == 0) { - dptr_close(sconn, &dptr_num); + dptr_close(&dptr_num); } else if(expect_close && status_len == 0) { /* Close the dptr - we know it's gone */ - dptr_close(sconn, &dptr_num); + dptr_close(&dptr_num); } /* If we were called as SMBfunique, then we can close the dirptr now ! */ if(dptr_num >= 0 && req->cmd == SMBfunique) { - dptr_close(sconn, &dptr_num); + dptr_close(&dptr_num); } if ((numentries == 0) && !mask_contains_wcard) { reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles); - goto out; + END_PROFILE(SMBsearch); + return; } SSVAL(req->outbuf,smb_vwv0,numentries); @@ -1601,16 +1531,18 @@ void reply_search(struct smb_request *req) SSVAL(req->outbuf, smb_flg2, (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS))); + if (!directory) { + directory = dptr_path(dptr_num); + } + DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n", smb_fn_name(req->cmd), mask, - directory, + directory ? directory : "./", dirtype, numentries, maxentries )); - out: - TALLOC_FREE(directory); - TALLOC_FREE(smb_fname); + END_PROFILE(SMBsearch); return; } @@ -1629,7 +1561,6 @@ void reply_fclose(struct smb_request *req) NTSTATUS err; bool path_contains_wcard = False; TALLOC_CTX *ctx = talloc_tos(); - struct smbd_server_connection *sconn = smbd_server_conn; START_PROFILE(SMBfclose); @@ -1652,16 +1583,16 @@ void reply_fclose(struct smb_request *req) p += 2; if (status_len == 0) { - reply_force_doserror(req, ERRSRV, ERRsrverror); + reply_doserror(req, ERRSRV, ERRsrverror); END_PROFILE(SMBfclose); return; } memcpy(status,p,21); - if(dptr_fetch(sconn, status+12,&dptr_num)) { + if(dptr_fetch(status+12,&dptr_num)) { /* Close the dptr - we know it's gone */ - dptr_close(sconn, &dptr_num); + dptr_close(&dptr_num); } reply_outbuf(req, 1, 0); @@ -1680,12 +1611,12 @@ void reply_fclose(struct smb_request *req) void reply_open(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname = NULL; char *fname = NULL; uint32 fattr=0; SMB_OFF_T size = 0; time_t mtime=0; int info; + SMB_STRUCT_STAT sbuf; files_struct *fsp; int oplock_request; int deny_mode; @@ -1695,14 +1626,16 @@ void reply_open(struct smb_request *req) uint32 create_disposition; uint32 create_options = 0; NTSTATUS status; - bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); TALLOC_CTX *ctx = talloc_tos(); START_PROFILE(SMBopen); + SET_STAT_INVALID(sbuf); + if (req->wct < 2) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBopen); + return; } oplock_request = CORE_OPLOCK_REQUEST(req->inbuf); @@ -1713,40 +1646,24 @@ void reply_open(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; - } - - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - goto out; - } - reply_nterror(req, status); - goto out; + END_PROFILE(SMBopen); + return; } - if (!map_open_params_to_ntcreate(smb_fname, deny_mode, - OPENX_FILE_EXISTS_OPEN, &access_mask, - &share_mode, &create_disposition, - &create_options)) { - reply_force_doserror(req, ERRDOS, ERRbadaccess); - goto out; + if (!map_open_params_to_ntcreate( + fname, deny_mode, OPENX_FILE_EXISTS_OPEN, &access_mask, + &share_mode, &create_disposition, &create_options)) { + reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess)); + END_PROFILE(SMBopen); + return; } status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + CFF_DOS_PATH, /* create_file_flags */ access_mask, /* access_mask */ share_mode, /* share_access */ create_disposition, /* create_disposition*/ @@ -1757,41 +1674,30 @@ void reply_open(struct smb_request *req) NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + &sbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - goto out; + END_PROFILE(SMBopen); + return; } reply_openerror(req, status); - goto out; - } - - size = smb_fname->st.st_ex_size; - fattr = dos_mode(conn, smb_fname); - - /* Deal with other possible opens having a modified - write time. JRA. */ - if (ask_sharemode) { - struct timespec write_time_ts; - - ZERO_STRUCT(write_time_ts); - get_file_infos(fsp->file_id, NULL, &write_time_ts); - if (!null_timespec(write_time_ts)) { - update_stat_ex_mtime(&smb_fname->st, write_time_ts); - } + END_PROFILE(SMBopen); + return; } - mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime); + size = sbuf.st_size; + fattr = dos_mode(conn,fsp->fsp_name,&sbuf); + mtime = sbuf.st_mtime; if (fattr & aDIR) { - DEBUG(3,("attempt to open a directory %s\n", - fsp_str_dbg(fsp))); + DEBUG(3,("attempt to open a directory %s\n",fsp->fsp_name)); close_file(req, fsp, ERROR_CLOSE); - reply_botherror(req, NT_STATUS_ACCESS_DENIED, - ERRDOS, ERRnoaccess); - goto out; + reply_doserror(req, ERRDOS,ERRnoaccess); + END_PROFILE(SMBopen); + return; } reply_outbuf(req, 7, 0); @@ -1814,8 +1720,6 @@ void reply_open(struct smb_request *req) SCVAL(req->outbuf,smb_flg, CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } - out: - TALLOC_FREE(smb_fname); END_PROFILE(SMBopen); return; } @@ -1827,7 +1731,6 @@ void reply_open(struct smb_request *req) void reply_open_and_X(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname = NULL; char *fname = NULL; uint16 open_flags; int deny_mode; @@ -1844,6 +1747,7 @@ void reply_open_and_X(struct smb_request *req) int smb_ofun; uint32 fattr=0; int mtime=0; + SMB_STRUCT_STAT sbuf; int smb_action = 0; files_struct *fsp; NTSTATUS status; @@ -1859,9 +1763,12 @@ void reply_open_and_X(struct smb_request *req) if (req->wct < 15) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBopenX); + return; } + SET_STAT_INVALID(sbuf); + open_flags = SVAL(req->vwv+2, 0); deny_mode = SVAL(req->vwv+3, 0); smb_attr = SVAL(req->vwv+5, 0); @@ -1876,9 +1783,10 @@ void reply_open_and_X(struct smb_request *req) if (lp_nt_pipe_support()) { reply_open_pipe_and_X(conn, req); } else { - reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED); + reply_doserror(req, ERRSRV, ERRaccess); } - goto out; + END_PROFILE(SMBopenX); + return; } /* XXXX we need to handle passed times, sattr and flags */ @@ -1886,40 +1794,24 @@ void reply_open_and_X(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; - } - - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - goto out; - } - reply_nterror(req, status); - goto out; + END_PROFILE(SMBopenX); + return; } - if (!map_open_params_to_ntcreate(smb_fname, deny_mode, smb_ofun, - &access_mask, &share_mode, - &create_disposition, - &create_options)) { - reply_force_doserror(req, ERRDOS, ERRbadaccess); - goto out; + if (!map_open_params_to_ntcreate( + fname, deny_mode, smb_ofun, &access_mask, + &share_mode, &create_disposition, &create_options)) { + reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess)); + END_PROFILE(SMBopenX); + return; } status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + CFF_DOS_PATH, /* create_file_flags */ access_mask, /* access_mask */ share_mode, /* share_access */ create_disposition, /* create_disposition*/ @@ -1930,15 +1822,17 @@ void reply_open_and_X(struct smb_request *req) NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &smb_action); /* pinfo */ + &smb_action, /* pinfo */ + &sbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBopenX); if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - goto out; + return; } reply_openerror(req, status); - goto out; + return; } /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size, @@ -1948,24 +1842,26 @@ void reply_open_and_X(struct smb_request *req) if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { close_file(req, fsp, ERROR_CLOSE); reply_nterror(req, NT_STATUS_DISK_FULL); - goto out; + END_PROFILE(SMBopenX); + return; } retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size); if (retval < 0) { close_file(req, fsp, ERROR_CLOSE); reply_nterror(req, NT_STATUS_DISK_FULL); - goto out; + END_PROFILE(SMBopenX); + return; } - smb_fname->st.st_ex_size = - SMB_VFS_GET_ALLOC_SIZE(conn, fsp, &smb_fname->st); + sbuf.st_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf); } - fattr = dos_mode(conn, smb_fname); - mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime); + fattr = dos_mode(conn,fsp->fsp_name,&sbuf); + mtime = sbuf.st_mtime; if (fattr & aDIR) { close_file(req, fsp, ERROR_CLOSE); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - goto out; + reply_doserror(req, ERRDOS, ERRnoaccess); + END_PROFILE(SMBopenX); + return; } /* If the caller set the extended oplock request bit @@ -2009,7 +1905,7 @@ void reply_open_and_X(struct smb_request *req) } else { srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime); } - SIVAL(req->outbuf,smb_vwv6,(uint32)smb_fname->st.st_ex_size); + SIVAL(req->outbuf,smb_vwv6,(uint32)sbuf.st_size); SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode)); SSVAL(req->outbuf,smb_vwv11,smb_action); @@ -2017,10 +1913,8 @@ void reply_open_and_X(struct smb_request *req) SIVAL(req->outbuf, smb_vwv15, STD_RIGHT_ALL_ACCESS); } - chain_reply(req); - out: - TALLOC_FREE(smb_fname); END_PROFILE(SMBopenX); + chain_reply(req); return; } @@ -2030,12 +1924,11 @@ void reply_open_and_X(struct smb_request *req) void reply_ulogoffX(struct smb_request *req) { - struct smbd_server_connection *sconn = smbd_server_conn; user_struct *vuser; START_PROFILE(SMBulogoffX); - vuser = get_valid_user_struct(sconn, req->vuid); + vuser = get_valid_user_struct(req->vuid); if(vuser == NULL) { DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", @@ -2048,7 +1941,7 @@ void reply_ulogoffX(struct smb_request *req) file_close_user(req->vuid); } - invalidate_vuid(sconn, req->vuid); + invalidate_vuid(req->vuid); reply_outbuf(req, 2, 0); @@ -2066,12 +1959,12 @@ void reply_ulogoffX(struct smb_request *req) void reply_mknew(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname = NULL; char *fname = NULL; uint32 fattr = 0; struct smb_file_time ft; files_struct *fsp; int oplock_request = 0; + SMB_STRUCT_STAT sbuf; NTSTATUS status; uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE; uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE; @@ -2081,10 +1974,12 @@ void reply_mknew(struct smb_request *req) START_PROFILE(SMBcreate); ZERO_STRUCT(ft); + SET_STAT_INVALID(sbuf); if (req->wct < 3) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBcreate); + return; } fattr = SVAL(req->vwv+0, 0); @@ -2097,31 +1992,13 @@ void reply_mknew(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; - } - - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - goto out; - } - reply_nterror(req, status); - goto out; + END_PROFILE(SMBcreate); + return; } if (fattr & aVOLID) { DEBUG(0,("Attempt to create file (%s) with volid set - " - "please report this\n", - smb_fname_str_dbg(smb_fname))); + "please report this\n", fname)); } if(req->cmd == SMBmknew) { @@ -2136,7 +2013,8 @@ void reply_mknew(struct smb_request *req) conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + CFF_DOS_PATH, /* create_file_flags */ access_mask, /* access_mask */ share_mode, /* share_access */ create_disposition, /* create_disposition*/ @@ -2147,22 +2025,25 @@ void reply_mknew(struct smb_request *req) NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + &sbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcreate); if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - goto out; + return; } reply_openerror(req, status); - goto out; + return; } - ft.atime = smb_fname->st.st_ex_atime; /* atime. */ - status = smb_set_file_time(conn, fsp, smb_fname, &ft, true); + ft.atime = get_atimespec(&sbuf); /* atime. */ + status = smb_set_file_time(conn, fsp, fsp->fsp_name, &sbuf, &ft, true); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcreate); - goto out; + reply_openerror(req, status); + return; } reply_outbuf(req, 1, 0); @@ -2178,13 +2059,10 @@ void reply_mknew(struct smb_request *req) CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } - DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname))); - DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n", - smb_fname_str_dbg(smb_fname), fsp->fh->fd, - (unsigned int)fattr)); + DEBUG( 2, ( "reply_mknew: file %s\n", fsp->fsp_name ) ); + DEBUG( 3, ( "reply_mknew %s fd=%d dmode=0x%x\n", + fsp->fsp_name, fsp->fh->fd, (unsigned int)fattr ) ); - out: - TALLOC_FREE(smb_fname); END_PROFILE(SMBcreate); return; } @@ -2196,12 +2074,12 @@ void reply_mknew(struct smb_request *req) void reply_ctemp(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname = NULL; char *fname = NULL; uint32 fattr; files_struct *fsp; int oplock_request; int tmpfd; + SMB_STRUCT_STAT sbuf; char *s; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); @@ -2210,7 +2088,8 @@ void reply_ctemp(struct smb_request *req) if (req->wct < 3) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBctemp); + return; } fattr = SVAL(req->vwv+0, 0); @@ -2220,7 +2099,8 @@ void reply_ctemp(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBctemp); + return; } if (*fname) { fname = talloc_asprintf(ctx, @@ -2232,39 +2112,57 @@ void reply_ctemp(struct smb_request *req) if (!fname) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBctemp); + return; } - status = filename_convert(ctx, conn, + status = resolve_dfspath(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - 0, - NULL, - &smb_fname); + &fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBctemp); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBctemp); + return; } - tmpfd = mkstemp(smb_fname->base_name); + status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBctemp); + return; + } + + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBctemp); + return; + } + + tmpfd = smb_mkstemp(fname); if (tmpfd == -1) { - reply_nterror(req, map_nt_error_from_unix(errno)); - goto out; + reply_unixerror(req, ERRDOS, ERRnoaccess); + END_PROFILE(SMBctemp); + return; } - SMB_VFS_STAT(conn, smb_fname); + SET_STAT_INVALID(sbuf); + SMB_VFS_STAT(conn,fname,&sbuf); /* We should fail if file does not exist. */ status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + 0, /* create_file_flags */ FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */ FILE_OPEN, /* create_disposition*/ @@ -2275,27 +2173,30 @@ void reply_ctemp(struct smb_request *req) NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + &sbuf); /* psbuf */ - /* close fd from mkstemp() */ + /* close fd from smb_mkstemp() */ close(tmpfd); if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - goto out; + END_PROFILE(SMBctemp); + return; } reply_openerror(req, status); - goto out; + END_PROFILE(SMBctemp); + return; } reply_outbuf(req, 1, 0); SSVAL(req->outbuf,smb_vwv0,fsp->fnum); /* the returned filename is relative to the directory */ - s = strrchr_m(fsp->fsp_name->base_name, '/'); + s = strrchr_m(fsp->fsp_name, '/'); if (!s) { - s = fsp->fsp_name->base_name; + s = fsp->fsp_name; } else { s++; } @@ -2308,7 +2209,8 @@ void reply_ctemp(struct smb_request *req) if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE) == -1) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBctemp); + return; } if (oplock_request && lp_fake_oplocks(SNUM(conn))) { @@ -2321,11 +2223,10 @@ void reply_ctemp(struct smb_request *req) CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } - DEBUG(2, ("reply_ctemp: created temp file %s\n", fsp_str_dbg(fsp))); - DEBUG(3, ("reply_ctemp %s fd=%d umode=0%o\n", fsp_str_dbg(fsp), - fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode)); - out: - TALLOC_FREE(smb_fname); + DEBUG( 2, ( "reply_ctemp: created temp file %s\n", fsp->fsp_name ) ); + DEBUG( 3, ( "reply_ctemp %s fd=%d umode=0%o\n", fsp->fsp_name, + fsp->fh->fd, (unsigned int)sbuf.st_mode ) ); + END_PROFILE(SMBctemp); return; } @@ -2335,7 +2236,7 @@ void reply_ctemp(struct smb_request *req) ********************************************************************/ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp, - uint16 dirtype) + uint16 dirtype, SMB_STRUCT_STAT *pst) { uint32 fmode; @@ -2343,12 +2244,12 @@ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp, return NT_STATUS_MEDIA_WRITE_PROTECTED; } - fmode = dos_mode(conn, fsp->fsp_name); + fmode = dos_mode(conn, fsp->fsp_name, pst); if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) { return NT_STATUS_NO_SUCH_FILE; } - if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) { + if (S_ISDIR(pst->st_mode)) { if (fsp->posix_open) { return NT_STATUS_OK; } @@ -2375,34 +2276,33 @@ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp, static NTSTATUS do_unlink(connection_struct *conn, struct smb_request *req, - struct smb_filename *smb_fname, + const char *fname, uint32 dirtype) { + SMB_STRUCT_STAT sbuf; uint32 fattr; files_struct *fsp; uint32 dirtype_orig = dirtype; - NTSTATUS status; - int ret; bool posix_paths = lp_posix_pathnames(); + int ret; + NTSTATUS status; - DEBUG(10,("do_unlink: %s, dirtype = %d\n", - smb_fname_str_dbg(smb_fname), - dirtype)); + DEBUG(10,("do_unlink: %s, dirtype = %d\n", fname, dirtype )); if (!CAN_WRITE(conn)) { return NT_STATUS_MEDIA_WRITE_PROTECTED; } if (posix_paths) { - ret = SMB_VFS_LSTAT(conn, smb_fname); + ret = SMB_VFS_LSTAT(conn,fname,&sbuf); } else { - ret = SMB_VFS_LSTAT(conn, smb_fname); + ret = SMB_VFS_STAT(conn,fname,&sbuf); } if (ret != 0) { return map_nt_error_from_unix(errno); } - fattr = dos_mode(conn, smb_fname); + fattr = dos_mode(conn,fname,&sbuf); if (dirtype & FILE_ATTRIBUTE_NORMAL) { dirtype = aDIR|aARCH|aRONLY; @@ -2455,6 +2355,24 @@ static NTSTATUS do_unlink(connection_struct *conn, return NT_STATUS_OBJECT_NAME_INVALID; #endif /* JRATEST */ + /* Fix for bug #3035 from SATOH Fumiyasu <fumiyas@miraclelinux.com> + + On a Windows share, a file with read-only dosmode can be opened with + DELETE_ACCESS. But on a Samba share (delete readonly = no), it + fails with NT_STATUS_CANNOT_DELETE error. + + This semantic causes a problem that a user can not + rename a file with read-only dosmode on a Samba share + from a Windows command prompt (i.e. cmd.exe, but can rename + from Windows Explorer). + */ + + if (!lp_delete_readonly(SNUM(conn))) { + if (fattr & aRONLY) { + return NT_STATUS_CANNOT_DELETE; + } + } + /* On open checks the open itself will check the share mode, so don't do it here as we'll get it wrong. */ @@ -2462,12 +2380,13 @@ static NTSTATUS do_unlink(connection_struct *conn, (conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + 0, /* create_file_flags */ DELETE_ACCESS, /* access_mask */ FILE_SHARE_NONE, /* share_access */ FILE_OPEN, /* create_disposition*/ FILE_NON_DIRECTORY_FILE, /* create_options */ - /* file_attributes */ + /* file_attributes */ posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 : FILE_ATTRIBUTE_NORMAL, 0, /* oplock_request */ @@ -2475,7 +2394,8 @@ static NTSTATUS do_unlink(connection_struct *conn, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + &sbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n", @@ -2483,16 +2403,6 @@ static NTSTATUS do_unlink(connection_struct *conn, return status; } - status = can_set_delete_on_close(fsp, fattr); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - " - "(%s)\n", - smb_fname_str_dbg(smb_fname), - nt_errstr(status))); - close_file(req, fsp, NORMAL_CLOSE); - return status; - } - /* The set is across all open files on this dev/inode pair. */ if (!set_delete_on_close(fsp, True, &conn->server_info->utok)) { close_file(req, fsp, NORMAL_CLOSE); @@ -2508,20 +2418,33 @@ static NTSTATUS do_unlink(connection_struct *conn, ****************************************************************************/ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, - uint32 dirtype, struct smb_filename *smb_fname, - bool has_wild) + uint32 dirtype, const char *name_in, bool has_wild) { - char *fname_dir = NULL; - char *fname_mask = NULL; + const char *directory = NULL; + char *mask = NULL; + char *name = NULL; + char *p = NULL; int count=0; NTSTATUS status = NT_STATUS_OK; + SMB_STRUCT_STAT sbuf, st; TALLOC_CTX *ctx = talloc_tos(); - /* Split up the directory from the filename/mask. */ - status = split_fname_dir_mask(ctx, smb_fname->base_name, - &fname_dir, &fname_mask); + status = unix_convert(ctx, conn, name_in, has_wild, &name, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { - goto out; + return status; + } + + p = strrchr_m(name,'/'); + if (!p) { + directory = talloc_strdup(ctx, "."); + if (!directory) { + return NT_STATUS_NO_MEMORY; + } + mask = name; + } else { + *p = 0; + directory = name; + mask = p+1; } /* @@ -2533,77 +2456,63 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!VALID_STAT(smb_fname->st) && - mangle_is_mangled(fname_mask, conn->params)) { + if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) { char *new_mask = NULL; - mangle_lookup_name_from_8_3(ctx, fname_mask, - &new_mask, conn->params); + mangle_lookup_name_from_8_3(ctx, + mask, + &new_mask, + conn->params ); if (new_mask) { - TALLOC_FREE(fname_mask); - fname_mask = new_mask; + mask = new_mask; } } if (!has_wild) { - - /* - * Only one file needs to be unlinked. Append the mask back - * onto the directory. - */ - TALLOC_FREE(smb_fname->base_name); - smb_fname->base_name = talloc_asprintf(smb_fname, - "%s/%s", - fname_dir, - fname_mask); - if (!smb_fname->base_name) { - status = NT_STATUS_NO_MEMORY; - goto out; + directory = talloc_asprintf(ctx, + "%s/%s", + directory, + mask); + if (!directory) { + return NT_STATUS_NO_MEMORY; } if (dirtype == 0) { dirtype = FILE_ATTRIBUTE_NORMAL; } - status = check_name(conn, smb_fname->base_name); + status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { - goto out; + return status; } - status = do_unlink(conn, req, smb_fname, dirtype); + status = do_unlink(conn, req, directory, dirtype); if (!NT_STATUS_IS_OK(status)) { - goto out; + return status; } count++; } else { struct smb_Dir *dir_hnd = NULL; long offset = 0; - const char *dname = NULL; - char *talloced = NULL; + const char *dname; if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) { - status = NT_STATUS_OBJECT_NAME_INVALID; - goto out; + return NT_STATUS_OBJECT_NAME_INVALID; } - if (strequal(fname_mask,"????????.???")) { - TALLOC_FREE(fname_mask); - fname_mask = talloc_strdup(ctx, "*"); - if (!fname_mask) { - status = NT_STATUS_NO_MEMORY; - goto out; - } + if (strequal(mask,"????????.???")) { + mask[0] = '*'; + mask[1] = '\0'; } - status = check_name(conn, fname_dir); + status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { - goto out; + return status; } - dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask, + dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, dirtype); if (dir_hnd == NULL) { - status = map_nt_error_from_unix(errno); - goto out; + return map_nt_error_from_unix(errno); } /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then @@ -2613,65 +2522,48 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, status = NT_STATUS_NO_SUCH_FILE; - while ((dname = ReadDirName(dir_hnd, &offset, - &smb_fname->st, &talloced))) { - TALLOC_CTX *frame = talloc_stackframe(); + while ((dname = ReadDirName(dir_hnd, &offset, &st))) { + char *fname = NULL; - if (!is_visible_file(conn, fname_dir, dname, - &smb_fname->st, true)) { - TALLOC_FREE(frame); - TALLOC_FREE(talloced); + if (!is_visible_file(conn, directory, dname, &st, + true)) + { continue; } /* Quick check for "." and ".." */ if (ISDOT(dname) || ISDOTDOT(dname)) { - TALLOC_FREE(frame); - TALLOC_FREE(talloced); continue; } - if(!mask_match(dname, fname_mask, - conn->case_sensitive)) { - TALLOC_FREE(frame); - TALLOC_FREE(talloced); + if(!mask_match(dname, mask, conn->case_sensitive)) { continue; } - TALLOC_FREE(smb_fname->base_name); - smb_fname->base_name = - talloc_asprintf(smb_fname, "%s/%s", - fname_dir, dname); - - if (!smb_fname->base_name) { - TALLOC_FREE(dir_hnd); - status = NT_STATUS_NO_MEMORY; - TALLOC_FREE(frame); - TALLOC_FREE(talloced); - goto out; + fname = talloc_asprintf(ctx, "%s/%s", + directory, + dname); + if (!fname) { + return NT_STATUS_NO_MEMORY; } - status = check_name(conn, smb_fname->base_name); + status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(dir_hnd); - TALLOC_FREE(frame); - TALLOC_FREE(talloced); - goto out; + return status; } - status = do_unlink(conn, req, smb_fname, dirtype); + status = do_unlink(conn, req, fname, dirtype); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(frame); - TALLOC_FREE(talloced); + TALLOC_FREE(fname); continue; } count++; DEBUG(3,("unlink_internals: successful unlink [%s]\n", - smb_fname->base_name)); + fname)); - TALLOC_FREE(frame); - TALLOC_FREE(talloced); + TALLOC_FREE(fname); } TALLOC_FREE(dir_hnd); } @@ -2680,9 +2572,6 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, status = map_nt_error_from_unix(errno); } - out: - TALLOC_FREE(fname_dir); - TALLOC_FREE(fname_mask); return status; } @@ -2694,7 +2583,6 @@ void reply_unlink(struct smb_request *req) { connection_struct *conn = req->conn; char *name = NULL; - struct smb_filename *smb_fname = NULL; uint32 dirtype; NTSTATUS status; bool path_contains_wcard = False; @@ -2704,7 +2592,8 @@ void reply_unlink(struct smb_request *req) if (req->wct < 1) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBunlink); + return; } dirtype = SVAL(req->vwv+0, 0); @@ -2714,42 +2603,45 @@ void reply_unlink(struct smb_request *req) &path_contains_wcard); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBunlink); + return; } - status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - name, - UCF_COND_ALLOW_WCARD_LCOMP, - &path_contains_wcard, - &smb_fname); + status = resolve_dfspath_wcard(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + name, + &name, + &path_contains_wcard); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBunlink); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBunlink); + return; } - DEBUG(3,("reply_unlink : %s\n", smb_fname_str_dbg(smb_fname))); + DEBUG(3,("reply_unlink : %s\n",name)); - status = unlink_internals(conn, req, dirtype, smb_fname, + status = unlink_internals(conn, req, dirtype, name, path_contains_wcard); if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - goto out; + END_PROFILE(SMBunlink); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBunlink); + return; } reply_outbuf(req, 0, 0); - out: - TALLOC_FREE(smb_fname); END_PROFILE(SMBunlink); + return; } @@ -2836,7 +2728,7 @@ static void sendfile_short_send(files_struct *fsp, if (nread < headersize) { DEBUG(0,("sendfile_short_send: sendfile failed to send " "header for file %s (%s). Terminating\n", - fsp_str_dbg(fsp), strerror(errno))); + fsp->fsp_name, strerror(errno) )); exit_server_cleanly("sendfile_short_send failed"); } @@ -2850,7 +2742,7 @@ static void sendfile_short_send(files_struct *fsp, } DEBUG(0,("sendfile_short_send: filling truncated file %s " - "with zeros !\n", fsp_str_dbg(fsp))); + "with zeros !\n", fsp->fsp_name)); while (nread < smb_maxcnt) { /* @@ -2917,8 +2809,7 @@ static void send_file_readbraw(connection_struct *conn, */ if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) && - (fsp->wcp == NULL) && - lp_use_sendfile(SNUM(conn), smbd_server_conn->smb1.signing_state) ) { + (fsp->wcp == NULL) && lp_use_sendfile(SNUM(conn)) ) { ssize_t sendfile_read = -1; char header[4]; DATA_BLOB header_blob; @@ -2945,19 +2836,15 @@ static void send_file_readbraw(connection_struct *conn, DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n")); if (fake_sendfile(fsp, startpos, nread) == -1) { - DEBUG(0,("send_file_readbraw: " - "fake_sendfile failed for " - "file %s (%s).\n", - fsp_str_dbg(fsp), - strerror(errno))); + DEBUG(0,("send_file_readbraw: fake_sendfile failed for file %s (%s).\n", + fsp->fsp_name, strerror(errno) )); exit_server_cleanly("send_file_readbraw fake_sendfile failed"); } return; } - DEBUG(0,("send_file_readbraw: sendfile failed for " - "file %s (%s). Terminating\n", - fsp_str_dbg(fsp), strerror(errno))); + DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n", + fsp->fsp_name, strerror(errno) )); exit_server_cleanly("send_file_readbraw sendfile failed"); } else if (sendfile_read == 0) { /* @@ -2969,7 +2856,7 @@ static void send_file_readbraw(connection_struct *conn, */ DEBUG(3, ("send_file_readbraw: sendfile sent zero " "bytes falling back to the normal read: " - "%s\n", fsp_str_dbg(fsp))); + "%s\n", fsp->fsp_name)); goto normal_readbraw; } @@ -3021,12 +2908,12 @@ void reply_readbraw(struct smb_request *req) SMB_OFF_T startpos; files_struct *fsp; struct lock_struct lock; + SMB_STRUCT_STAT st; SMB_OFF_T size = 0; START_PROFILE(SMBreadbraw); - if (srv_is_signing_active(smbd_server_conn) || - is_encrypted_packet(req->inbuf)) { + if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) { exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - " "raw reads/writes are disallowed."); } @@ -3112,7 +2999,7 @@ void reply_readbraw(struct smb_request *req) reply_readbraw_error(); END_PROFILE(SMBreadbraw); return; - } + } } maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF); @@ -3131,8 +3018,8 @@ void reply_readbraw(struct smb_request *req) return; } - if (fsp_stat(fsp) == 0) { - size = fsp->fsp_name->st.st_ex_size; + if (SMB_VFS_FSTAT(fsp, &st) == 0) { + size = st.st_size; } if (startpos >= size) { @@ -3181,7 +3068,6 @@ void reply_lockread(struct smb_request *req) files_struct *fsp; struct byte_range_lock *br_lck = NULL; char *p = NULL; - struct smbd_server_connection *sconn = smbd_server_conn; START_PROFILE(SMBlockread); @@ -3199,7 +3085,7 @@ void reply_lockread(struct smb_request *req) } if (!CHECK_READ(fsp,req)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRbadaccess); END_PROFILE(SMBlockread); return; } @@ -3244,17 +3130,16 @@ void reply_lockread(struct smb_request *req) * However the requested READ size IS affected by max_recv. Insanity.... JRA. */ - if (numtoread > sconn->smb1.negprot.max_recv) { + if (numtoread > max_recv) { DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \ Returning short read of maximum allowed for compatibility with Windows 2000.\n", - (unsigned int)numtoread, - (unsigned int)sconn->smb1.negprot.max_recv)); - numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv); + (unsigned int)numtoread, (unsigned int)max_recv )); + numtoread = MIN(numtoread,max_recv); } nread = read_file(fsp,data,startpos,numtoread); if (nread < 0) { - reply_nterror(req, map_nt_error_from_unix(errno)); + reply_unixerror(req, ERRDOS, ERRnoaccess); END_PROFILE(SMBlockread); return; } @@ -3291,7 +3176,6 @@ void reply_read(struct smb_request *req) int outsize = 0; files_struct *fsp; struct lock_struct lock; - struct smbd_server_connection *sconn = smbd_server_conn; START_PROFILE(SMBread); @@ -3309,7 +3193,7 @@ void reply_read(struct smb_request *req) } if (!CHECK_READ(fsp,req)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRbadaccess); END_PROFILE(SMBread); return; } @@ -3322,12 +3206,11 @@ void reply_read(struct smb_request *req) /* * The requested read size cannot be greater than max_recv. JRA. */ - if (numtoread > sconn->smb1.negprot.max_recv) { + if (numtoread > max_recv) { DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \ Returning short read of maximum allowed for compatibility with Windows 2000.\n", - (unsigned int)numtoread, - (unsigned int)sconn->smb1.negprot.max_recv)); - numtoread = MIN(numtoread, sconn->smb1.negprot.max_recv); + (unsigned int)numtoread, (unsigned int)max_recv )); + numtoread = MIN(numtoread,max_recv); } reply_outbuf(req, 5, numtoread+3); @@ -3339,7 +3222,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n", &lock); if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + reply_doserror(req, ERRDOS,ERRlock); END_PROFILE(SMBread); return; } @@ -3348,7 +3231,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n", nread = read_file(fsp,data,startpos,numtoread); if (nread < 0) { - reply_nterror(req, map_nt_error_from_unix(errno)); + reply_unixerror(req, ERRDOS,ERRnoaccess); goto strict_unlock; } @@ -3407,12 +3290,12 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt) { + SMB_STRUCT_STAT sbuf; ssize_t nread = -1; struct lock_struct lock; - int saved_errno = 0; - if(fsp_stat(fsp) == -1) { - reply_nterror(req, map_nt_error_from_unix(errno)); + if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + reply_unixerror(req, ERRDOS, ERRnoaccess); return; } @@ -3421,13 +3304,12 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, &lock); if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + reply_doserror(req, ERRDOS, ERRlock); return; } - if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) || - (startpos > fsp->fsp_name->st.st_ex_size) - || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) { + if (!S_ISREG(sbuf.st_mode) || (startpos > sbuf.st_size) + || (smb_maxcnt > (sbuf.st_size - startpos))) { /* * We already know that we would do a short read, so don't * try the sendfile() path. @@ -3444,8 +3326,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, if (!req_is_in_chain(req) && !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) && - (fsp->wcp == NULL) && - lp_use_sendfile(SNUM(conn), smbd_server_conn->smb1.signing_state) ) { + lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) { uint8 headerbuf[smb_size + 12 * 2]; DATA_BLOB header; @@ -3480,11 +3361,8 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, nread = fake_sendfile(fsp, startpos, smb_maxcnt); if (nread == -1) { - DEBUG(0,("send_file_readX: " - "fake_sendfile failed for " - "file %s (%s).\n", - fsp_str_dbg(fsp), - strerror(errno))); + DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n", + fsp->fsp_name, strerror(errno) )); exit_server_cleanly("send_file_readX: fake_sendfile failed"); } DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n", @@ -3493,9 +3371,8 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, goto strict_unlock; } - DEBUG(0,("send_file_readX: sendfile failed for file " - "%s (%s). Terminating\n", fsp_str_dbg(fsp), - strerror(errno))); + DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n", + fsp->fsp_name, strerror(errno) )); exit_server_cleanly("send_file_readX sendfile failed"); } else if (nread == 0) { /* @@ -3507,7 +3384,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, */ DEBUG(3, ("send_file_readX: sendfile sent zero bytes " "falling back to the normal read: %s\n", - fsp_str_dbg(fsp))); + fsp->fsp_name)); goto normal_read; } @@ -3537,16 +3414,14 @@ normal_read: /* Send out the header. */ if (write_data(smbd_server_fd(), (char *)headerbuf, sizeof(headerbuf)) != sizeof(headerbuf)) { - DEBUG(0,("send_file_readX: write_data failed for file " - "%s (%s). Terminating\n", fsp_str_dbg(fsp), - strerror(errno))); + DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n", + fsp->fsp_name, strerror(errno) )); exit_server_cleanly("send_file_readX sendfile failed"); } nread = fake_sendfile(fsp, startpos, smb_maxcnt); if (nread == -1) { - DEBUG(0,("send_file_readX: fake_sendfile failed for " - "file %s (%s).\n", fsp_str_dbg(fsp), - strerror(errno))); + DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n", + fsp->fsp_name, strerror(errno) )); exit_server_cleanly("send_file_readX: fake_sendfile failed"); } goto strict_unlock; @@ -3557,12 +3432,11 @@ nosendfile_read: reply_outbuf(req, 12, smb_maxcnt); nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt); - saved_errno = errno; SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); if (nread < 0) { - reply_nterror(req, map_nt_error_from_unix(saved_errno)); + reply_unixerror(req, ERRDOS, ERRnoaccess); return; } @@ -3619,7 +3493,7 @@ void reply_read_and_X(struct smb_request *req) } if (!CHECK_READ(fsp,req)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS,ERRbadaccess); END_PROFILE(SMBreadX); return; } @@ -3635,8 +3509,7 @@ void reply_read_and_X(struct smb_request *req) return; } /* We currently don't do this on signed or sealed data. */ - if (srv_is_signing_active(smbd_server_conn) || - is_encrypted_packet(req->inbuf)) { + if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) { reply_nterror(req, NT_STATUS_NOT_SUPPORTED); END_PROFILE(SMBreadX); return; @@ -3670,7 +3543,7 @@ void reply_read_and_X(struct smb_request *req) "used and we don't support 64 bit offsets.\n", (unsigned int)IVAL(req->vwv+10, 0) )); END_PROFILE(SMBreadX); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRbadaccess); return; } @@ -3732,7 +3605,7 @@ void reply_writebraw(struct smb_request *req) */ SCVAL(req->inbuf,smb_com,SMBwritec); - if (srv_is_signing_active(smbd_server_conn)) { + if (srv_is_signing_active()) { END_PROFILE(SMBwritebraw); exit_server_cleanly("reply_writebraw: SMB signing is active - " "raw reads/writes are disallowed."); @@ -3753,7 +3626,7 @@ void reply_writebraw(struct smb_request *req) } if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRbadaccess); error_to_writebrawerr(req); END_PROFILE(SMBwritebraw); return; @@ -3766,7 +3639,7 @@ void reply_writebraw(struct smb_request *req) /* We have to deal with slightly different formats depending on whether we are using the core+ or lanman1.0 protocol */ - if(get_Protocol() <= PROTOCOL_COREPLUS) { + if(Protocol <= PROTOCOL_COREPLUS) { numtowrite = SVAL(smb_buf(req->inbuf),-2); data = smb_buf(req->inbuf); } else { @@ -3787,7 +3660,7 @@ void reply_writebraw(struct smb_request *req) &lock); if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + reply_doserror(req, ERRDOS, ERRlock); error_to_writebrawerr(req); END_PROFILE(SMBwritebraw); return; @@ -3803,7 +3676,7 @@ void reply_writebraw(struct smb_request *req) (int)nwritten, (int)write_through)); if (nwritten < (ssize_t)numtowrite) { - reply_nterror(req, NT_STATUS_DISK_FULL); + reply_unixerror(req, ERRHRD, ERRdiskfull); error_to_writebrawerr(req); goto strict_unlock; } @@ -3813,7 +3686,7 @@ void reply_writebraw(struct smb_request *req) /* Allocate a buffer of 64k + length. */ buf = TALLOC_ARRAY(NULL, char, 65540); if (!buf) { - reply_nterror(req, NT_STATUS_NO_MEMORY); + reply_doserror(req, ERRDOS, ERRnomem); error_to_writebrawerr(req); goto strict_unlock; } @@ -3822,15 +3695,14 @@ void reply_writebraw(struct smb_request *req) * it to send more bytes */ memcpy(buf, req->inbuf, smb_size); - srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True); + srv_set_message(buf,Protocol>PROTOCOL_COREPLUS?1:0,0,True); SCVAL(buf,smb_com,SMBwritebraw); SSVALS(buf,smb_vwv0,0xFFFF); show_msg(buf); if (!srv_send_smb(smbd_server_fd(), - buf, - false, 0, /* no signing */ - IS_CONN_ENCRYPTED(conn), - &req->pcd)) { + buf, + IS_CONN_ENCRYPTED(conn), + &req->pcd)) { exit_server_cleanly("reply_writebraw: srv_send_smb " "failed."); } @@ -3872,7 +3744,7 @@ void reply_writebraw(struct smb_request *req) nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite); if (nwritten == -1) { TALLOC_FREE(buf); - reply_nterror(req, map_nt_error_from_unix(errno)); + reply_unixerror(req, ERRHRD, ERRdiskfull); error_to_writebrawerr(req); goto strict_unlock; } @@ -3893,7 +3765,7 @@ void reply_writebraw(struct smb_request *req) status = sync_file(conn, fsp, write_through); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n", - fsp_str_dbg(fsp), nt_errstr(status))); + fsp->fsp_name, nt_errstr(status) )); reply_nterror(req, status); error_to_writebrawerr(req); goto strict_unlock; @@ -3951,7 +3823,6 @@ void reply_writeunlock(struct smb_request *req) NTSTATUS status = NT_STATUS_OK; files_struct *fsp; struct lock_struct lock; - int saved_errno = 0; START_PROFILE(SMBwriteunlock); @@ -3969,7 +3840,7 @@ void reply_writeunlock(struct smb_request *req) } if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS,ERRbadaccess); END_PROFILE(SMBwriteunlock); return; } @@ -3984,7 +3855,7 @@ void reply_writeunlock(struct smb_request *req) &lock); if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + reply_doserror(req, ERRDOS, ERRlock); END_PROFILE(SMBwriteunlock); return; } @@ -3997,24 +3868,18 @@ void reply_writeunlock(struct smb_request *req) nwritten = 0; } else { nwritten = write_file(req,fsp,data,startpos,numtowrite); - saved_errno = errno; } status = sync_file(conn, fsp, False /* write through */); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n", - fsp_str_dbg(fsp), nt_errstr(status))); + fsp->fsp_name, nt_errstr(status) )); reply_nterror(req, status); goto strict_unlock; } - if(nwritten < 0) { - reply_nterror(req, map_nt_error_from_unix(saved_errno)); - goto strict_unlock; - } - - if((nwritten < numtowrite) && (numtowrite != 0)) { - reply_nterror(req, NT_STATUS_DISK_FULL); + if(((nwritten < numtowrite) && (numtowrite != 0))||(nwritten < 0)) { + reply_unixerror(req, ERRHRD, ERRdiskfull); goto strict_unlock; } @@ -4065,7 +3930,6 @@ void reply_write(struct smb_request *req) files_struct *fsp; struct lock_struct lock; NTSTATUS status; - int saved_errno = 0; START_PROFILE(SMBwrite); @@ -4090,7 +3954,7 @@ void reply_write(struct smb_request *req) } if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRbadaccess); END_PROFILE(SMBwrite); return; } @@ -4104,7 +3968,7 @@ void reply_write(struct smb_request *req) &lock); if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + reply_doserror(req, ERRDOS, ERRlock); END_PROFILE(SMBwrite); return; } @@ -4137,18 +4001,13 @@ void reply_write(struct smb_request *req) status = sync_file(conn, fsp, False); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_write: sync_file for %s returned %s\n", - fsp_str_dbg(fsp), nt_errstr(status))); + fsp->fsp_name, nt_errstr(status) )); reply_nterror(req, status); goto strict_unlock; } - if(nwritten < 0) { - reply_nterror(req, map_nt_error_from_unix(saved_errno)); - goto strict_unlock; - } - - if((nwritten == 0) && (numtowrite != 0)) { - reply_nterror(req, NT_STATUS_DISK_FULL); + if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { + reply_unixerror(req, ERRHRD, ERRdiskfull); goto strict_unlock; } @@ -4184,7 +4043,6 @@ bool is_valid_writeX_buffer(const uint8_t *inbuf) connection_struct *conn = NULL; unsigned int doff = 0; size_t len = smb_len_large(inbuf); - struct smbd_server_connection *sconn = smbd_server_conn; if (is_encrypted_packet(inbuf)) { /* Can't do this on encrypted @@ -4203,7 +4061,7 @@ bool is_valid_writeX_buffer(const uint8_t *inbuf) return false; } - conn = conn_find(sconn, SVAL(inbuf, smb_tid)); + conn = conn_find(SVAL(inbuf, smb_tid)); if (conn == NULL) { DEBUG(10,("is_valid_writeX_buffer: bad tid\n")); return false; @@ -4300,14 +4158,14 @@ void reply_write_and_X(struct smb_request *req) return; } if (numtowrite != req->unread_bytes) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRbadmem); END_PROFILE(SMBwriteX); return; } } else { if (smb_doff > smblen || smb_doff + numtowrite < numtowrite || smb_doff + numtowrite > smblen) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRbadmem); END_PROFILE(SMBwriteX); return; } @@ -4316,7 +4174,7 @@ void reply_write_and_X(struct smb_request *req) /* If it's an IPC, pass off the pipe handler. */ if (IS_IPC(conn)) { if (req->unread_bytes) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + reply_doserror(req, ERRDOS, ERRbadmem); END_PROFILE(SMBwriteX); return; } @@ -4335,7 +4193,7 @@ void reply_write_and_X(struct smb_request *req) } if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRbadaccess); END_PROFILE(SMBwriteX); return; } @@ -4359,7 +4217,7 @@ void reply_write_and_X(struct smb_request *req) DEBUG(0,("reply_write_and_X - large offset (%x << 32) " "used and we don't support 64 bit offsets.\n", (unsigned int)IVAL(req->vwv+12, 0) )); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRbadaccess); END_PROFILE(SMBwriteX); return; } @@ -4372,7 +4230,7 @@ void reply_write_and_X(struct smb_request *req) &lock); if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + reply_doserror(req, ERRDOS, ERRlock); END_PROFILE(SMBwriteX); return; } @@ -4395,13 +4253,8 @@ void reply_write_and_X(struct smb_request *req) nwritten = write_file(req,fsp,data,startpos,numtowrite); } - if(nwritten < 0) { - reply_nterror(req, map_nt_error_from_unix(errno)); - goto strict_unlock; - } - - if((nwritten == 0) && (numtowrite != 0)) { - reply_nterror(req, NT_STATUS_DISK_FULL); + if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { + reply_unixerror(req, ERRHRD, ERRdiskfull); goto strict_unlock; } @@ -4420,7 +4273,7 @@ void reply_write_and_X(struct smb_request *req) status = sync_file(conn, fsp, write_through); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n", - fsp_str_dbg(fsp), nt_errstr(status))); + fsp->fsp_name, nt_errstr(status) )); reply_nterror(req, status); goto strict_unlock; } @@ -4492,22 +4345,23 @@ void reply_lseek(struct smb_request *req) if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) { if(errno == EINVAL) { SMB_OFF_T current_pos = startpos; + SMB_STRUCT_STAT sbuf; - if(fsp_stat(fsp) == -1) { - reply_nterror(req, - map_nt_error_from_unix(errno)); + if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + reply_unixerror(req, ERRDOS, + ERRnoaccess); END_PROFILE(SMBlseek); return; } - current_pos += fsp->fsp_name->st.st_ex_size; + current_pos += sbuf.st_size; if(current_pos < 0) res = SMB_VFS_LSEEK(fsp,0,SEEK_SET); } } if(res == -1) { - reply_nterror(req, map_nt_error_from_unix(errno)); + reply_unixerror(req, ERRDOS, ERRnoaccess); END_PROFILE(SMBlseek); return; } @@ -4555,7 +4409,7 @@ void reply_flush(struct smb_request *req) NTSTATUS status = sync_file(conn, fsp, True); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_flush: sync_file for %s returned %s\n", - fsp_str_dbg(fsp), nt_errstr(status))); + fsp->fsp_name, nt_errstr(status) )); reply_nterror(req, status); END_PROFILE(SMBflush); return; @@ -4612,7 +4466,7 @@ void reply_close(struct smb_request *req) */ if(!fsp || (fsp->conn != conn) || (fsp->vuid != req->vuid)) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); + reply_doserror(req, ERRDOS, ERRbadfid); END_PROFILE(SMBclose); return; } @@ -4691,7 +4545,7 @@ void reply_writeclose(struct smb_request *req) return; } if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS,ERRbadaccess); END_PROFILE(SMBwriteclose); return; } @@ -4707,7 +4561,7 @@ void reply_writeclose(struct smb_request *req) &lock); if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + reply_doserror(req, ERRDOS,ERRlock); END_PROFILE(SMBwriteclose); return; } @@ -4723,8 +4577,8 @@ void reply_writeclose(struct smb_request *req) */ if (numtowrite) { - DEBUG(3,("reply_writeclose: zero length write doesn't close " - "file %s\n", fsp_str_dbg(fsp))); + DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n", + fsp->fsp_name )); close_status = close_file(req, fsp, NORMAL_CLOSE); } @@ -4733,7 +4587,7 @@ void reply_writeclose(struct smb_request *req) conn->num_files_open)); if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) { - reply_nterror(req, NT_STATUS_DISK_FULL); + reply_doserror(req, ERRHRD, ERRdiskfull); goto strict_unlock; } @@ -4883,7 +4737,7 @@ void reply_tdis(struct smb_request *req) if (!conn) { DEBUG(4,("Invalid connection in tdis\n")); - reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED); + reply_doserror(req, ERRSRV, ERRinvnid); END_PROFILE(SMBtdis); return; } @@ -4950,7 +4804,6 @@ void reply_echo(struct smb_request *req) show_msg((char *)req->outbuf); if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(conn)||req->encrypted, cur_pcd)) exit_server_cleanly("reply_echo: srv_send_smb failed."); @@ -4972,6 +4825,7 @@ void reply_printopen(struct smb_request *req) { connection_struct *conn = req->conn; files_struct *fsp; + SMB_STRUCT_STAT sbuf; NTSTATUS status; START_PROFILE(SMBsplopen); @@ -4983,7 +4837,7 @@ void reply_printopen(struct smb_request *req) } if (!CAN_PRINT(conn)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRnoaccess); END_PROFILE(SMBsplopen); return; } @@ -4996,10 +4850,9 @@ void reply_printopen(struct smb_request *req) } /* Open for exclusive use, write only. */ - status = print_fsp_open(req, conn, NULL, req->vuid, fsp); + status = print_fsp_open(req, conn, NULL, req->vuid, fsp, &sbuf); if (!NT_STATUS_IS_OK(status)) { - file_free(req, fsp); reply_nterror(req, status); END_PROFILE(SMBsplopen); return; @@ -5041,7 +4894,7 @@ void reply_printclose(struct smb_request *req) } if (!CAN_PRINT(conn)) { - reply_force_doserror(req, ERRSRV, ERRerror); + reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRerror)); END_PROFILE(SMBsplclose); return; } @@ -5089,7 +4942,7 @@ void reply_printqueue(struct smb_request *req) one printer - I think we should now only accept it if they get it right (tridge) */ if (!CAN_PRINT(conn)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRnoaccess); END_PROFILE(SMBsplretq); return; } @@ -5183,13 +5036,13 @@ void reply_printwrite(struct smb_request *req) } if (!CAN_PRINT(conn)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRnoaccess); END_PROFILE(SMBsplwr); return; } if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRDOS, ERRbadaccess); END_PROFILE(SMBsplwr); return; } @@ -5205,7 +5058,7 @@ void reply_printwrite(struct smb_request *req) data = (const char *)req->buf + 3; if (write_file(req,fsp,data,-1,numtowrite) != numtowrite) { - reply_nterror(req, map_nt_error_from_unix(errno)); + reply_unixerror(req, ERRHRD, ERRdiskfull); END_PROFILE(SMBsplwr); return; } @@ -5223,9 +5076,9 @@ void reply_printwrite(struct smb_request *req) void reply_mkdir(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_dname = NULL; char *directory = NULL; NTSTATUS status; + SMB_STRUCT_STAT sbuf; TALLOC_CTX *ctx = talloc_tos(); START_PROFILE(SMBmkdir); @@ -5234,26 +5087,41 @@ void reply_mkdir(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBmkdir); + return; } - status = filename_convert(ctx, conn, + status = resolve_dfspath(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, - 0, - NULL, - &smb_dname); + &directory); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBmkdir); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBmkdir); + return; + } + + status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBmkdir); + return; + } + + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBmkdir); + return; } - status = create_directory(conn, req, smb_dname); + status = create_directory(conn, req, directory); DEBUG(5, ("create_directory returned %s\n", nt_errstr(status))); @@ -5271,32 +5139,224 @@ void reply_mkdir(struct smb_request *req) } reply_nterror(req, status); - goto out; + END_PROFILE(SMBmkdir); + return; } reply_outbuf(req, 0, 0); - DEBUG(3, ("mkdir %s\n", smb_dname->base_name)); - out: - TALLOC_FREE(smb_dname); + DEBUG( 3, ( "mkdir %s\n", directory ) ); + END_PROFILE(SMBmkdir); return; } /**************************************************************************** + Static function used by reply_rmdir to delete an entire directory + tree recursively. Return True on ok, False on fail. +****************************************************************************/ + +static bool recursive_rmdir(TALLOC_CTX *ctx, + connection_struct *conn, + char *directory) +{ + const char *dname = NULL; + bool ret = True; + long offset = 0; + SMB_STRUCT_STAT st; + struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, directory, + NULL, 0); + + if(dir_hnd == NULL) + return False; + + while((dname = ReadDirName(dir_hnd, &offset, &st))) { + char *fullname = NULL; + + if (ISDOT(dname) || ISDOTDOT(dname)) { + continue; + } + + if (!is_visible_file(conn, directory, dname, &st, False)) { + continue; + } + + /* Construct the full name. */ + fullname = talloc_asprintf(ctx, + "%s/%s", + directory, + dname); + if (!fullname) { + errno = ENOMEM; + ret = False; + break; + } + + if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) { + ret = False; + break; + } + + if(st.st_mode & S_IFDIR) { + if(!recursive_rmdir(ctx, conn, fullname)) { + ret = False; + break; + } + if(SMB_VFS_RMDIR(conn,fullname) != 0) { + ret = False; + break; + } + } else if(SMB_VFS_UNLINK(conn,fullname) != 0) { + ret = False; + break; + } + TALLOC_FREE(fullname); + } + TALLOC_FREE(dir_hnd); + return ret; +} + +/**************************************************************************** + The internals of the rmdir code - called elsewhere. +****************************************************************************/ + +NTSTATUS rmdir_internals(TALLOC_CTX *ctx, + connection_struct *conn, + const char *directory) +{ + int ret; + SMB_STRUCT_STAT st; + + /* Might be a symlink. */ + if(SMB_VFS_LSTAT(conn, directory, &st) != 0) { + return map_nt_error_from_unix(errno); + } + + if (S_ISLNK(st.st_mode)) { + /* Is what it points to a directory ? */ + if(SMB_VFS_STAT(conn, directory, &st) != 0) { + return map_nt_error_from_unix(errno); + } + if (!(S_ISDIR(st.st_mode))) { + return NT_STATUS_NOT_A_DIRECTORY; + } + ret = SMB_VFS_UNLINK(conn,directory); + } else { + ret = SMB_VFS_RMDIR(conn,directory); + } + if (ret == 0) { + notify_fname(conn, NOTIFY_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_DIR_NAME, + directory); + return NT_STATUS_OK; + } + + if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) { + /* + * Check to see if the only thing in this directory are + * vetoed files/directories. If so then delete them and + * retry. If we fail to delete any of them (and we *don't* + * do a recursive delete) then fail the rmdir. + */ + const char *dname; + long dirpos = 0; + struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, + directory, NULL, 0); + + if(dir_hnd == NULL) { + errno = ENOTEMPTY; + goto err; + } + + while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) { + if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) + continue; + if (!is_visible_file(conn, directory, dname, &st, False)) + continue; + if(!IS_VETO_PATH(conn, dname)) { + TALLOC_FREE(dir_hnd); + errno = ENOTEMPTY; + goto err; + } + } + + /* We only have veto files/directories. + * Are we allowed to delete them ? */ + + if(!lp_recursive_veto_delete(SNUM(conn))) { + TALLOC_FREE(dir_hnd); + errno = ENOTEMPTY; + goto err; + } + + /* Do a recursive delete. */ + RewindDir(dir_hnd,&dirpos); + while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) { + char *fullname = NULL; + + if (ISDOT(dname) || ISDOTDOT(dname)) { + continue; + } + if (!is_visible_file(conn, directory, dname, &st, False)) { + continue; + } + + fullname = talloc_asprintf(ctx, + "%s/%s", + directory, + dname); + + if(!fullname) { + errno = ENOMEM; + break; + } + + if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) { + break; + } + if(st.st_mode & S_IFDIR) { + if(!recursive_rmdir(ctx, conn, fullname)) { + break; + } + if(SMB_VFS_RMDIR(conn,fullname) != 0) { + break; + } + } else if(SMB_VFS_UNLINK(conn,fullname) != 0) { + break; + } + TALLOC_FREE(fullname); + } + TALLOC_FREE(dir_hnd); + /* Retry the rmdir */ + ret = SMB_VFS_RMDIR(conn,directory); + } + + err: + + if (ret != 0) { + DEBUG(3,("rmdir_internals: couldn't remove directory %s : " + "%s\n", directory,strerror(errno))); + return map_nt_error_from_unix(errno); + } + + notify_fname(conn, NOTIFY_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_DIR_NAME, + directory); + + return NT_STATUS_OK; +} + +/**************************************************************************** Reply to a rmdir. ****************************************************************************/ void reply_rmdir(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_dname = NULL; char *directory = NULL; + SMB_STRUCT_STAT sbuf; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); - files_struct *fsp = NULL; - int info = 0; - struct smbd_server_connection *sconn = smbd_server_conn; START_PROFILE(SMBrmdir); @@ -5304,82 +5364,53 @@ void reply_rmdir(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBrmdir); + return; } - status = filename_convert(ctx, conn, + status = resolve_dfspath(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, - 0, - NULL, - &smb_dname); + &directory); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBrmdir); + return; } reply_nterror(req, status); - goto out; - } - - if (is_ntfs_stream_smb_fname(smb_dname)) { - reply_nterror(req, NT_STATUS_NOT_A_DIRECTORY); - goto out; + END_PROFILE(SMBrmdir); + return; } - status = SMB_VFS_CREATE_FILE( - conn, /* conn */ - req, /* req */ - 0, /* root_dir_fid */ - smb_dname, /* fname */ - DELETE_ACCESS, /* access_mask */ - (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ - FILE_SHARE_DELETE), - FILE_OPEN, /* create_disposition*/ - FILE_DIRECTORY_FILE, /* create_options */ - FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */ - 0, /* oplock_request */ - 0, /* allocation_size */ - NULL, /* sd */ - NULL, /* ea_list */ - &fsp, /* result */ - &info); /* pinfo */ - + status = unix_convert(ctx, conn, directory, False, &directory, + NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { - /* We have re-scheduled this call. */ - goto out; - } reply_nterror(req, status); - goto out; + END_PROFILE(SMBrmdir); + return; } - status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY); + status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { - close_file(req, fsp, ERROR_CLOSE); reply_nterror(req, status); - goto out; - } - - if (!set_delete_on_close(fsp, true, &conn->server_info->utok)) { - close_file(req, fsp, ERROR_CLOSE); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - goto out; + END_PROFILE(SMBrmdir); + return; } - status = close_file(req, fsp, NORMAL_CLOSE); + dptr_closepath(directory, req->smbpid); + status = rmdir_internals(ctx, conn, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - } else { - reply_outbuf(req, 0, 0); + END_PROFILE(SMBrmdir); + return; } - dptr_closepath(sconn, smb_dname->base_name, req->smbpid); + reply_outbuf(req, 0, 0); + + DEBUG( 3, ( "rmdir %s\n", directory ) ); - DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname))); - out: - TALLOC_FREE(smb_dname); END_PROFILE(SMBrmdir); return; } @@ -5518,11 +5549,10 @@ static bool resolve_wildcards(TALLOC_CTX *ctx, static void rename_open_files(connection_struct *conn, struct share_mode_lock *lck, - const struct smb_filename *smb_fname_dst) + const char *newname) { files_struct *fsp; bool did_rename = False; - NTSTATUS status; for(fsp = file_find_di_first(lck->id); fsp; fsp = file_find_di_next(fsp)) { @@ -5533,27 +5563,21 @@ static void rename_open_files(connection_struct *conn, if (!strequal(fsp->conn->connectpath, conn->connectpath)) { continue; } - DEBUG(10, ("rename_open_files: renaming file fnum %d " - "(file_id %s) from %s -> %s\n", fsp->fnum, - file_id_string_tos(&fsp->file_id), fsp_str_dbg(fsp), - smb_fname_str_dbg(smb_fname_dst))); - - status = fsp_set_smb_fname(fsp, smb_fname_dst); - if (NT_STATUS_IS_OK(status)) { - did_rename = True; - } + DEBUG(10,("rename_open_files: renaming file fnum %d (file_id %s) from %s -> %s\n", + fsp->fnum, file_id_string_tos(&fsp->file_id), + fsp->fsp_name, newname )); + string_set(&fsp->fsp_name, newname); + did_rename = True; } if (!did_rename) { - DEBUG(10, ("rename_open_files: no open files on file_id %s " - "for %s\n", file_id_string_tos(&lck->id), - smb_fname_str_dbg(smb_fname_dst))); + DEBUG(10,("rename_open_files: no open files on file_id %s for %s\n", + file_id_string_tos(&lck->id), newname )); } /* Send messages to all smbd's (not ourself) that the name has changed. */ rename_share_filename(smbd_messaging_context(), lck, conn->connectpath, - smb_fname_dst); - + newname); } /**************************************************************************** @@ -5567,11 +5591,10 @@ static void rename_open_files(connection_struct *conn, report from <AndyLiebman@aol.com>. ****************************************************************************/ -static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src, - const struct smb_filename *smb_fname_dst) +static bool rename_path_prefix_equal(const char *src, const char *dest) { - const char *psrc = smb_fname_src->base_name; - const char *pdst = smb_fname_dst->base_name; + const char *psrc = src; + const char *pdst = dest; size_t slen; if (psrc[0] == '.' && psrc[1] == '/') { @@ -5591,35 +5614,31 @@ static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src, */ static void notify_rename(connection_struct *conn, bool is_dir, - const struct smb_filename *smb_fname_src, - const struct smb_filename *smb_fname_dst) + const char *oldpath, const char *newpath) { - char *parent_dir_src = NULL; - char *parent_dir_dst = NULL; + char *olddir, *newdir; + const char *oldname, *newname; uint32 mask; mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME; - if (!parent_dirname(talloc_tos(), smb_fname_src->base_name, - &parent_dir_src, NULL) || - !parent_dirname(talloc_tos(), smb_fname_dst->base_name, - &parent_dir_dst, NULL)) { - goto out; + if (!parent_dirname(talloc_tos(), oldpath, &olddir, &oldname) + || !parent_dirname(talloc_tos(), newpath, &newdir, &newname)) { + TALLOC_FREE(olddir); + return; } - if (strcmp(parent_dir_src, parent_dir_dst) == 0) { - notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, - smb_fname_src->base_name); - notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, - smb_fname_dst->base_name); + if (strcmp(olddir, newdir) == 0) { + notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath); + notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath); } else { - notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, - smb_fname_src->base_name); - notify_fname(conn, NOTIFY_ACTION_ADDED, mask, - smb_fname_dst->base_name); + notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath); + notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath); } + TALLOC_FREE(olddir); + TALLOC_FREE(newdir); /* this is a strange one. w2k3 gives an additional event for CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming @@ -5628,11 +5647,8 @@ static void notify_rename(connection_struct *conn, bool is_dir, notify_fname(conn, NOTIFY_ACTION_MODIFIED, FILE_NOTIFY_CHANGE_ATTRIBUTES |FILE_NOTIFY_CHANGE_CREATION, - smb_fname_dst->base_name); + newpath); } - out: - TALLOC_FREE(parent_dir_src); - TALLOC_FREE(parent_dir_dst); } /**************************************************************************** @@ -5641,39 +5657,32 @@ static void notify_rename(connection_struct *conn, bool is_dir, NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, - const struct smb_filename *smb_fname_dst_in, + char *newname, + const char *newname_last_component, uint32 attrs, bool replace_if_exists) { TALLOC_CTX *ctx = talloc_tos(); - struct smb_filename *smb_fname_dst = NULL; + SMB_STRUCT_STAT sbuf, sbuf1; NTSTATUS status = NT_STATUS_OK; struct share_mode_lock *lck = NULL; bool dst_exists, old_is_stream, new_is_stream; - status = check_name(conn, smb_fname_dst_in->base_name); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + ZERO_STRUCT(sbuf); - /* Make a copy of the dst smb_fname structs */ - - status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst); + status = check_name(conn, newname); if (!NT_STATUS_IS_OK(status)) { - goto out; + return status; } - /* Ensure the dst smb_fname contains a '/' */ - if(strrchr_m(smb_fname_dst->base_name,'/') == 0) { - char * tmp; - tmp = talloc_asprintf(smb_fname_dst, "./%s", - smb_fname_dst->base_name); - if (!tmp) { - status = NT_STATUS_NO_MEMORY; - goto out; + /* Ensure newname contains a '/' */ + if(strrchr_m(newname,'/') == 0) { + newname = talloc_asprintf(ctx, + "./%s", + newname); + if (!newname) { + return NT_STATUS_NO_MEMORY; } - TALLOC_FREE(smb_fname_dst->base_name); - smb_fname_dst->base_name = tmp; } /* @@ -5683,78 +5692,36 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, * the rename (user is trying to change the case of the * filename). */ - if((conn->case_sensitive == False) && (conn->case_preserve == True) && - strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) && - strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) { - char *last_slash; - char *fname_dst_lcomp_base_mod = NULL; - struct smb_filename *smb_fname_orig_lcomp = NULL; - /* - * Get the last component of the destination name. Note that - * we guarantee that destination name contains a '/' character - * above. - */ - last_slash = strrchr_m(smb_fname_dst->base_name, '/'); - fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1); - if (!fname_dst_lcomp_base_mod) { - status = NT_STATUS_NO_MEMORY; - goto out; - } + if((conn->case_sensitive == False) && (conn->case_preserve == True) && + strequal(newname, fsp->fsp_name)) { + char *p; + char *newname_modified_last_component = NULL; /* - * Create an smb_filename struct using the original last - * component of the destination. + * Get the last component of the modified name. + * Note that we guarantee that newname contains a '/' + * character above. */ - status = create_synthetic_smb_fname_split(ctx, - smb_fname_dst->original_lcomp, NULL, - &smb_fname_orig_lcomp); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(fname_dst_lcomp_base_mod); - goto out; + p = strrchr_m(newname,'/'); + newname_modified_last_component = talloc_strdup(ctx, + p+1); + if (!newname_modified_last_component) { + return NT_STATUS_NO_MEMORY; } - /* If the base names only differ by case, use original. */ - if(!strcsequal(fname_dst_lcomp_base_mod, - smb_fname_orig_lcomp->base_name)) { - char *tmp; + if(strcsequal(newname_modified_last_component, + newname_last_component) == False) { /* - * Replace the modified last component with the - * original. + * Replace the modified last component with + * the original. */ - *last_slash = '\0'; /* Truncate at the '/' */ - tmp = talloc_asprintf(smb_fname_dst, + *p = '\0'; /* Truncate at the '/' */ + newname = talloc_asprintf(ctx, "%s/%s", - smb_fname_dst->base_name, - smb_fname_orig_lcomp->base_name); - if (tmp == NULL) { - status = NT_STATUS_NO_MEMORY; - TALLOC_FREE(fname_dst_lcomp_base_mod); - TALLOC_FREE(smb_fname_orig_lcomp); - goto out; - } - TALLOC_FREE(smb_fname_dst->base_name); - smb_fname_dst->base_name = tmp; - } - - /* If the stream_names only differ by case, use original. */ - if(!strcsequal(smb_fname_dst->stream_name, - smb_fname_orig_lcomp->stream_name)) { - char *tmp = NULL; - /* Use the original stream. */ - tmp = talloc_strdup(smb_fname_dst, - smb_fname_orig_lcomp->stream_name); - if (tmp == NULL) { - status = NT_STATUS_NO_MEMORY; - TALLOC_FREE(fname_dst_lcomp_base_mod); - TALLOC_FREE(smb_fname_orig_lcomp); - goto out; - } - TALLOC_FREE(smb_fname_dst->stream_name); - smb_fname_dst->stream_name = tmp; + newname, + newname_last_component); } - TALLOC_FREE(fname_dst_lcomp_base_mod); - TALLOC_FREE(smb_fname_orig_lcomp); } /* @@ -5762,71 +5729,74 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, * don't do the rename, just return success. */ - if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) && - strcsequal(fsp->fsp_name->stream_name, - smb_fname_dst->stream_name)) { - DEBUG(3, ("rename_internals_fsp: identical names in rename %s " - "- returning success\n", - smb_fname_str_dbg(smb_fname_dst))); - status = NT_STATUS_OK; - goto out; + if (strcsequal(fsp->fsp_name, newname)) { + DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n", + newname)); + return NT_STATUS_OK; } - old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name); - new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst); + old_is_stream = is_ntfs_stream_name(fsp->fsp_name); + new_is_stream = is_ntfs_stream_name(newname); /* Return the correct error code if both names aren't streams. */ if (!old_is_stream && new_is_stream) { - status = NT_STATUS_OBJECT_NAME_INVALID; - goto out; + return NT_STATUS_OBJECT_NAME_INVALID; } if (old_is_stream && !new_is_stream) { - status = NT_STATUS_INVALID_PARAMETER; - goto out; + return NT_STATUS_INVALID_PARAMETER; } - dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0; + /* + * Have vfs_object_exist also fill sbuf1 + */ + dst_exists = vfs_object_exist(conn, newname, &sbuf1); if(!replace_if_exists && dst_exists) { - DEBUG(3, ("rename_internals_fsp: dest exists doing rename " - "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name), - smb_fname_str_dbg(smb_fname_dst))); - status = NT_STATUS_OBJECT_NAME_COLLISION; - goto out; + DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n", + fsp->fsp_name,newname)); + return NT_STATUS_OBJECT_NAME_COLLISION; } if (dst_exists) { - struct file_id fileid = vfs_file_id_from_sbuf(conn, - &smb_fname_dst->st); + struct file_id fileid = vfs_file_id_from_sbuf(conn, &sbuf1); files_struct *dst_fsp = file_find_di_first(fileid); /* The file can be open when renaming a stream */ if (dst_fsp && !new_is_stream) { DEBUG(3, ("rename_internals_fsp: Target file open\n")); - status = NT_STATUS_ACCESS_DENIED; - goto out; + return NT_STATUS_ACCESS_DENIED; } } /* Ensure we have a valid stat struct for the source. */ - status = vfs_stat_fsp(fsp); - if (!NT_STATUS_IS_OK(status)) { - goto out; + if (fsp->fh->fd != -1) { + if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } else { + int ret = -1; + if (fsp->posix_open) { + ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf); + } else { + ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf); + } + if (ret == -1) { + return map_nt_error_from_unix(errno); + } } - status = can_rename(conn, fsp, attrs); + status = can_rename(conn, fsp, attrs, &sbuf); if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n", - nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name), - smb_fname_str_dbg(smb_fname_dst))); + DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n", + nt_errstr(status), fsp->fsp_name,newname)); if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) status = NT_STATUS_ACCESS_DENIED; - goto out; + return status; } - if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) { - status = NT_STATUS_ACCESS_DENIED; + if (rename_path_prefix_equal(fsp->fsp_name, newname)) { + return NT_STATUS_ACCESS_DENIED; } lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, @@ -5839,17 +5809,15 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, SMB_ASSERT(lck != NULL); - if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) { + if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) { uint32 create_options = fsp->fh->private_options; - DEBUG(3, ("rename_internals_fsp: succeeded doing rename on " - "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name), - smb_fname_str_dbg(smb_fname_dst))); + DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n", + fsp->fsp_name,newname)); - notify_rename(conn, fsp->is_directory, fsp->fsp_name, - smb_fname_dst); + notify_rename(conn, fsp->is_directory, fsp->fsp_name, newname); - rename_open_files(conn, lck, smb_fname_dst); + rename_open_files(conn, lck, newname); /* * A rename acts as a new file create w.r.t. allowing an initial delete @@ -5861,7 +5829,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, */ if (create_options & FILE_DELETE_ON_CLOSE) { - status = can_set_delete_on_close(fsp, 0); + status = can_set_delete_on_close(fsp, True, 0); if (NT_STATUS_IS_OK(status)) { /* Note that here we set the *inital* delete on close flag, @@ -5870,8 +5838,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, } } TALLOC_FREE(lck); - status = NT_STATUS_OK; - goto out; + return NT_STATUS_OK; } TALLOC_FREE(lck); @@ -5882,12 +5849,8 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, status = map_nt_error_from_unix(errno); } - DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n", - nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name), - smb_fname_str_dbg(smb_fname_dst))); - - out: - TALLOC_FREE(smb_fname_dst); + DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n", + nt_errstr(status), fsp->fsp_name,newname)); return status; } @@ -5900,25 +5863,45 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, NTSTATUS rename_internals(TALLOC_CTX *ctx, connection_struct *conn, struct smb_request *req, - struct smb_filename *smb_fname_src, - struct smb_filename *smb_fname_dst, + const char *name_in, + const char *newname_in, uint32 attrs, bool replace_if_exists, bool src_has_wild, bool dest_has_wild, uint32_t access_mask) { - char *fname_src_dir = NULL; - char *fname_src_mask = NULL; + char *directory = NULL; + char *mask = NULL; + char *last_component_src = NULL; + char *last_component_dest = NULL; + char *name = NULL; + char *newname = NULL; + char *p; int count=0; NTSTATUS status = NT_STATUS_OK; + SMB_STRUCT_STAT sbuf1, sbuf2; struct smb_Dir *dir_hnd = NULL; - const char *dname = NULL; - char *talloced = NULL; + const char *dname; long offset = 0; int create_options = 0; bool posix_pathnames = lp_posix_pathnames(); + ZERO_STRUCT(sbuf1); + ZERO_STRUCT(sbuf2); + + status = unix_convert(ctx, conn, name_in, src_has_wild, &name, + &last_component_src, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = unix_convert(ctx, conn, newname_in, dest_has_wild, &newname, + &last_component_dest, &sbuf2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* * Split the old name into directory and last component * strings. Note that unix_convert may have stripped off a @@ -5928,12 +5911,21 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, * as this is checked in resolve_wildcards(). */ - /* Split up the directory from the filename/mask. */ - status = split_fname_dir_mask(ctx, smb_fname_src->base_name, - &fname_src_dir, &fname_src_mask); - if (!NT_STATUS_IS_OK(status)) { - status = NT_STATUS_NO_MEMORY; - goto out; + p = strrchr_m(name,'/'); + if (!p) { + directory = talloc_strdup(ctx, "."); + if (!directory) { + return NT_STATUS_NO_MEMORY; + } + mask = name; + } else { + *p = 0; + directory = talloc_strdup(ctx, name); + if (!directory) { + return NT_STATUS_NO_MEMORY; + } + mask = p+1; + *p = '/'; /* Replace needed for exceptional test below. */ } /* @@ -5945,14 +5937,14 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!VALID_STAT(smb_fname_src->st) && - mangle_is_mangled(fname_src_mask, conn->params)) { + if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) { char *new_mask = NULL; - mangle_lookup_name_from_8_3(ctx, fname_src_mask, &new_mask, - conn->params); + mangle_lookup_name_from_8_3(ctx, + mask, + &new_mask, + conn->params ); if (new_mask) { - TALLOC_FREE(fname_src_mask); - fname_src_mask = new_mask; + mask = new_mask; } } @@ -5960,30 +5952,24 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, files_struct *fsp; /* - * Only one file needs to be renamed. Append the mask back - * onto the directory. + * No wildcards - just process the one file. */ - TALLOC_FREE(smb_fname_src->base_name); - smb_fname_src->base_name = talloc_asprintf(smb_fname_src, - "%s/%s", - fname_src_dir, - fname_src_mask); - if (!smb_fname_src->base_name) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - - /* Ensure dst fname contains a '/' also */ - if(strrchr_m(smb_fname_dst->base_name, '/') == 0) { - char *tmp; - tmp = talloc_asprintf(smb_fname_dst, "./%s", - smb_fname_dst->base_name); - if (!tmp) { - status = NT_STATUS_NO_MEMORY; - goto out; + /* Add a terminating '/' to the directory name. */ + directory = talloc_asprintf_append(directory, + "/%s", + mask); + if (!directory) { + return NT_STATUS_NO_MEMORY; + } + + /* Ensure newname contains a '/' also */ + if(strrchr_m(newname,'/') == 0) { + newname = talloc_asprintf(ctx, + "./%s", + newname); + if (!newname) { + return NT_STATUS_NO_MEMORY; } - TALLOC_FREE(smb_fname_dst->base_name); - smb_fname_dst->base_name = tmp; } DEBUG(3, ("rename_internals: case_sensitive = %d, " @@ -5991,37 +5977,31 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, "directory = %s, newname = %s, " "last_component_dest = %s\n", conn->case_sensitive, conn->case_preserve, - conn->short_case_preserve, - smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst), - smb_fname_dst->original_lcomp)); + conn->short_case_preserve, directory, + newname, last_component_dest)); /* The dest name still may have wildcards. */ if (dest_has_wild) { - char *fname_dst_mod = NULL; - if (!resolve_wildcards(smb_fname_dst, - smb_fname_src->base_name, - smb_fname_dst->base_name, - &fname_dst_mod)) { + char *mod_newname = NULL; + if (!resolve_wildcards(ctx, + directory,newname,&mod_newname)) { DEBUG(6, ("rename_internals: resolve_wildcards " - "%s %s failed\n", - smb_fname_src->base_name, - smb_fname_dst->base_name)); - status = NT_STATUS_NO_MEMORY; - goto out; + "%s %s failed\n", + directory, + newname)); + return NT_STATUS_NO_MEMORY; } - TALLOC_FREE(smb_fname_dst->base_name); - smb_fname_dst->base_name = fname_dst_mod; + newname = mod_newname; } - ZERO_STRUCT(smb_fname_src->st); + ZERO_STRUCT(sbuf1); if (posix_pathnames) { - SMB_VFS_LSTAT(conn, smb_fname_src); + SMB_VFS_LSTAT(conn, directory, &sbuf1); } else { - SMB_VFS_STAT(conn, smb_fname_src); + SMB_VFS_STAT(conn, directory, &sbuf1); } - if (S_ISDIR(smb_fname_src->st.st_ex_mode)) { + if (S_ISDIR(sbuf1.st_mode)) { create_options |= FILE_DIRECTORY_FILE; } @@ -6029,7 +6009,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname_src, /* fname */ + directory, /* fname */ + 0, /* create_file_flags */ access_mask, /* access_mask */ (FILE_SHARE_READ | /* share_access */ FILE_SHARE_WRITE), @@ -6041,49 +6022,43 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + &sbuf1); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("Could not open rename source %s: %s\n", - smb_fname_str_dbg(smb_fname_src), - nt_errstr(status))); - goto out; + directory, nt_errstr(status))); + return status; } - status = rename_internals_fsp(conn, fsp, smb_fname_dst, + status = rename_internals_fsp(conn, fsp, newname, + last_component_dest, attrs, replace_if_exists); close_file(req, fsp, NORMAL_CLOSE); DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(status), smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst))); + nt_errstr(status), directory,newname)); - goto out; + return status; } /* * Wildcards - process each file that matches. */ - if (strequal(fname_src_mask, "????????.???")) { - TALLOC_FREE(fname_src_mask); - fname_src_mask = talloc_strdup(ctx, "*"); - if (!fname_src_mask) { - status = NT_STATUS_NO_MEMORY; - goto out; - } + if (strequal(mask,"????????.???")) { + mask[0] = '*'; + mask[1] = '\0'; } - status = check_name(conn, fname_src_dir); + status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { - goto out; + return status; } - dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask, - attrs); + dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, attrs); if (dir_hnd == NULL) { - status = map_nt_error_from_unix(errno); - goto out; + return map_nt_error_from_unix(errno); } status = NT_STATUS_NO_SUCH_FILE; @@ -6092,9 +6067,9 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, * - gentest fix. JRA */ - while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st, - &talloced))) { + while ((dname = ReadDirName(dir_hnd, &offset, &sbuf1))) { files_struct *fsp = NULL; + char *fname = NULL; char *destname = NULL; bool sysdir_entry = False; @@ -6103,19 +6078,15 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, if (attrs & aDIR) { sysdir_entry = True; } else { - TALLOC_FREE(talloced); continue; } } - if (!is_visible_file(conn, fname_src_dir, dname, - &smb_fname_src->st, false)) { - TALLOC_FREE(talloced); + if (!is_visible_file(conn, directory, dname, &sbuf1, False)) { continue; } - if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) { - TALLOC_FREE(talloced); + if(!mask_match(dname, mask, conn->case_sensitive)) { continue; } @@ -6124,42 +6095,35 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, break; } - TALLOC_FREE(smb_fname_src->base_name); - smb_fname_src->base_name = talloc_asprintf(smb_fname_src, - "%s/%s", - fname_src_dir, - dname); - if (!smb_fname_src->base_name) { - status = NT_STATUS_NO_MEMORY; - goto out; + fname = talloc_asprintf(ctx, + "%s/%s", + directory, + dname); + if (!fname) { + return NT_STATUS_NO_MEMORY; } - if (!resolve_wildcards(ctx, smb_fname_src->base_name, - smb_fname_dst->base_name, - &destname)) { + if (!resolve_wildcards(ctx, + fname,newname,&destname)) { DEBUG(6, ("resolve_wildcards %s %s failed\n", - smb_fname_src->base_name, destname)); - TALLOC_FREE(talloced); + fname, destname)); + TALLOC_FREE(fname); continue; } if (!destname) { - status = NT_STATUS_NO_MEMORY; - goto out; + return NT_STATUS_NO_MEMORY; } - TALLOC_FREE(smb_fname_dst->base_name); - smb_fname_dst->base_name = destname; - - ZERO_STRUCT(smb_fname_src->st); + ZERO_STRUCT(sbuf1); if (posix_pathnames) { - SMB_VFS_LSTAT(conn, smb_fname_src); + SMB_VFS_LSTAT(conn, fname, &sbuf1); } else { - SMB_VFS_STAT(conn, smb_fname_src); + SMB_VFS_STAT(conn, fname, &sbuf1); } create_options = 0; - if (S_ISDIR(smb_fname_src->st.st_ex_mode)) { + if (S_ISDIR(sbuf1.st_mode)) { create_options |= FILE_DIRECTORY_FILE; } @@ -6167,7 +6131,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname_src, /* fname */ + fname, /* fname */ + 0, /* create_file_flags */ access_mask, /* access_mask */ (FILE_SHARE_READ | /* share_access */ FILE_SHARE_WRITE), @@ -6179,25 +6144,17 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + &sbuf1); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE " "returned %s rename %s -> %s\n", - nt_errstr(status), - smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst))); + nt_errstr(status), directory, newname)); break; } - smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst, - dname); - if (!smb_fname_dst->original_lcomp) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - - status = rename_internals_fsp(conn, fsp, smb_fname_dst, + status = rename_internals_fsp(conn, fsp, destname, dname, attrs, replace_if_exists); close_file(req, fsp, NORMAL_CLOSE); @@ -6205,17 +6162,17 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("rename_internals_fsp returned %s for " "rename %s -> %s\n", nt_errstr(status), - smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst))); + directory, newname)); break; } count++; DEBUG(3,("rename_internals: doing rename on %s -> " - "%s\n", smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_src))); - TALLOC_FREE(talloced); + "%s\n",fname,destname)); + + TALLOC_FREE(fname); + TALLOC_FREE(destname); } TALLOC_FREE(dir_hnd); @@ -6223,10 +6180,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, status = map_nt_error_from_unix(errno); } - out: - TALLOC_FREE(talloced); - TALLOC_FREE(fname_src_dir); - TALLOC_FREE(fname_src_mask); return status; } @@ -6245,14 +6198,13 @@ void reply_mv(struct smb_request *req) bool src_has_wcard = False; bool dest_has_wcard = False; TALLOC_CTX *ctx = talloc_tos(); - struct smb_filename *smb_fname_src = NULL; - struct smb_filename *smb_fname_dst = NULL; START_PROFILE(SMBmv); if (req->wct < 1) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBmv); + return; } attrs = SVAL(req->vwv+0, 0); @@ -6262,71 +6214,69 @@ void reply_mv(struct smb_request *req) &status, &src_has_wcard); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBmv); + return; } p++; p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE, &status, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBmv); + return; } - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - name, - UCF_COND_ALLOW_WCARD_LCOMP, - &src_has_wcard, - &smb_fname_src); - + status = resolve_dfspath_wcard(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + name, + &name, + &src_has_wcard); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBmv); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBmv); + return; } - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - newname, - UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP, - &dest_has_wcard, - &smb_fname_dst); - + status = resolve_dfspath_wcard(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + newname, + &newname, + &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBmv); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBmv); + return; } - DEBUG(3,("reply_mv : %s -> %s\n", smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst))); + DEBUG(3,("reply_mv : %s -> %s\n",name,newname)); - status = rename_internals(ctx, conn, req, smb_fname_src, smb_fname_dst, - attrs, False, src_has_wcard, dest_has_wcard, - DELETE_ACCESS); + status = rename_internals(ctx, conn, req, name, newname, attrs, False, + src_has_wcard, dest_has_wcard, DELETE_ACCESS); if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - goto out; + END_PROFILE(SMBmv); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBmv); + return; } reply_outbuf(req, 0, 0); - out: - TALLOC_FREE(smb_fname_src); - TALLOC_FREE(smb_fname_dst); + END_PROFILE(SMBmv); return; } @@ -6341,73 +6291,60 @@ void reply_mv(struct smb_request *req) NTSTATUS copy_file(TALLOC_CTX *ctx, connection_struct *conn, - struct smb_filename *smb_fname_src, - struct smb_filename *smb_fname_dst, + const char *src, + const char *dest1, int ofun, int count, bool target_is_directory) { - struct smb_filename *smb_fname_dst_tmp = NULL; + SMB_STRUCT_STAT src_sbuf, sbuf2; SMB_OFF_T ret=-1; files_struct *fsp1,*fsp2; + char *dest = NULL; uint32 dosattrs; uint32 new_create_disposition; NTSTATUS status; - - status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp); - if (!NT_STATUS_IS_OK(status)) { - return status; + dest = talloc_strdup(ctx, dest1); + if (!dest) { + return NT_STATUS_NO_MEMORY; } - - /* - * If the target is a directory, extract the last component from the - * src filename and append it to the dst filename - */ if (target_is_directory) { - const char *p; - - /* dest/target can't be a stream if it's a directory. */ - SMB_ASSERT(smb_fname_dst->stream_name == NULL); - - p = strrchr_m(smb_fname_src->base_name,'/'); + const char *p = strrchr_m(src,'/'); if (p) { p++; } else { - p = smb_fname_src->base_name; + p = src; } - smb_fname_dst_tmp->base_name = - talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s", - p); - if (!smb_fname_dst_tmp->base_name) { - status = NT_STATUS_NO_MEMORY; - goto out; + dest = talloc_asprintf_append(dest, + "/%s", + p); + if (!dest) { + return NT_STATUS_NO_MEMORY; } } - status = vfs_file_exist(conn, smb_fname_src); - if (!NT_STATUS_IS_OK(status)) { - goto out; + if (!vfs_file_exist(conn,src,&src_sbuf)) { + TALLOC_FREE(dest); + return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (!target_is_directory && count) { new_create_disposition = FILE_OPEN; } else { - if (!map_open_params_to_ntcreate(smb_fname_dst_tmp, 0, ofun, - NULL, NULL, - &new_create_disposition, - NULL)) { - status = NT_STATUS_INVALID_PARAMETER; - goto out; + if (!map_open_params_to_ntcreate(dest1,0,ofun, + NULL, NULL, &new_create_disposition, NULL)) { + TALLOC_FREE(dest); + return NT_STATUS_INVALID_PARAMETER; } } - /* Open the src file for reading. */ status = SMB_VFS_CREATE_FILE( conn, /* conn */ NULL, /* req */ 0, /* root_dir_fid */ - smb_fname_src, /* fname */ + src, /* fname */ + 0, /* create_file_flags */ FILE_GENERIC_READ, /* access_mask */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */ FILE_OPEN, /* create_disposition*/ @@ -6418,24 +6355,25 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp1, /* result */ - NULL); /* psbuf */ + NULL, /* pinfo */ + &src_sbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { - goto out; + TALLOC_FREE(dest); + return status; } - dosattrs = dos_mode(conn, smb_fname_src); - - if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) { - ZERO_STRUCTP(&smb_fname_dst_tmp->st); + dosattrs = dos_mode(conn, src, &src_sbuf); + if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1) { + ZERO_STRUCTP(&sbuf2); } - /* Open the dst file for writing. */ status = SMB_VFS_CREATE_FILE( conn, /* conn */ NULL, /* req */ 0, /* root_dir_fid */ - smb_fname_dst, /* fname */ + dest, /* fname */ + 0, /* create_file_flags */ FILE_GENERIC_WRITE, /* access_mask */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */ new_create_disposition, /* create_disposition*/ @@ -6446,11 +6384,14 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp2, /* result */ - NULL); /* psbuf */ + NULL, /* pinfo */ + &sbuf2); /* psbuf */ + + TALLOC_FREE(dest); if (!NT_STATUS_IS_OK(status)) { close_file(NULL, fsp1, ERROR_CLOSE); - goto out; + return status; } if ((ofun&3) == 1) { @@ -6460,19 +6401,18 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, * Stop the copy from occurring. */ ret = -1; - smb_fname_src->st.st_ex_size = 0; + src_sbuf.st_size = 0; } } - /* Do the actual copy. */ - if (smb_fname_src->st.st_ex_size) { - ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size); + if (src_sbuf.st_size) { + ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size); } close_file(NULL, fsp1, NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime); + set_close_write_time(fsp2, get_mtimespec(&src_sbuf)); /* * As we are opening fsp1 read-only we only expect @@ -6483,19 +6423,14 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, status = close_file(NULL, fsp2, NORMAL_CLOSE); if (!NT_STATUS_IS_OK(status)) { - goto out; + return status; } - if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) { - status = NT_STATUS_DISK_FULL; - goto out; + if (ret != (SMB_OFF_T)src_sbuf.st_size) { + return NT_STATUS_DISK_FULL; } - status = NT_STATUS_OK; - - out: - TALLOC_FREE(smb_fname_dst_tmp); - return status; + return NT_STATUS_OK; } /**************************************************************************** @@ -6505,21 +6440,22 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, void reply_copy(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname_src = NULL; - struct smb_filename *smb_fname_dst = NULL; - char *fname_src = NULL; - char *fname_dst = NULL; - char *fname_src_mask = NULL; - char *fname_src_dir = NULL; + char *name = NULL; + char *newname = NULL; + char *directory = NULL; + const char *mask = NULL; + const char mask_star[] = "*"; const char *p; int count=0; int error = ERRnoaccess; + int err = 0; int tid2; int ofun; int flags; bool target_is_directory=False; bool source_has_wild = False; bool dest_has_wild = False; + SMB_STRUCT_STAT sbuf1, sbuf2; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); @@ -6527,7 +6463,8 @@ void reply_copy(struct smb_request *req) if (req->wct < 3) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBcopy); + return; } tid2 = SVAL(req->vwv+0, 0); @@ -6535,85 +6472,116 @@ void reply_copy(struct smb_request *req) flags = SVAL(req->vwv+2, 0); p = (const char *)req->buf; - p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE, + p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE, &status, &source_has_wild); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } - p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE, + p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE, &status, &dest_has_wild); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } - DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst)); + DEBUG(3,("reply_copy : %s -> %s\n",name,newname)); if (tid2 != conn->cnum) { /* can't currently handle inter share copies XXXX */ DEBUG(3,("Rejecting inter-share copy\n")); - reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE); - goto out; + reply_doserror(req, ERRSRV, ERRinvdevice); + END_PROFILE(SMBcopy); + return; } - status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname_src, - UCF_COND_ALLOW_WCARD_LCOMP, - &source_has_wild, - &smb_fname_src); + status = resolve_dfspath_wcard(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + name, + &name, + &source_has_wild); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBcopy); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } - status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname_dst, - UCF_COND_ALLOW_WCARD_LCOMP, - &dest_has_wild, - &smb_fname_dst); + status = resolve_dfspath_wcard(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + newname, + &newname, + &dest_has_wild); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + END_PROFILE(SMBcopy); + return; } reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } - target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st); + status = unix_convert(ctx, conn, name, source_has_wild, + &name, NULL, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBcopy); + return; + } + + status = unix_convert(ctx, conn, newname, dest_has_wild, + &newname, NULL, &sbuf2); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBcopy); + return; + } + + target_is_directory = VALID_STAT_OF_DIR(sbuf2); if ((flags&1) && target_is_directory) { - reply_nterror(req, NT_STATUS_NO_SUCH_FILE); - goto out; + reply_doserror(req, ERRDOS, ERRbadfile); + END_PROFILE(SMBcopy); + return; } if ((flags&2) && !target_is_directory) { - reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND); - goto out; + reply_doserror(req, ERRDOS, ERRbadpath); + END_PROFILE(SMBcopy); + return; } - if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) { + if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) { /* wants a tree copy! XXXX */ DEBUG(3,("Rejecting tree copy\n")); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + reply_doserror(req, ERRSRV, ERRerror); + END_PROFILE(SMBcopy); + return; } - /* Split up the directory from the filename/mask. */ - status = split_fname_dir_mask(ctx, smb_fname_src->base_name, - &fname_src_dir, &fname_src_mask); - if (!NT_STATUS_IS_OK(status)) { + p = strrchr_m(name,'/'); + if (p != NULL) { + directory = talloc_strndup(ctx, name, PTR_DIFF(p, name)); + mask = p+1; + } else { + directory = talloc_strdup(ctx, "./"); + mask = name; + } + + if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBcopy); + return; } /* @@ -6624,210 +6592,167 @@ void reply_copy(struct smb_request *req) * for a possible mangle. This patch from * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!VALID_STAT(smb_fname_src->st) && - mangle_is_mangled(fname_src_mask, conn->params)) { - char *new_mask = NULL; - mangle_lookup_name_from_8_3(ctx, fname_src_mask, - &new_mask, conn->params); - /* Use demangled name if one was successfully found. */ + if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) { + char *new_mask = NULL; + mangle_lookup_name_from_8_3(ctx, + mask, + &new_mask, + conn->params ); if (new_mask) { - TALLOC_FREE(fname_src_mask); - fname_src_mask = new_mask; + mask = new_mask; } } if (!source_has_wild) { - - /* - * Only one file needs to be copied. Append the mask back onto - * the directory. - */ - TALLOC_FREE(smb_fname_src->base_name); - smb_fname_src->base_name = talloc_asprintf(smb_fname_src, - "%s/%s", - fname_src_dir, - fname_src_mask); - if (!smb_fname_src->base_name) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; - } - + directory = talloc_asprintf_append(directory, + "/%s", + mask); if (dest_has_wild) { - char *fname_dst_mod = NULL; - if (!resolve_wildcards(smb_fname_dst, - smb_fname_src->base_name, - smb_fname_dst->base_name, - &fname_dst_mod)) { + char *mod_newname = NULL; + if (!resolve_wildcards(ctx, + directory,newname,&mod_newname)) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBcopy); + return; } - TALLOC_FREE(smb_fname_dst->base_name); - smb_fname_dst->base_name = fname_dst_mod; + newname = mod_newname; } - status = check_name(conn, smb_fname_src->base_name); + status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } - status = check_name(conn, smb_fname_dst->base_name); + status = check_name(conn, newname); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } - status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst, - ofun, count, target_is_directory); + status = copy_file(ctx,conn,directory,newname,ofun, + count,target_is_directory); if(!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } else { count++; } } else { struct smb_Dir *dir_hnd = NULL; const char *dname = NULL; - char *talloced = NULL; long offset = 0; - /* - * There is a wildcard that requires us to actually read the - * src dir and copy each file matching the mask to the dst. - * Right now streams won't be copied, but this could - * presumably be added with a nested loop for reach dir entry. - */ - SMB_ASSERT(!smb_fname_src->stream_name); - SMB_ASSERT(!smb_fname_dst->stream_name); - - smb_fname_src->stream_name = NULL; - smb_fname_dst->stream_name = NULL; - - if (strequal(fname_src_mask,"????????.???")) { - TALLOC_FREE(fname_src_mask); - fname_src_mask = talloc_strdup(ctx, "*"); - if (!fname_src_mask) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; - } + if (strequal(mask,"????????.???")) { + mask = mask_star; } - status = check_name(conn, fname_src_dir); + status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } - dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0); + dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, 0); if (dir_hnd == NULL) { status = map_nt_error_from_unix(errno); reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } error = ERRbadfile; - /* Iterate over the src dir copying each entry to the dst. */ - while ((dname = ReadDirName(dir_hnd, &offset, - &smb_fname_src->st, &talloced))) { + while ((dname = ReadDirName(dir_hnd, &offset, &sbuf1))) { char *destname = NULL; + char *fname = NULL; if (ISDOT(dname) || ISDOTDOT(dname)) { - TALLOC_FREE(talloced); continue; } - if (!is_visible_file(conn, fname_src_dir, dname, - &smb_fname_src->st, false)) { - TALLOC_FREE(talloced); + if (!is_visible_file(conn, directory, dname, &sbuf1, False)) { continue; } - if(!mask_match(dname, fname_src_mask, - conn->case_sensitive)) { - TALLOC_FREE(talloced); + if(!mask_match(dname, mask, conn->case_sensitive)) { continue; } error = ERRnoaccess; - - /* Get the src smb_fname struct setup. */ - TALLOC_FREE(smb_fname_src->base_name); - smb_fname_src->base_name = - talloc_asprintf(smb_fname_src, "%s/%s", - fname_src_dir, dname); - - if (!smb_fname_src->base_name) { + fname = talloc_asprintf(ctx, + "%s/%s", + directory, + dname); + if (!fname) { TALLOC_FREE(dir_hnd); - TALLOC_FREE(talloced); reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBcopy); + return; } - if (!resolve_wildcards(ctx, smb_fname_src->base_name, - smb_fname_dst->base_name, - &destname)) { - TALLOC_FREE(talloced); + if (!resolve_wildcards(ctx, + fname,newname,&destname)) { continue; } if (!destname) { TALLOC_FREE(dir_hnd); - TALLOC_FREE(talloced); reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + END_PROFILE(SMBcopy); + return; } - TALLOC_FREE(smb_fname_dst->base_name); - smb_fname_dst->base_name = destname; - - status = check_name(conn, smb_fname_src->base_name); + status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(dir_hnd); - TALLOC_FREE(talloced); reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } - status = check_name(conn, smb_fname_dst->base_name); + status = check_name(conn, destname); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(dir_hnd); - TALLOC_FREE(talloced); reply_nterror(req, status); - goto out; + END_PROFILE(SMBcopy); + return; } - DEBUG(3,("reply_copy : doing copy on %s -> %s\n", - smb_fname_src->base_name, - smb_fname_dst->base_name)); + DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname)); - status = copy_file(ctx, conn, smb_fname_src, - smb_fname_dst, ofun, count, - target_is_directory); + status = copy_file(ctx,conn,fname,destname,ofun, + count,target_is_directory); if (NT_STATUS_IS_OK(status)) { count++; } - - TALLOC_FREE(talloced); + TALLOC_FREE(fname); + TALLOC_FREE(destname); } TALLOC_FREE(dir_hnd); } if (count == 0) { - reply_nterror(req, dos_to_ntstatus(ERRDOS, error)); - goto out; + if(err) { + /* Error on close... */ + errno = err; + reply_unixerror(req, ERRHRD, ERRgeneral); + END_PROFILE(SMBcopy); + return; + } + + reply_doserror(req, ERRDOS, error); + END_PROFILE(SMBcopy); + return; } reply_outbuf(req, 1, 0); SSVAL(req->outbuf,smb_vwv0,count); - out: - TALLOC_FREE(smb_fname_src); - TALLOC_FREE(smb_fname_dst); - TALLOC_FREE(fname_src); - TALLOC_FREE(fname_dst); - TALLOC_FREE(fname_src_mask); - TALLOC_FREE(fname_src_dir); END_PROFILE(SMBcopy); return; @@ -6972,238 +6897,6 @@ uint64_t get_lock_offset(const uint8_t *data, int data_offset, return offset; } -NTSTATUS smbd_do_locking(struct smb_request *req, - files_struct *fsp, - uint8_t type, - int32_t timeout, - uint16_t num_ulocks, - struct smbd_lock_element *ulocks, - uint16_t num_locks, - struct smbd_lock_element *locks, - bool *async) -{ - connection_struct *conn = req->conn; - int i; - NTSTATUS status = NT_STATUS_OK; - - *async = false; - - /* Data now points at the beginning of the list - of smb_unlkrng structs */ - for(i = 0; i < (int)num_ulocks; i++) { - struct smbd_lock_element *e = &ulocks[i]; - - DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for " - "pid %u, file %s\n", - (double)e->offset, - (double)e->count, - (unsigned int)e->smbpid, - fsp_str_dbg(fsp))); - - if (e->brltype != UNLOCK_LOCK) { - /* this can only happen with SMB2 */ - return NT_STATUS_INVALID_PARAMETER; - } - - status = do_unlock(smbd_messaging_context(), - fsp, - e->smbpid, - e->count, - e->offset, - WINDOWS_LOCK); - - DEBUG(10, ("smbd_do_locking: unlock returned %s\n", - nt_errstr(status))); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - } - - /* Setup the timeout in seconds. */ - - if (!lp_blocking_locks(SNUM(conn))) { - timeout = 0; - } - - /* Data now points at the beginning of the list - of smb_lkrng structs */ - - for(i = 0; i < (int)num_locks; i++) { - struct smbd_lock_element *e = &locks[i]; - - DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for pid " - "%u, file %s timeout = %d\n", - (double)e->offset, - (double)e->count, - (unsigned int)e->smbpid, - fsp_str_dbg(fsp), - (int)timeout)); - - if (type & LOCKING_ANDX_CANCEL_LOCK) { - struct blocking_lock_record *blr = NULL; - - if (num_locks > 1) { - /* - * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only - * if the lock vector contains one entry. When given mutliple cancel - * requests in a single PDU we expect the server to return an - * error. Windows servers seem to accept the request but only - * cancel the first lock. - * JRA - Do what Windows does (tm) :-). - */ - -#if 0 - /* MS-CIFS (2.2.4.32.1) behavior. */ - return NT_STATUS_DOS(ERRDOS, - ERRcancelviolation); -#else - /* Windows behavior. */ - if (i != 0) { - DEBUG(10,("smbd_do_locking: ignoring subsequent " - "cancel request\n")); - continue; - } -#endif - } - - if (lp_blocking_locks(SNUM(conn))) { - - /* Schedule a message to ourselves to - remove the blocking lock record and - return the right error. */ - - blr = blocking_lock_cancel(fsp, - e->smbpid, - e->offset, - e->count, - WINDOWS_LOCK, - type, - NT_STATUS_FILE_LOCK_CONFLICT); - if (blr == NULL) { - return NT_STATUS_DOS( - ERRDOS, - ERRcancelviolation); - } - } - /* Remove a matching pending lock. */ - status = do_lock_cancel(fsp, - e->smbpid, - e->count, - e->offset, - WINDOWS_LOCK, - blr); - } else { - bool blocking_lock = timeout ? true : false; - bool defer_lock = false; - struct byte_range_lock *br_lck; - uint32_t block_smbpid; - - br_lck = do_lock(smbd_messaging_context(), - fsp, - e->smbpid, - e->count, - e->offset, - e->brltype, - WINDOWS_LOCK, - blocking_lock, - &status, - &block_smbpid, - NULL); - - if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) { - /* Windows internal resolution for blocking locks seems - to be about 200ms... Don't wait for less than that. JRA. */ - if (timeout != -1 && timeout < lp_lock_spin_time()) { - timeout = lp_lock_spin_time(); - } - defer_lock = true; - } - - /* If a lock sent with timeout of zero would fail, and - * this lock has been requested multiple times, - * according to brl_lock_failed() we convert this - * request to a blocking lock with a timeout of between - * 150 - 300 milliseconds. - * - * If lp_lock_spin_time() has been set to 0, we skip - * this blocking retry and fail immediately. - * - * Replacement for do_lock_spin(). JRA. */ - - if (br_lck && lp_blocking_locks(SNUM(conn)) && - lp_lock_spin_time() && !blocking_lock && - NT_STATUS_EQUAL((status), - NT_STATUS_FILE_LOCK_CONFLICT)) - { - defer_lock = true; - timeout = lp_lock_spin_time(); - } - - if (br_lck && defer_lock) { - /* - * A blocking lock was requested. Package up - * this smb into a queued request and push it - * onto the blocking lock queue. - */ - if(push_blocking_lock_request(br_lck, - req, - fsp, - timeout, - i, - e->smbpid, - e->brltype, - WINDOWS_LOCK, - e->offset, - e->count, - block_smbpid)) { - TALLOC_FREE(br_lck); - *async = true; - return NT_STATUS_OK; - } - } - - TALLOC_FREE(br_lck); - } - - if (!NT_STATUS_IS_OK(status)) { - break; - } - } - - /* If any of the above locks failed, then we must unlock - all of the previous locks (X/Open spec). */ - - if (num_locks != 0 && !NT_STATUS_IS_OK(status)) { - - if (type & LOCKING_ANDX_CANCEL_LOCK) { - i = -1; /* we want to skip the for loop */ - } - - /* - * Ensure we don't do a remove on the lock that just failed, - * as under POSIX rules, if we have a lock already there, we - * will delete it (and we shouldn't) ..... - */ - for(i--; i >= 0; i--) { - struct smbd_lock_element *e = &locks[i]; - - do_unlock(smbd_messaging_context(), - fsp, - e->smbpid, - e->count, - e->offset, - WINDOWS_LOCK); - } - return status; - } - - DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n", - fsp->fnum, (unsigned int)type, num_locks, num_ulocks)); - - return NT_STATUS_OK; -} - /**************************************************************************** Reply to a lockingX request. ****************************************************************************/ @@ -7216,15 +6909,14 @@ void reply_lockingX(struct smb_request *req) unsigned char oplocklevel; uint16 num_ulocks; uint16 num_locks; + uint64_t count = 0, offset = 0; + uint32 lock_pid; int32 lock_timeout; int i; const uint8_t *data; bool large_file_format; bool err; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; - struct smbd_lock_element *ulocks; - struct smbd_lock_element *locks; - bool async = false; START_PROFILE(SMBlockingX); @@ -7253,7 +6945,7 @@ void reply_lockingX(struct smb_request *req) /* we don't support these - and CANCEL_LOCK makes w2k and XP reboot so I don't really want to be compatible! (tridge) */ - reply_force_doserror(req, ERRDOS, ERRnoatomiclocks); + reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks)); END_PROFILE(SMBlockingX); return; } @@ -7286,8 +6978,7 @@ void reply_lockingX(struct smb_request *req) DEBUG(5,("reply_lockingX: Error : oplock break from " "client for fnum = %d (oplock=%d) and no " "oplock granted on this file (%s).\n", - fsp->fnum, fsp->oplock_type, - fsp_str_dbg(fsp))); + fsp->fnum, fsp->oplock_type, fsp->fsp_name)); /* if this is a pure oplock break request then don't * send a reply */ @@ -7296,7 +6987,7 @@ void reply_lockingX(struct smb_request *req) return; } else { END_PROFILE(SMBlockingX); - reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + reply_doserror(req, ERRDOS, ERRlock); return; } } @@ -7310,7 +7001,7 @@ void reply_lockingX(struct smb_request *req) if (!result) { DEBUG(0, ("reply_lockingX: error in removing " - "oplock on file %s\n", fsp_str_dbg(fsp))); + "oplock on file %s\n", fsp->fsp_name)); /* Hmmm. Is this panic justified? */ smb_panic("internal tdb error"); } @@ -7338,38 +7029,49 @@ void reply_lockingX(struct smb_request *req) return; } - ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks); - if (ulocks == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBlockingX); - return; - } - - locks = talloc_array(req, struct smbd_lock_element, num_locks); - if (locks == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBlockingX); - return; - } - /* Data now points at the beginning of the list of smb_unlkrng structs */ for(i = 0; i < (int)num_ulocks; i++) { - ulocks[i].smbpid = get_lock_pid(data, i, large_file_format); - ulocks[i].count = get_lock_count(data, i, large_file_format); - ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err); - ulocks[i].brltype = UNLOCK_LOCK; + lock_pid = get_lock_pid( data, i, large_file_format); + count = get_lock_count( data, i, large_file_format); + offset = get_lock_offset( data, i, large_file_format, &err); /* * There is no error code marked "stupid client bug".... :-). */ if(err) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); END_PROFILE(SMBlockingX); + reply_doserror(req, ERRDOS, ERRnoaccess); + return; + } + + DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for " + "pid %u, file %s\n", (double)offset, (double)count, + (unsigned int)lock_pid, fsp->fsp_name )); + + status = do_unlock(smbd_messaging_context(), + fsp, + lock_pid, + count, + offset, + WINDOWS_LOCK); + + DEBUG(10, ("reply_lockingX: unlock returned %s\n", + nt_errstr(status))); + + if (NT_STATUS_V(status)) { + END_PROFILE(SMBlockingX); + reply_nterror(req, status); return; } } + /* Setup the timeout in seconds. */ + + if (!lp_blocking_locks(SNUM(conn))) { + lock_timeout = 0; + } + /* Now do any requested locks */ data += ((large_file_format ? 20 : 10)*num_ulocks); @@ -7377,48 +7079,168 @@ void reply_lockingX(struct smb_request *req) of smb_lkrng structs */ for(i = 0; i < (int)num_locks; i++) { - locks[i].smbpid = get_lock_pid(data, i, large_file_format); - locks[i].count = get_lock_count(data, i, large_file_format); - locks[i].offset = get_lock_offset(data, i, large_file_format, &err); - - if (locktype & LOCKING_ANDX_SHARED_LOCK) { - if (locktype & LOCKING_ANDX_CANCEL_LOCK) { - locks[i].brltype = PENDING_READ_LOCK; - } else { - locks[i].brltype = READ_LOCK; - } - } else { - if (locktype & LOCKING_ANDX_CANCEL_LOCK) { - locks[i].brltype = PENDING_WRITE_LOCK; - } else { - locks[i].brltype = WRITE_LOCK; - } - } + enum brl_type lock_type = ((locktype & LOCKING_ANDX_SHARED_LOCK) ? + READ_LOCK:WRITE_LOCK); + lock_pid = get_lock_pid( data, i, large_file_format); + count = get_lock_count( data, i, large_file_format); + offset = get_lock_offset( data, i, large_file_format, &err); /* * There is no error code marked "stupid client bug".... :-). */ if(err) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); END_PROFILE(SMBlockingX); + reply_doserror(req, ERRDOS, ERRnoaccess); return; } + + DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid " + "%u, file %s timeout = %d\n", (double)offset, + (double)count, (unsigned int)lock_pid, + fsp->fsp_name, (int)lock_timeout )); + + if (locktype & LOCKING_ANDX_CANCEL_LOCK) { + struct blocking_lock_record *blr = NULL; + + if (lp_blocking_locks(SNUM(conn))) { + + /* Schedule a message to ourselves to + remove the blocking lock record and + return the right error. */ + + blr = blocking_lock_cancel(fsp, + lock_pid, + offset, + count, + WINDOWS_LOCK, + locktype, + NT_STATUS_FILE_LOCK_CONFLICT); + if (blr == NULL) { + END_PROFILE(SMBlockingX); + reply_nterror( + req, + NT_STATUS_DOS( + ERRDOS, + ERRcancelviolation)); + return; + } + } + /* Remove a matching pending lock. */ + status = do_lock_cancel(fsp, + lock_pid, + count, + offset, + WINDOWS_LOCK, + blr); + } else { + bool blocking_lock = lock_timeout ? True : False; + bool defer_lock = False; + struct byte_range_lock *br_lck; + uint32 block_smbpid; + + br_lck = do_lock(smbd_messaging_context(), + fsp, + lock_pid, + count, + offset, + lock_type, + WINDOWS_LOCK, + blocking_lock, + &status, + &block_smbpid, + NULL); + + if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) { + /* Windows internal resolution for blocking locks seems + to be about 200ms... Don't wait for less than that. JRA. */ + if (lock_timeout != -1 && lock_timeout < lp_lock_spin_time()) { + lock_timeout = lp_lock_spin_time(); + } + defer_lock = True; + } + + /* This heuristic seems to match W2K3 very well. If a + lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT + it pretends we asked for a timeout of between 150 - 300 milliseconds as + far as I can tell. Replacement for do_lock_spin(). JRA. */ + + if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock && + NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) { + defer_lock = True; + lock_timeout = lp_lock_spin_time(); + } + + if (br_lck && defer_lock) { + /* + * A blocking lock was requested. Package up + * this smb into a queued request and push it + * onto the blocking lock queue. + */ + if(push_blocking_lock_request(br_lck, + req, + fsp, + lock_timeout, + i, + lock_pid, + lock_type, + WINDOWS_LOCK, + offset, + count, + block_smbpid)) { + TALLOC_FREE(br_lck); + END_PROFILE(SMBlockingX); + return; + } + } + + TALLOC_FREE(br_lck); + } + + if (NT_STATUS_V(status)) { + break; + } } - status = smbd_do_locking(req, fsp, - locktype, lock_timeout, - num_ulocks, ulocks, - num_locks, locks, - &async); - if (!NT_STATUS_IS_OK(status)) { + /* If any of the above locks failed, then we must unlock + all of the previous locks (X/Open spec). */ + if (num_locks != 0 && !NT_STATUS_IS_OK(status)) { + + if (locktype & LOCKING_ANDX_CANCEL_LOCK) { + i = -1; /* we want to skip the for loop */ + } + + /* + * Ensure we don't do a remove on the lock that just failed, + * as under POSIX rules, if we have a lock already there, we + * will delete it (and we shouldn't) ..... + */ + for(i--; i >= 0; i--) { + lock_pid = get_lock_pid( data, i, large_file_format); + count = get_lock_count( data, i, large_file_format); + offset = get_lock_offset( data, i, large_file_format, + &err); + + /* + * There is no error code marked "stupid client + * bug".... :-). + */ + if(err) { + END_PROFILE(SMBlockingX); + reply_doserror(req, ERRDOS, ERRnoaccess); + return; + } + + do_unlock(smbd_messaging_context(), + fsp, + lock_pid, + count, + offset, + WINDOWS_LOCK); + } END_PROFILE(SMBlockingX); reply_nterror(req, status); return; } - if (async) { - END_PROFILE(SMBlockingX); - return; - } reply_outbuf(req, 2, 0); @@ -7441,7 +7263,7 @@ void reply_lockingX(struct smb_request *req) void reply_readbmpx(struct smb_request *req) { START_PROFILE(SMBreadBmpx); - reply_force_doserror(req, ERRSRV, ERRuseSTD); + reply_doserror(req, ERRSRV, ERRuseSTD); END_PROFILE(SMBreadBmpx); return; } @@ -7455,7 +7277,7 @@ void reply_readbmpx(struct smb_request *req) void reply_readbs(struct smb_request *req) { START_PROFILE(SMBreadBs); - reply_force_doserror(req, ERRSRV, ERRuseSTD); + reply_doserror(req, ERRSRV, ERRuseSTD); END_PROFILE(SMBreadBs); return; } @@ -7469,6 +7291,7 @@ void reply_setattrE(struct smb_request *req) connection_struct *conn = req->conn; struct smb_file_time ft; files_struct *fsp; + SMB_STRUCT_STAT sbuf; NTSTATUS status; START_PROFILE(SMBsetattrE); @@ -7476,16 +7299,19 @@ void reply_setattrE(struct smb_request *req) if (req->wct < 7) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + END_PROFILE(SMBsetattrE); + return; } fsp = file_fsp(req, SVAL(req->vwv+0, 0)); if(!fsp || (fsp->conn != conn)) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); - goto out; + reply_doserror(req, ERRDOS, ERRbadfid); + END_PROFILE(SMBsetattrE); + return; } + /* * Convert the DOS times into unix times. */ @@ -7505,16 +7331,35 @@ void reply_setattrE(struct smb_request *req) */ /* Ensure we have a valid stat struct for the source. */ - status = vfs_stat_fsp(fsp); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; + if (fsp->fh->fd != -1) { + if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + status = map_nt_error_from_unix(errno); + reply_nterror(req, status); + END_PROFILE(SMBsetattrE); + return; + } + } else { + int ret = -1; + + if (fsp->posix_open) { + ret = SMB_VFS_LSTAT(conn, fsp->fsp_name, &sbuf); + } else { + ret = SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf); + } + if (ret == -1) { + status = map_nt_error_from_unix(errno); + reply_nterror(req, status); + END_PROFILE(SMBsetattrE); + return; + } } - status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true); + status = smb_set_file_time(conn, fsp, fsp->fsp_name, + &sbuf, &ft, true); if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; + reply_doserror(req, ERRDOS, ERRnoaccess); + END_PROFILE(SMBsetattrE); + return; } DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u " @@ -7524,7 +7369,7 @@ void reply_setattrE(struct smb_request *req) (unsigned int)ft.mtime.tv_sec, (unsigned int)ft.create_time.tv_sec )); - out: + END_PROFILE(SMBsetattrE); return; } @@ -7541,7 +7386,7 @@ void reply_setattrE(struct smb_request *req) void reply_writebmpx(struct smb_request *req) { START_PROFILE(SMBwriteBmpx); - reply_force_doserror(req, ERRSRV, ERRuseSTD); + reply_doserror(req, ERRSRV, ERRuseSTD); END_PROFILE(SMBwriteBmpx); return; } @@ -7555,7 +7400,7 @@ void reply_writebmpx(struct smb_request *req) void reply_writebs(struct smb_request *req) { START_PROFILE(SMBwriteBs); - reply_force_doserror(req, ERRSRV, ERRuseSTD); + reply_doserror(req, ERRSRV, ERRuseSTD); END_PROFILE(SMBwriteBs); return; } @@ -7567,6 +7412,7 @@ void reply_writebs(struct smb_request *req) void reply_getattrE(struct smb_request *req) { connection_struct *conn = req->conn; + SMB_STRUCT_STAT sbuf; int mode; files_struct *fsp; struct timespec create_ts; @@ -7582,19 +7428,19 @@ void reply_getattrE(struct smb_request *req) fsp = file_fsp(req, SVAL(req->vwv+0, 0)); if(!fsp || (fsp->conn != conn)) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); + reply_doserror(req, ERRDOS, ERRbadfid); END_PROFILE(SMBgetattrE); return; } /* Do an fstat on this file */ - if(fsp_stat(fsp)) { - reply_nterror(req, map_nt_error_from_unix(errno)); + if(fsp_stat(fsp, &sbuf)) { + reply_unixerror(req, ERRDOS, ERRnoaccess); END_PROFILE(SMBgetattrE); return; } - mode = dos_mode(conn, fsp->fsp_name); + mode = dos_mode(conn,fsp->fsp_name,&sbuf); /* * Convert the times into dos times. Set create @@ -7604,20 +7450,19 @@ void reply_getattrE(struct smb_request *req) reply_outbuf(req, 11, 0); - create_ts = get_create_timespec(conn, fsp, fsp->fsp_name); + create_ts = get_create_timespec(&sbuf, + lp_fake_dir_create_times(SNUM(conn))); srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec); - srv_put_dos_date2((char *)req->outbuf, smb_vwv2, - convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime)); + srv_put_dos_date2((char *)req->outbuf, smb_vwv2, sbuf.st_atime); /* Should we check pending modtime here ? JRA */ - srv_put_dos_date2((char *)req->outbuf, smb_vwv4, - convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime)); + srv_put_dos_date2((char *)req->outbuf, smb_vwv4, sbuf.st_mtime); if (mode & aDIR) { SIVAL(req->outbuf, smb_vwv6, 0); SIVAL(req->outbuf, smb_vwv8, 0); } else { - uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st); - SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size); + uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &sbuf); + SIVAL(req->outbuf, smb_vwv6, (uint32)sbuf.st_size); SIVAL(req->outbuf, smb_vwv8, allocation_size); } SSVAL(req->outbuf,smb_vwv10, mode); diff --git a/source3/smbd/seal.c b/source3/smbd/seal.c index 2d738cbd12..0d5415b5f4 100644 --- a/source3/smbd/seal.c +++ b/source3/smbd/seal.c @@ -19,7 +19,6 @@ #include "includes.h" #include "smbd/globals.h" -#include "../libcli/auth/spnego.h" /****************************************************************************** Server side encryption. diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 642980a6b9..2c5ce40085 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -181,34 +181,20 @@ static void msg_inject_fault(struct messaging_context *msg, } #endif /* DEVELOPER */ -/* - * Parent smbd process sets its own debug level first and then - * sends a message to all the smbd children to adjust their debug - * level to that of the parent. - */ - -static void smbd_msg_debug(struct messaging_context *msg_ctx, - void *private_data, - uint32_t msg_type, - struct server_id server_id, - DATA_BLOB *data) -{ - struct child_pid *child; - - debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data); - - for (child = children; child != NULL; child = child->next) { - messaging_send_buf(msg_ctx, pid_to_procid(child->pid), - MSG_DEBUG, - data->data, - strlen((char *) data->data) + 1); - } -} +struct child_pid { + struct child_pid *prev, *next; + pid_t pid; +}; static void add_child_pid(pid_t pid) { struct child_pid *child; + if (lp_max_smbd_processes() == 0) { + /* Don't bother with the child list if we don't care anyway */ + return; + } + child = SMB_MALLOC_P(struct child_pid); if (child == NULL) { DEBUG(0, ("Could not add child struct -- malloc failed\n")); @@ -234,6 +220,11 @@ static void remove_child_pid(pid_t pid, bool unclean_shutdown) MSG_SMB_UNLOCK, NULL, 0, NULL); } + if (lp_max_smbd_processes() == 0) { + /* Don't bother with the child list if we don't care anyway */ + return; + } + for (child = children; child != NULL; child = child->next) { if (child->pid == pid) { struct child_pid *tmp = child; @@ -646,8 +637,6 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent, MSG_SMB_CONF_UPDATED, smb_conf_updated); messaging_register(smbd_messaging_context(), NULL, MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete); - messaging_register(smbd_messaging_context(), NULL, - MSG_DEBUG, smbd_msg_debug); brl_register_msgs(smbd_messaging_context()); #ifdef CLUSTER_SUPPORT @@ -710,10 +699,6 @@ void reload_printers(void) int pnum = lp_servicenumber(PRINTERS_NAME); const char *pname; - if (!lp_load_printers() - && (lp_auto_services() == NULL || !strcmp(lp_auto_services(),""))) - return; - pcap_cache_reload(); /* remove stale printers */ @@ -800,8 +785,7 @@ static void exit_server_common(enum server_exit_reason how, static void exit_server_common(enum server_exit_reason how, const char *const reason) { - bool had_open_conn = false; - struct smbd_server_connection *sconn = smbd_server_conn; + bool had_open_conn; if (!exit_firsttime) exit(0); @@ -809,15 +793,13 @@ static void exit_server_common(enum server_exit_reason how, change_to_root_user(); - if (sconn && sconn->smb1.negprot.auth_context) { - struct auth_context *a = sconn->smb1.negprot.auth_context; - a->free(&sconn->smb1.negprot.auth_context); + if (negprot_global_auth_context) { + (negprot_global_auth_context->free)(&negprot_global_auth_context); } - if (sconn) { - had_open_conn = conn_close_all(sconn); - invalidate_all_vuids(sconn); - } + had_open_conn = conn_close_all(); + + invalidate_all_vuids(); /* 3 second timeout. */ print_notify_send_messages(smbd_messaging_context(), 3); @@ -843,15 +825,6 @@ static void exit_server_common(enum server_exit_reason how, locking_end(); printing_end(); - /* - * we need to force the order of freeing the following, - * because smbd_msg_ctx is not a talloc child of smbd_server_conn. - */ - sconn = NULL; - TALLOC_FREE(smbd_server_conn); - TALLOC_FREE(smbd_msg_ctx); - TALLOC_FREE(smbd_event_ctx); - if (how != SERVER_EXIT_NORMAL) { int oldlevel = DEBUGLEVEL; @@ -873,7 +846,6 @@ static void exit_server_common(enum server_exit_reason how, if (am_parent) { pidfile_unlink(); } - gencache_stabilize(); } /* if we had any open SMB connections when we exited then we @@ -916,8 +888,12 @@ static bool init_structs(void ) if (!init_names()) return False; + conn_init(); + file_init(); + init_dptrs(); + if (!secrets_init()) return False; @@ -1222,15 +1198,6 @@ extern void build_options(bool screen); return -1; } - /* Open the share_info.tdb here, so we don't have to open - after the fork on every single connection. This is a small - performance improvment and reduces the total number of system - fds used. */ - if (!share_info_db_init()) { - DEBUG(0,("ERROR: failed to load share info db.\n")); - exit(1); - } - /* only start the background queue daemon if we are running as a daemon -- bad things will happen if smbd is launched via inetd and we fork a copy of diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 572861a084..8490f17dea 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -187,8 +187,8 @@ bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir) if (do_chdir && vfs_ChDir(conn,conn->connectpath) != 0 && vfs_ChDir(conn,conn->origpath) != 0) { - DEBUG(((errno!=EACCES)?0:3),("chdir (%s) failed, reason: %s\n", - conn->connectpath, strerror(errno))); + DEBUG(0,("chdir (%s) failed\n", + conn->connectpath)); return(False); } @@ -306,7 +306,6 @@ int add_home_service(const char *service, const char *username, const char *home int find_service(fstring service) { int iService; - struct smbd_server_connection *sconn = smbd_server_conn; all_string_sub(service,"\\","/",0); @@ -321,7 +320,7 @@ int find_service(fstring service) * Try mapping the servicename, it may * be a Windows to unix mapped user name. */ - if(map_username(sconn, service)) + if(map_username(service)) phome_dir = get_user_home_dir( talloc_tos(), service); } @@ -562,8 +561,7 @@ static NTSTATUS find_forced_group(bool force_user, Create an auth_serversupplied_info structure for a connection_struct ****************************************************************************/ -static NTSTATUS create_connection_server_info(struct smbd_server_connection *sconn, - TALLOC_CTX *mem_ctx, int snum, +static NTSTATUS create_connection_server_info(TALLOC_CTX *mem_ctx, int snum, struct auth_serversupplied_info *vuid_serverinfo, DATA_BLOB password, struct auth_serversupplied_info **presult) @@ -617,11 +615,11 @@ static NTSTATUS create_connection_server_info(struct smbd_server_connection *sco /* add the sharename as a possible user name if we are in share mode security */ - add_session_user(sconn, lp_servicename(snum)); + add_session_user(lp_servicename(snum)); /* shall we let them in? */ - if (!authorise_login(sconn, snum,user,password,&guest)) { + if (!authorise_login(snum,user,password,&guest)) { DEBUG( 2, ( "Invalid username/password for [%s]\n", lp_servicename(snum)) ); return NT_STATUS_WRONG_PASSWORD; @@ -641,26 +639,26 @@ static NTSTATUS create_connection_server_info(struct smbd_server_connection *sco connecting user if appropriate. ****************************************************************************/ -connection_struct *make_connection_snum(struct smbd_server_connection *sconn, - int snum, user_struct *vuser, - DATA_BLOB password, - const char *pdev, - NTSTATUS *pstatus) +static connection_struct *make_connection_snum(int snum, user_struct *vuser, + DATA_BLOB password, + const char *pdev, + NTSTATUS *pstatus) { connection_struct *conn; - struct smb_filename *smb_fname_cpath = NULL; + SMB_STRUCT_STAT st; fstring dev; int ret; char addr[INET6_ADDRSTRLEN]; NTSTATUS status; fstrcpy(dev, pdev); + SET_STAT_INVALID(st); if (NT_STATUS_IS_ERR(*pstatus = share_sanity_checks(snum, dev))) { return NULL; } - conn = conn_new(sconn); + conn = conn_new(); if (!conn) { DEBUG(0,("Couldn't find free connection.\n")); *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; @@ -669,7 +667,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, conn->params->service = snum; - status = create_connection_server_info(sconn, + status = create_connection_server_info( conn, snum, vuser ? vuser->server_info : NULL, password, &conn->server_info); @@ -685,7 +683,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, conn->force_user = true; } - add_session_user(sconn, conn->server_info->unix_name); + add_session_user(conn->server_info->unix_name); safe_strcpy(conn->client_address, client_addr(get_client_fd(),addr,sizeof(addr)), @@ -696,6 +694,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, conn->printer = (strncmp(dev,"LPT",3) == 0); conn->ipc = ( (strncmp(dev,"IPC",3) == 0) || ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) ); + conn->dirptr = NULL; /* Case options for the share. */ if (lp_casesensitive(snum) == Auto) { @@ -715,6 +714,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, conn->hide_list = NULL; conn->veto_oplock_list = NULL; conn->aio_write_behind_list = NULL; + string_set(&conn->dirpath,""); conn->read_only = lp_readonly(SNUM(conn)); conn->admin_user = False; @@ -1006,21 +1006,15 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, lp_aio_write_behind(snum)); } - status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath, - NULL, NULL, &smb_fname_cpath); - if (!NT_STATUS_IS_OK(status)) { - *pstatus = status; - goto err_root_exit; - } /* win2000 does not check the permissions on the directory during the tree connect, instead relying on permission check during individual operations. To match this behaviour I have disabled this chdir check (tridge) */ /* the alternative is just to check the directory exists */ - if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 || - !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { - if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { + if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 || + !S_ISDIR(st.st_mode)) { + if (ret == 0 && !S_ISDIR(st.st_mode)) { DEBUG(0,("'%s' is not a directory, when connecting to " "[%s]\n", conn->connectpath, lp_servicename(snum))); @@ -1058,7 +1052,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, * the same characteristics, which is likely but not guaranteed. */ - conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res); + conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn); /* * Print out the 'connected as' stuff here as we need @@ -1069,7 +1063,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) { dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address ); - dbgtext( "%s", srv_is_signing_active(smbd_server_conn) ? "signed " : ""); + dbgtext( "%s", srv_is_signing_active() ? "signed " : ""); dbgtext( "connect to service %s ", lp_servicename(snum) ); dbgtext( "initially as user %s ", conn->server_info->unix_name ); @@ -1082,7 +1076,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, return(conn); err_root_exit: - TALLOC_FREE(smb_fname_cpath); + change_to_root_user(); /* Call VFS disconnect hook */ SMB_VFS_DISCONNECT(conn); @@ -1097,8 +1091,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, * @param service ****************************************************************************/ -connection_struct *make_connection(struct smbd_server_connection *sconn, - const char *service_in, DATA_BLOB password, +connection_struct *make_connection(const char *service_in, DATA_BLOB password, const char *pdev, uint16 vuid, NTSTATUS *status) { @@ -1119,13 +1112,13 @@ connection_struct *make_connection(struct smbd_server_connection *sconn, smb_panic("make_connection: PANIC ERROR. Called as nonroot\n"); } - if (conn_num_open(sconn) > 2047) { + if (conn_num_open() > 2047) { *status = NT_STATUS_INSUFF_SERVER_RESOURCES; return NULL; } if(lp_security() != SEC_SHARE) { - vuser = get_valid_user_struct(sconn, vuid); + vuser = get_valid_user_struct(vuid); if (!vuser) { DEBUG(1,("make_connection: refusing to connect with " "no session setup\n")); @@ -1156,8 +1149,7 @@ connection_struct *make_connection(struct smbd_server_connection *sconn, } DEBUG(5, ("making a connection to [homes] service " "created at session setup time\n")); - return make_connection_snum(sconn, - vuser->homes_snum, + return make_connection_snum(vuser->homes_snum, vuser, no_pw, dev, status); } else { @@ -1167,15 +1159,14 @@ connection_struct *make_connection(struct smbd_server_connection *sconn, fstring unix_username; fstrcpy(unix_username, current_user_info.smb_name); - map_username(sconn, unix_username); + map_username(unix_username); snum = find_service(unix_username); } if (snum != -1) { DEBUG(5, ("making a connection to 'homes' " "service %s based on " "security=share\n", service_in)); - return make_connection_snum(sconn, - snum, NULL, + return make_connection_snum(snum, NULL, password, dev, status); } @@ -1186,8 +1177,7 @@ connection_struct *make_connection(struct smbd_server_connection *sconn, DATA_BLOB no_pw = data_blob_null; DEBUG(5, ("making a connection to 'homes' service [%s] " "created at session setup time\n", service_in)); - return make_connection_snum(sconn, - vuser->homes_snum, + return make_connection_snum(vuser->homes_snum, vuser, no_pw, dev, status); } @@ -1206,7 +1196,7 @@ connection_struct *make_connection(struct smbd_server_connection *sconn, return NULL; } - DEBUG(3,("%s (%s) couldn't find service %s\n", + DEBUG(0,("%s (%s) couldn't find service %s\n", get_remote_machine_name(), client_addr(get_client_fd(),addr,sizeof(addr)), service)); @@ -1225,7 +1215,7 @@ connection_struct *make_connection(struct smbd_server_connection *sconn, DEBUG(5, ("making a connection to 'normal' service %s\n", service)); - return make_connection_snum(sconn, snum, vuser, + return make_connection_snum(snum, vuser, password, dev, status); } diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 1529166d43..044e3988af 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -24,16 +24,8 @@ #include "includes.h" #include "smbd/globals.h" -#include "../libcli/auth/spnego.h" -/* For split krb5 SPNEGO blobs. */ -struct pending_auth_data { - struct pending_auth_data *prev, *next; - uint16 vuid; /* Tag for this entry. */ - uint16 smbpid; /* Alternate tag for this entry. */ - size_t needed_len; - DATA_BLOB partial_data; -}; +extern enum protocol_types Protocol; /* on a logon error possibly map the error to success if "map to guest" @@ -99,6 +91,25 @@ static int push_signature(uint8 **outbuf) } /**************************************************************************** + Start the signing engine if needed. Don't fail signing here. +****************************************************************************/ + +static void sessionsetup_start_signing_engine( + const auth_serversupplied_info *server_info, + const uint8 *inbuf) +{ + if (!server_info->guest && !srv_signing_started()) { + /* We need to start the signing engine + * here but a W2K client sends the old + * "BSRSPYL " signature instead of the + * correct one. Subsequent packets will + * be correct. + */ + srv_check_sign_mac((char *)inbuf, False); + } +} + +/**************************************************************************** Send a security blob via a session setup reply. ****************************************************************************/ @@ -251,7 +262,6 @@ static void reply_spnego_kerberos(struct smb_request *req, bool map_domainuser_to_guest = False; bool username_was_mapped; struct PAC_LOGON_INFO *logon_info = NULL; - struct smbd_server_connection *sconn = smbd_server_conn; ZERO_STRUCT(ticket); ZERO_STRUCT(ap_rep); @@ -415,7 +425,7 @@ static void reply_spnego_kerberos(struct smb_request *req, /* lookup the passwd struct, create a new user if necessary */ - username_was_mapped = map_username(sconn, user); + username_was_mapped = map_username( user ); pw = smb_getpwnam( mem_ctx, user, real_username, True ); @@ -485,40 +495,10 @@ static void reply_spnego_kerberos(struct smb_request *req, } } else { - /* - * We didn't get a PAC, we have to make up the user - * ourselves. Try to ask the pdb backend to provide - * SID consistency with ntlmssp session setup - */ - struct samu *sampass; - - sampass = samu_new(talloc_tos()); - if (sampass == NULL) { - ret = NT_STATUS_NO_MEMORY; - data_blob_free(&ap_rep); - data_blob_free(&session_key); - TALLOC_FREE(mem_ctx); - reply_nterror(req, nt_status_squash(ret)); - return; - } - - if (pdb_getsampwnam(sampass, real_username)) { - DEBUG(10, ("found user %s in passdb, calling " - "make_server_info_sam\n", real_username)); - ret = make_server_info_sam(&server_info, sampass); - } else { - /* - * User not in passdb, make it up artificially - */ - TALLOC_FREE(sampass); - DEBUG(10, ("didn't find user %s in passdb, calling " - "make_server_info_pw\n", real_username)); - ret = make_server_info_pw(&server_info, real_username, - pw); - } + ret = make_server_info_pw(&server_info, real_username, pw); if ( !NT_STATUS_IS_OK(ret) ) { - DEBUG(1,("make_server_info_[sam|pw] failed: %s!\n", + DEBUG(1,("make_server_info_pw failed: %s!\n", nt_errstr(ret))); data_blob_free(&ap_rep); data_blob_free(&session_key); @@ -556,8 +536,8 @@ static void reply_spnego_kerberos(struct smb_request *req, } } - if (!is_partial_auth_vuid(sconn, sess_vuid)) { - sess_vuid = register_initial_vuid(sconn); + if (!is_partial_auth_vuid(sess_vuid)) { + sess_vuid = register_initial_vuid(); } data_blob_free(&server_info->user_session_key); @@ -569,8 +549,7 @@ static void reply_spnego_kerberos(struct smb_request *req, * no need to free after this on success. A better interface would copy * it.... */ - sess_vuid = register_existing_vuid(sconn, - sess_vuid, + sess_vuid = register_existing_vuid(sess_vuid, server_info, nullblob, client); @@ -592,6 +571,7 @@ static void reply_spnego_kerberos(struct smb_request *req, SSVAL(req->outbuf, smb_uid, sess_vuid); + sessionsetup_start_signing_engine(server_info, req->inbuf); /* Successful logon. Keep this vuid. */ *p_invalidate_vuid = False; } @@ -632,7 +612,6 @@ static void reply_spnego_ntlmssp(struct smb_request *req, { DATA_BLOB response; struct auth_serversupplied_info *server_info = NULL; - struct smbd_server_connection *sconn = smbd_server_conn; if (NT_STATUS_IS_OK(nt_status)) { server_info = (*auth_ntlmssp_state)->server_info; @@ -650,7 +629,7 @@ static void reply_spnego_ntlmssp(struct smb_request *req, if (NT_STATUS_IS_OK(nt_status)) { DATA_BLOB nullblob = data_blob_null; - if (!is_partial_auth_vuid(sconn, vuid)) { + if (!is_partial_auth_vuid(vuid)) { nt_status = NT_STATUS_LOGON_FAILURE; goto out; } @@ -663,7 +642,7 @@ static void reply_spnego_ntlmssp(struct smb_request *req, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length); /* register_existing_vuid keeps the server info */ - if (register_existing_vuid(sconn, vuid, + if (register_existing_vuid(vuid, server_info, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user) != vuid) { @@ -681,6 +660,9 @@ static void reply_spnego_ntlmssp(struct smb_request *req, if (server_info->guest) { SSVAL(req->outbuf,smb_vwv2,1); } + + sessionsetup_start_signing_engine(server_info, + (uint8 *)req->inbuf); } out: @@ -705,7 +687,7 @@ static void reply_spnego_ntlmssp(struct smb_request *req, auth_ntlmssp_end(auth_ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); } } } @@ -791,12 +773,11 @@ static void reply_spnego_negotiate(struct smb_request *req, DATA_BLOB chal; char *kerb_mech = NULL; NTSTATUS status; - struct smbd_server_connection *sconn = smbd_server_conn; status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech); if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); reply_nterror(req, nt_status_squash(status)); return; } @@ -813,7 +794,7 @@ static void reply_spnego_negotiate(struct smb_request *req, data_blob_free(&secblob); if (destroy_vuid) { /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); } SAFE_FREE(kerb_mech); return; @@ -836,7 +817,7 @@ static void reply_spnego_negotiate(struct smb_request *req, status = auth_ntlmssp_start(auth_ntlmssp_state); if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); reply_nterror(req, nt_status_squash(status)); return; } @@ -868,14 +849,13 @@ static void reply_spnego_auth(struct smb_request *req, DATA_BLOB auth_reply = data_blob_null; DATA_BLOB secblob = data_blob_null; NTSTATUS status = NT_STATUS_LOGON_FAILURE; - struct smbd_server_connection *sconn = smbd_server_conn; if (!spnego_parse_auth(blob1, &auth)) { #if 0 file_save("auth.dat", blob1.data, blob1.length); #endif /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); reply_nterror(req, nt_status_squash( NT_STATUS_LOGON_FAILURE)); @@ -890,7 +870,7 @@ static void reply_spnego_auth(struct smb_request *req, if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); reply_nterror(req, nt_status_squash(status)); return; } @@ -907,7 +887,7 @@ static void reply_spnego_auth(struct smb_request *req, data_blob_free(&auth); if (destroy_vuid) { /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); } SAFE_FREE(kerb_mech); return; @@ -918,7 +898,7 @@ static void reply_spnego_auth(struct smb_request *req, if (kerb_mech) { /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); DEBUG(3,("reply_spnego_auth: network " "misconfiguration, client sent us a " "krb5 ticket and kerberos security " @@ -936,7 +916,7 @@ static void reply_spnego_auth(struct smb_request *req, status = auth_ntlmssp_start(auth_ntlmssp_state); if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); reply_nterror(req, nt_status_squash(status)); return; } @@ -963,13 +943,12 @@ static void reply_spnego_auth(struct smb_request *req, Delete an entry on the list. ****************************************************************************/ -static void delete_partial_auth(struct smbd_server_connection *sconn, - struct pending_auth_data *pad) +static void delete_partial_auth(struct pending_auth_data *pad) { if (!pad) { return; } - DLIST_REMOVE(sconn->smb1.pd_list, pad); + DLIST_REMOVE(pd_list, pad); data_blob_free(&pad->partial_data); SAFE_FREE(pad); } @@ -978,17 +957,11 @@ static void delete_partial_auth(struct smbd_server_connection *sconn, Search for a partial SPNEGO auth fragment matching an smbpid. ****************************************************************************/ -static struct pending_auth_data *get_pending_auth_data( - struct smbd_server_connection *sconn, - uint16_t smbpid) +static struct pending_auth_data *get_pending_auth_data(uint16 smbpid) { struct pending_auth_data *pad; -/* - * NOTE: using the smbpid here is completely wrong... - * see [MS-SMB] - * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request - */ - for (pad = sconn->smb1.pd_list; pad; pad = pad->next) { + + for (pad = pd_list; pad; pad = pad->next) { if (pad->smbpid == smbpid) { break; } @@ -1002,21 +975,20 @@ static struct pending_auth_data *get_pending_auth_data( the blob to be more than 64k. ****************************************************************************/ -static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn, - uint16 smbpid, uint16 vuid, - DATA_BLOB *pblob) +static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, + DATA_BLOB *pblob) { struct pending_auth_data *pad = NULL; ASN1_DATA *data; size_t needed_len = 0; - pad = get_pending_auth_data(sconn, smbpid); + pad = get_pending_auth_data(smbpid); /* Ensure we have some data. */ if (pblob->length == 0) { /* Caller can cope. */ DEBUG(2,("check_spnego_blob_complete: zero blob length !\n")); - delete_partial_auth(sconn, pad); + delete_partial_auth(pad); return NT_STATUS_OK; } @@ -1037,7 +1009,7 @@ static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn, (unsigned int)pad->partial_data.length, (unsigned int)copy_len )); - delete_partial_auth(sconn, pad); + delete_partial_auth(pad); return NT_STATUS_INVALID_PARAMETER; } @@ -1073,7 +1045,7 @@ static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn, data_blob_free(pblob); *pblob = pad->partial_data; ZERO_STRUCT(pad->partial_data); - delete_partial_auth(sconn, pad); + delete_partial_auth(pad); return NT_STATUS_OK; } @@ -1158,7 +1130,7 @@ static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn, } pad->smbpid = smbpid; pad->vuid = vuid; - DLIST_ADD(sconn->smb1.pd_list, pad); + DLIST_ADD(pd_list, pad); return NT_STATUS_MORE_PROCESSING_REQUIRED; } @@ -1184,7 +1156,6 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) user_struct *vuser = NULL; NTSTATUS status = NT_STATUS_OK; uint16 smbpid = req->smbpid; - struct smbd_server_connection *sconn = smbd_server_conn; DEBUG(3,("Doing spnego session setup\n")); @@ -1247,11 +1218,10 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) } /* Did we get a valid vuid ? */ - if (!is_partial_auth_vuid(sconn, vuid)) { + if (!is_partial_auth_vuid(vuid)) { /* No, then try and see if this is an intermediate sessionsetup * for a large SPNEGO packet. */ - struct pending_auth_data *pad; - pad = get_pending_auth_data(sconn, smbpid); + struct pending_auth_data *pad = get_pending_auth_data(smbpid); if (pad) { DEBUG(10,("reply_sesssetup_and_X_spnego: found " "pending vuid %u\n", @@ -1261,9 +1231,9 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) } /* Do we have a valid vuid now ? */ - if (!is_partial_auth_vuid(sconn, vuid)) { + if (!is_partial_auth_vuid(vuid)) { /* No, start a new authentication setup. */ - vuid = register_initial_vuid(sconn); + vuid = register_initial_vuid(); if (vuid == UID_FIELD_INVALID) { data_blob_free(&blob1); reply_nterror(req, nt_status_squash( @@ -1272,7 +1242,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) } } - vuser = get_partial_auth_user_struct(sconn, vuid); + vuser = get_partial_auth_user_struct(vuid); /* This MUST be valid. */ if (!vuser) { smb_panic("reply_sesssetup_and_X_spnego: invalid vuid."); @@ -1283,12 +1253,12 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) * field is 4k. Bug #4400. JRA. */ - status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1); + status = check_spnego_blob_complete(smbpid, vuid, &blob1); if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { /* Real error - kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); } data_blob_free(&blob1); reply_nterror(req, nt_status_squash(status)); @@ -1322,7 +1292,7 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state); if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ - invalidate_vuid(sconn, vuid); + invalidate_vuid(vuid); data_blob_free(&blob1); reply_nterror(req, nt_status_squash(status)); return; @@ -1422,9 +1392,8 @@ void reply_sesssetup_and_X(struct smb_request *req) uint16 smb_flag2 = req->flags2; NTSTATUS nt_status; - struct smbd_server_connection *sconn = smbd_server_conn; - bool doencrypt = sconn->smb1.negprot.encrypted_passwords; + bool doencrypt = global_encrypted_passwords_negotiated; START_PROFILE(SMBsesssetupX); @@ -1439,7 +1408,7 @@ void reply_sesssetup_and_X(struct smb_request *req) if (req->wct == 12 && (req->flags2 & FLAGS2_EXTENDED_SECURITY)) { - if (!sconn->smb1.negprot.spnego) { + if (!global_spnego_negotiated) { DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt " "at SPNEGO session setup when it was not " "negotiated.\n")); @@ -1460,7 +1429,7 @@ void reply_sesssetup_and_X(struct smb_request *req) smb_bufsize = SVAL(req->vwv+2, 0); - if (get_Protocol() < PROTOCOL_NT1) { + if (Protocol < PROTOCOL_NT1) { uint16 passlen1 = SVAL(req->vwv+7, 0); /* Never do NT status codes with protocols before NT1 as we @@ -1654,7 +1623,7 @@ void reply_sesssetup_and_X(struct smb_request *req) domain, user, get_remote_machine_name())); if (*user) { - if (sconn->smb1.negprot.spnego) { + if (global_spnego_negotiated) { /* This has to be here, because this is a perfectly * valid behaviour for guest logons :-( */ @@ -1683,9 +1652,9 @@ void reply_sesssetup_and_X(struct smb_request *req) data_blob_free(&nt_resp); data_blob_clear_free(&plaintext_password); - map_username(sconn, sub_user); - add_session_user(sconn, sub_user); - add_session_workgroup(sconn, domain); + map_username(sub_user); + add_session_user(sub_user); + add_session_workgroup(domain); /* Then force it to null for the benfit of the code below */ user = ""; } @@ -1695,9 +1664,7 @@ void reply_sesssetup_and_X(struct smb_request *req) nt_status = check_guest_password(&server_info); } else if (doencrypt) { - struct auth_context *negprot_auth_context = NULL; - negprot_auth_context = sconn->smb1.negprot.auth_context; - if (!negprot_auth_context) { + if (!negprot_global_auth_context) { DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted " "session setup without negprot denied!\n")); reply_nterror(req, nt_status_squash( @@ -1709,8 +1676,8 @@ void reply_sesssetup_and_X(struct smb_request *req) domain, lm_resp, nt_resp); if (NT_STATUS_IS_OK(nt_status)) { - nt_status = negprot_auth_context->check_ntlm_password( - negprot_auth_context, + nt_status = negprot_global_auth_context->check_ntlm_password( + negprot_global_auth_context, user_info, &server_info); } @@ -1787,7 +1754,7 @@ void reply_sesssetup_and_X(struct smb_request *req) /* it's ok - setup a reply */ reply_outbuf(req, 3, 0); - if (get_Protocol() >= PROTOCOL_NT1) { + if (Protocol >= PROTOCOL_NT1) { push_signature(&req->outbuf); /* perhaps grab OS version here?? */ } @@ -1804,7 +1771,7 @@ void reply_sesssetup_and_X(struct smb_request *req) TALLOC_FREE(server_info); } else { /* Ignore the initial vuid. */ - sess_vuid = register_initial_vuid(sconn); + sess_vuid = register_initial_vuid(); if (sess_vuid == UID_FIELD_INVALID) { data_blob_free(&nt_resp); data_blob_free(&lm_resp); @@ -1814,7 +1781,7 @@ void reply_sesssetup_and_X(struct smb_request *req) return; } /* register_existing_vuid keeps the server info */ - sess_vuid = register_existing_vuid(sconn, sess_vuid, + sess_vuid = register_existing_vuid(sess_vuid, server_info, nt_resp.data ? nt_resp : lm_resp, sub_user); @@ -1829,6 +1796,8 @@ void reply_sesssetup_and_X(struct smb_request *req) /* current_user_info is changed on new vuid */ reload_services( True ); + + sessionsetup_start_signing_engine(server_info, req->inbuf); } data_blob_free(&nt_resp); @@ -1838,11 +1807,10 @@ void reply_sesssetup_and_X(struct smb_request *req) SSVAL(req->inbuf,smb_uid,sess_vuid); req->vuid = sess_vuid; - if (!sconn->smb1.sessions.done_sesssetup) { - sconn->smb1.sessions.max_send = - MIN(sconn->smb1.sessions.max_send,smb_bufsize); - } - sconn->smb1.sessions.done_sesssetup = true; + if (!done_sesssetup) + max_send = MIN(max_send,smb_bufsize); + + done_sesssetup = True; END_PROFILE(SMBsesssetupX); chain_reply(req); diff --git a/source3/smbd/share_access.c b/source3/smbd/share_access.c index a300d6f1de..c72251b5a7 100644 --- a/source3/smbd/share_access.c +++ b/source3/smbd/share_access.c @@ -18,7 +18,6 @@ */ #include "includes.h" -#include "smbd/globals.h" /* * No prefix means direct username @@ -73,7 +72,6 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx, const char *prefix; DOM_SID sid; enum lsa_SidType type; - struct smbd_server_connection *sconn = smbd_server_conn; if (username != NULL) { name = talloc_sub_basic(mem_ctx, username, domain, name); @@ -130,10 +128,8 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx, continue; } if (*prefix == '&') { - if (username) { - if (user_in_netgroup(sconn, username, name)) { - return True; - } + if (user_in_netgroup(username, name)) { + return True; } continue; } diff --git a/source3/smbd/signing.c b/source3/smbd/signing.c deleted file mode 100644 index 9b5e3452f9..0000000000 --- a/source3/smbd/signing.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB Signing Code - Copyright (C) Jeremy Allison 2003. - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003 - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" - - -/*********************************************************** - Called to validate an incoming packet from the client. -************************************************************/ - -bool srv_check_sign_mac(struct smbd_server_connection *conn, - const char *inbuf, uint32_t *seqnum) -{ - /* Check if it's a non-session message. */ - if(CVAL(inbuf,0)) { - return true; - } - - *seqnum = smb_signing_next_seqnum(conn->smb1.signing_state, false); - return smb_signing_check_pdu(conn->smb1.signing_state, - (const uint8_t *)inbuf, - *seqnum); -} - -/*********************************************************** - Called to sign an outgoing packet to the client. -************************************************************/ - -void srv_calculate_sign_mac(struct smbd_server_connection *conn, - char *outbuf, uint32_t seqnum) -{ - /* Check if it's a non-session message. */ - if(CVAL(outbuf,0)) { - return; - } - - smb_signing_sign_pdu(conn->smb1.signing_state, (uint8_t *)outbuf, seqnum); -} - - -/*********************************************************** - Called to indicate a oneway request -************************************************************/ -void srv_cancel_sign_response(struct smbd_server_connection *conn) -{ - smb_signing_cancel_reply(conn->smb1.signing_state, true); -} - -/*********************************************************** - Called by server negprot when signing has been negotiated. -************************************************************/ - -bool srv_init_signing(struct smbd_server_connection *conn) -{ - bool allowed = true; - bool mandatory = false; - - switch (lp_server_signing()) { - case Required: - mandatory = true; - break; - case Auto: - break; - case True: - break; - case False: - allowed = false; - break; - } - - conn->smb1.signing_state = smb_signing_init(smbd_event_context(), - allowed, mandatory); - if (!conn->smb1.signing_state) { - return false; - } - - return true; -} - -void srv_set_signing_negotiated(struct smbd_server_connection *conn) -{ - smb_signing_set_negotiated(conn->smb1.signing_state); -} - -/*********************************************************** - Returns whether signing is active. We can't use sendfile or raw - reads/writes if it is. -************************************************************/ - -bool srv_is_signing_active(struct smbd_server_connection *conn) -{ - return smb_signing_is_active(conn->smb1.signing_state); -} - - -/*********************************************************** - Returns whether signing is negotiated. We can't use it unless it was - in the negprot. -************************************************************/ - -bool srv_is_signing_negotiated(struct smbd_server_connection *conn) -{ - return smb_signing_is_negotiated(conn->smb1.signing_state); -} - -/*********************************************************** - Turn on signing from this packet onwards. -************************************************************/ - -void srv_set_signing(struct smbd_server_connection *conn, - const DATA_BLOB user_session_key, - const DATA_BLOB response) -{ - bool negotiated; - bool mandatory; - - if (!user_session_key.length) - return; - - negotiated = smb_signing_is_negotiated(conn->smb1.signing_state); - mandatory = smb_signing_is_mandatory(conn->smb1.signing_state); - - if (!negotiated && !mandatory) { - DEBUG(5,("srv_set_signing: signing negotiated = %u, " - "mandatory_signing = %u. Not allowing smb signing.\n", - negotiated, mandatory)); - return; - } - - if (!smb_signing_activate(conn->smb1.signing_state, - user_session_key, response)) { - return; - } - - DEBUG(3,("srv_set_signing: turning on SMB signing: " - "signing negotiated = %u, mandatory_signing = %u.\n", - negotiated, mandatory)); -} - diff --git a/source3/smbd/smb2_break.c b/source3/smbd/smb2_break.c deleted file mode 100644 index 879d59f89e..0000000000 --- a/source3/smbd/smb2_break.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static struct tevent_req *smbd_smb2_oplock_break_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint8_t in_oplock_level, - uint64_t in_file_id_volatile); -static NTSTATUS smbd_smb2_oplock_break_recv(struct tevent_req *req, - uint8_t *out_oplock_level); - -static void smbd_smb2_request_oplock_break_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_break(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - size_t expected_body_size = 0x18; - size_t body_size; - uint8_t in_oplock_level; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - struct tevent_req *subreq; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_oplock_level = CVAL(inbody, 0x02); - /* 0x03 1 bytes reserved */ - /* 0x04 4 bytes reserved */ - in_file_id_persistent = BVAL(inbody, 0x08); - in_file_id_volatile = BVAL(inbody, 0x10); - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - subreq = smbd_smb2_oplock_break_send(req, - req->sconn->smb2.event_ctx, - req, - in_oplock_level, - in_file_id_volatile); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_oplock_break_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_oplock_break_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - const uint8_t *inbody; - int i = req->current_idx; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - uint8_t out_oplock_level = 0; - DATA_BLOB outbody; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_oplock_break_recv(subreq, &out_oplock_level); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - in_file_id_persistent = BVAL(inbody, 0x08); - in_file_id_volatile = BVAL(inbody, 0x10); - - outbody = data_blob_talloc(req->out.vector, NULL, 0x18); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x18); /* struct size */ - SCVAL(outbody.data, 0x02, - out_oplock_level); /* oplock level */ - SCVAL(outbody.data, 0x03, 0); /* reserved */ - SIVAL(outbody.data, 0x04, 0); /* reserved */ - SBVAL(outbody.data, 0x08, - in_file_id_persistent); /* file id (persistent) */ - SBVAL(outbody.data, 0x10, - in_file_id_volatile); /* file id (volatile) */ - - error = smbd_smb2_request_done(req, outbody, NULL); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } -} - -struct smbd_smb2_oplock_break_state { - struct smbd_smb2_request *smb2req; - uint8_t out_oplock_level; -}; - -static struct tevent_req *smbd_smb2_oplock_break_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint8_t in_oplock_level, - uint64_t in_file_id_volatile) -{ - struct tevent_req *req; - struct smbd_smb2_oplock_break_state *state; - struct smb_request *smbreq; - connection_struct *conn = smb2req->tcon->compat_conn; - files_struct *fsp; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_oplock_break_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - state->out_oplock_level = SMB2_OPLOCK_LEVEL_NONE; - - DEBUG(10,("smbd_smb2_oplock_break_send: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (conn != fsp->conn) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smb2req->session->vuid != fsp->vuid) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); - return tevent_req_post(req, ev); -} - -static NTSTATUS smbd_smb2_oplock_break_recv(struct tevent_req *req, - uint8_t *out_oplock_level) -{ - NTSTATUS status; - struct smbd_smb2_oplock_break_state *state = - tevent_req_data(req, - struct smbd_smb2_oplock_break_state); - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - *out_oplock_level = state->out_oplock_level; - - tevent_req_received(req); - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_close.c b/source3/smbd/smb2_close.c deleted file mode 100644 index b28fb72979..0000000000 --- a/source3/smbd/smb2_close.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req, - uint16_t in_flags, - uint64_t in_file_id_volatile); - -NTSTATUS smbd_smb2_request_process_close(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - size_t expected_body_size = 0x18; - size_t body_size; - uint16_t in_flags; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - NTSTATUS status; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_flags = SVAL(inbody, 0x02); - in_file_id_persistent = BVAL(inbody, 0x08); - in_file_id_volatile = BVAL(inbody, 0x10); - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - status = smbd_smb2_close(req, - in_flags, - in_file_id_volatile); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - outbody = data_blob_talloc(req->out.vector, NULL, 0x3C); - if (outbody.data == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - - SSVAL(outbody.data, 0x00, 0x3C); /* struct size */ - SSVAL(outbody.data, 0x02, 0); /* flags */ - SIVAL(outbody.data, 0x04, 0); /* reserved */ - SBVAL(outbody.data, 0x08, 0); /* creation time */ - SBVAL(outbody.data, 0x10, 0); /* last access time */ - SBVAL(outbody.data, 0x18, 0); /* last write time */ - SBVAL(outbody.data, 0x20, 0); /* change time */ - SBVAL(outbody.data, 0x28, 0); /* allocation size */ - SBVAL(outbody.data, 0x30, 0); /* end of size */ - SIVAL(outbody.data, 0x38, 0); /* file attributes */ - - return smbd_smb2_request_done(req, outbody, NULL); -} - -static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req, - uint16_t in_flags, - uint64_t in_file_id_volatile) -{ - NTSTATUS status; - struct smb_request *smbreq; - connection_struct *conn = req->tcon->compat_conn; - files_struct *fsp; - - DEBUG(10,("smbd_smb2_close: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(req); - if (smbreq == NULL) { - return NT_STATUS_NO_MEMORY; - } - - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - return NT_STATUS_FILE_CLOSED; - } - if (conn != fsp->conn) { - return NT_STATUS_FILE_CLOSED; - } - if (req->session->vuid != fsp->vuid) { - return NT_STATUS_FILE_CLOSED; - } - - status = close_file(smbreq, fsp, NORMAL_CLOSE); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n", - fsp_str_dbg(fsp), nt_errstr(status))); - return status; - } - - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c deleted file mode 100644 index 3cf8b185b0..0000000000 --- a/source3/smbd/smb2_create.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint8_t in_oplock_level, - uint32_t in_impersonation_level, - uint32_t in_desired_access, - uint32_t in_file_attributes, - uint32_t in_share_access, - uint32_t in_create_disposition, - uint32_t in_create_options, - const char *in_name, - struct smb2_create_blobs in_context_blobs); -static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - uint8_t *out_oplock_level, - uint32_t *out_create_action, - NTTIME *out_creation_time, - NTTIME *out_last_access_time, - NTTIME *out_last_write_time, - NTTIME *out_change_time, - uint64_t *out_allocation_size, - uint64_t *out_end_of_file, - uint32_t *out_file_attributes, - uint64_t *out_file_id_volatile, - struct smb2_create_blobs *out_context_blobs); - -static void smbd_smb2_request_create_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *req) -{ - const uint8_t *inbody; - int i = req->current_idx; - size_t expected_body_size = 0x39; - size_t body_size; - uint8_t in_oplock_level; - uint32_t in_impersonation_level; - uint32_t in_desired_access; - uint32_t in_file_attributes; - uint32_t in_share_access; - uint32_t in_create_disposition; - uint32_t in_create_options; - uint16_t in_name_offset; - uint16_t in_name_length; - DATA_BLOB in_name_buffer; - char *in_name_string; - size_t in_name_string_size; - uint32_t name_offset = 0; - uint32_t name_available_length = 0; - uint32_t in_context_offset; - uint32_t in_context_length; - DATA_BLOB in_context_buffer; - struct smb2_create_blobs in_context_blobs; - uint32_t context_offset = 0; - uint32_t context_available_length = 0; - uint32_t dyn_offset; - NTSTATUS status; - bool ok; - struct tevent_req *subreq; - - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_oplock_level = CVAL(inbody, 0x03); - in_impersonation_level = IVAL(inbody, 0x04); - in_desired_access = IVAL(inbody, 0x18); - in_file_attributes = IVAL(inbody, 0x1C); - in_share_access = IVAL(inbody, 0x20); - in_create_disposition = IVAL(inbody, 0x24); - in_create_options = IVAL(inbody, 0x28); - in_name_offset = SVAL(inbody, 0x2C); - in_name_length = SVAL(inbody, 0x2E); - in_context_offset = IVAL(inbody, 0x30); - in_context_length = IVAL(inbody, 0x34); - - /* - * First check if the dynamic name and context buffers - * are correctly specified. - * - * Note: That we don't check if the name and context buffers - * overlap - */ - - dyn_offset = SMB2_HDR_BODY + (body_size & 0xFFFFFFFE); - - if (in_name_offset == 0 && in_name_length == 0) { - /* This is ok */ - name_offset = 0; - } else if (in_name_offset < dyn_offset) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } else { - name_offset = in_name_offset - dyn_offset; - } - - if (name_offset > req->in.vector[i+2].iov_len) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - name_available_length = req->in.vector[i+2].iov_len - name_offset; - - if (in_name_length > name_available_length) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_name_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base + - name_offset; - in_name_buffer.length = in_name_length; - - if (in_context_offset == 0 && in_context_length == 0) { - /* This is ok */ - context_offset = 0; - } else if (in_context_offset < dyn_offset) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } else { - context_offset = in_context_offset - dyn_offset; - } - - if (context_offset > req->in.vector[i+2].iov_len) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - context_available_length = req->in.vector[i+2].iov_len - context_offset; - - if (in_context_length > context_available_length) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_context_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base + - context_offset; - in_context_buffer.length = in_context_length; - - /* - * Now interpret the name and context buffers - */ - - ok = convert_string_talloc(req, CH_UTF16, CH_UNIX, - in_name_buffer.data, - in_name_buffer.length, - &in_name_string, - &in_name_string_size, false); - if (!ok) { - return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER); - } - - ZERO_STRUCT(in_context_blobs); - status = smb2_create_blob_parse(req, in_context_buffer, &in_context_blobs); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - - subreq = smbd_smb2_create_send(req, - req->sconn->smb2.event_ctx, - req, - in_oplock_level, - in_impersonation_level, - in_desired_access, - in_file_attributes, - in_share_access, - in_create_disposition, - in_create_options, - in_name_string, - in_context_blobs); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_create_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_create_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - int i = req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - DATA_BLOB outdyn; - uint8_t out_oplock_level = 0; - uint32_t out_create_action = 0; - NTTIME out_creation_time = 0; - NTTIME out_last_access_time = 0; - NTTIME out_last_write_time = 0; - NTTIME out_change_time = 0; - uint64_t out_allocation_size = 0; - uint64_t out_end_of_file = 0; - uint32_t out_file_attributes = 0; - uint64_t out_file_id_volatile = 0; - struct smb2_create_blobs out_context_blobs; - DATA_BLOB out_context_buffer; - uint16_t out_context_buffer_offset = 0; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_create_recv(subreq, - req, - &out_oplock_level, - &out_create_action, - &out_creation_time, - &out_last_access_time, - &out_last_write_time, - &out_change_time, - &out_allocation_size, - &out_end_of_file, - &out_file_attributes, - &out_file_id_volatile, - &out_context_blobs); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - status = smb2_create_blob_push(req, &out_context_buffer, out_context_blobs); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - if (out_context_buffer.length > 0) { - out_context_buffer_offset = SMB2_HDR_BODY + 0x58; - } - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - outbody = data_blob_talloc(req->out.vector, NULL, 0x58); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x58 + 1); /* struct size */ - SCVAL(outbody.data, 0x02, - out_oplock_level); /* oplock level */ - SCVAL(outbody.data, 0x03, 0); /* reserved */ - SIVAL(outbody.data, 0x04, - out_create_action); /* create action */ - SBVAL(outbody.data, 0x08, - out_creation_time); /* creation time */ - SBVAL(outbody.data, 0x10, - out_last_access_time); /* last access time */ - SBVAL(outbody.data, 0x18, - out_last_write_time); /* last write time */ - SBVAL(outbody.data, 0x20, - out_change_time); /* change time */ - SBVAL(outbody.data, 0x28, - out_allocation_size); /* allocation size */ - SBVAL(outbody.data, 0x30, - out_end_of_file); /* end of file */ - SIVAL(outbody.data, 0x38, - out_file_attributes); /* file attributes */ - SIVAL(outbody.data, 0x3C, 0); /* reserved */ - SBVAL(outbody.data, 0x40, 0); /* file id (persistent) */ - SBVAL(outbody.data, 0x48, - out_file_id_volatile); /* file id (volatile) */ - SIVAL(outbody.data, 0x50, - out_context_buffer_offset); /* create contexts offset */ - SIVAL(outbody.data, 0x54, - out_context_buffer.length); /* create contexts length */ - - outdyn = out_context_buffer; - - error = smbd_smb2_request_done(req, outbody, &outdyn); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } -} - -struct smbd_smb2_create_state { - struct smbd_smb2_request *smb2req; - uint8_t out_oplock_level; - uint32_t out_create_action; - NTTIME out_creation_time; - NTTIME out_last_access_time; - NTTIME out_last_write_time; - NTTIME out_change_time; - uint64_t out_allocation_size; - uint64_t out_end_of_file; - uint32_t out_file_attributes; - uint64_t out_file_id_volatile; - struct smb2_create_blobs out_context_blobs; -}; - -static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint8_t in_oplock_level, - uint32_t in_impersonation_level, - uint32_t in_desired_access, - uint32_t in_file_attributes, - uint32_t in_share_access, - uint32_t in_create_disposition, - uint32_t in_create_options, - const char *in_name, - struct smb2_create_blobs in_context_blobs) -{ - struct tevent_req *req; - struct smbd_smb2_create_state *state; - NTSTATUS status; - struct smb_request *smbreq; - files_struct *result; - int info; - struct timespec write_time_ts; - struct smb2_create_blobs out_context_blobs; - - ZERO_STRUCT(out_context_blobs); - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_create_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - - DEBUG(10,("smbd_smb2_create: name[%s]\n", - in_name)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - - if (IS_IPC(smbreq->conn)) { - const char *pipe_name = in_name; - - if (!lp_nt_pipe_support()) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return tevent_req_post(req, ev); - } - - /* Strip \\ off the name. */ - if (pipe_name[0] == '\\') { - pipe_name++; - } - - status = open_np_file(smbreq, pipe_name, &result); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - info = FILE_WAS_OPENED; - } else if (CAN_PRINT(smbreq->conn)) { - status = file_new(smbreq, smbreq->conn, &result); - if(!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - status = print_fsp_open(smbreq, - smbreq->conn, - in_name, - smbreq->vuid, - result); - if (!NT_STATUS_IS_OK(status)) { - file_free(smbreq, result); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - info = FILE_WAS_CREATED; - } else { - char *fname; - struct smb_filename *smb_fname = NULL; - struct smb2_create_blob *exta = NULL; - struct ea_list *ea_list = NULL; - struct smb2_create_blob *mxac = NULL; - NTTIME max_access_time = 0; - struct smb2_create_blob *secd = NULL; - struct security_descriptor *sec_desc = NULL; - struct smb2_create_blob *dhnq = NULL; - struct smb2_create_blob *dhnc = NULL; - struct smb2_create_blob *alsi = NULL; - uint64_t allocation_size = 0; - struct smb2_create_blob *twrp = NULL; - struct smb2_create_blob *qfid = NULL; - - exta = smb2_create_blob_find(&in_context_blobs, - SMB2_CREATE_TAG_EXTA); - mxac = smb2_create_blob_find(&in_context_blobs, - SMB2_CREATE_TAG_MXAC); - secd = smb2_create_blob_find(&in_context_blobs, - SMB2_CREATE_TAG_SECD); - dhnq = smb2_create_blob_find(&in_context_blobs, - SMB2_CREATE_TAG_DHNQ); - dhnc = smb2_create_blob_find(&in_context_blobs, - SMB2_CREATE_TAG_DHNC); - alsi = smb2_create_blob_find(&in_context_blobs, - SMB2_CREATE_TAG_ALSI); - twrp = smb2_create_blob_find(&in_context_blobs, - SMB2_CREATE_TAG_TWRP); - qfid = smb2_create_blob_find(&in_context_blobs, - SMB2_CREATE_TAG_QFID); - - fname = talloc_strdup(state, in_name); - if (tevent_req_nomem(fname, req)) { - return tevent_req_post(req, ev); - } - - if (exta) { - if (dhnc) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - ea_list = read_nttrans_ea_list(mem_ctx, - (const char *)exta->data.data, exta->data.length); - if (!ea_list) { - DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n")); - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - } - - if (mxac) { - if (dhnc) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - if (mxac->data.length == 0) { - max_access_time = 0; - } else if (mxac->data.length == 8) { - max_access_time = BVAL(mxac->data.data, 0); - } else { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - } - - if (secd) { - enum ndr_err_code ndr_err; - - if (dhnc) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - sec_desc = talloc_zero(state, struct security_descriptor); - if (tevent_req_nomem(sec_desc, req)) { - return tevent_req_post(req, ev); - } - - ndr_err = ndr_pull_struct_blob(&secd->data, - sec_desc, NULL, sec_desc, - (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(2,("ndr_pull_security_descriptor failed: %s\n", - ndr_errstr(ndr_err))); - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - } - - if (dhnq) { - if (dhnc) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - if (dhnq->data.length != 16) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - /* - * we don't support durable handles yet - * and have to ignore this - */ - } - - if (dhnc) { - if (dhnc->data.length != 16) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - /* we don't support durable handles yet */ - tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); - return tevent_req_post(req, ev); - } - - if (alsi) { - if (dhnc) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - if (alsi->data.length != 8) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - allocation_size = BVAL(alsi->data.data, 0); - } - - if (twrp) { - NTTIME nttime; - time_t t; - struct tm *tm; - - if (dhnc) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - if (twrp->data.length != 8) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - nttime = BVAL(twrp->data.data, 0); - t = nt_time_to_unix(nttime); - tm = gmtime(&t); - - TALLOC_FREE(fname); - fname = talloc_asprintf(state, - "@GMT-%04u.%02u.%02u-%02u.%02u.%02u\\%s", - tm->tm_year + 1900, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_hour, - tm->tm_min, - tm->tm_sec, - in_name); - if (tevent_req_nomem(fname, req)) { - return tevent_req_post(req, ev); - } - } - - if (qfid) { - if (qfid->data.length != 0) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - } - - /* these are ignored for SMB2 */ - in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */ - in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */ - - /* convert '\\' into '/' */ - status = check_path_syntax(fname); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - status = filename_convert(req, - smbreq->conn, - smbreq->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - status = SMB_VFS_CREATE_FILE(smbreq->conn, - smbreq, - 0, /* root_dir_fid */ - smb_fname, - in_desired_access, - in_share_access, - in_create_disposition, - in_create_options, - in_file_attributes, - 0, /* oplock_request */ - allocation_size, - sec_desc, - ea_list, - &result, - &info); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - if (mxac) { - NTTIME last_write_time; - - unix_timespec_to_nt_time(&last_write_time, - result->fsp_name->st.st_ex_mtime); - if (last_write_time != max_access_time) { - uint8_t p[8]; - uint32_t max_access_granted; - DATA_BLOB blob = data_blob_const(p, sizeof(p)); - - status = smbd_check_open_rights(smbreq->conn, - result->fsp_name, - SEC_FLAG_MAXIMUM_ALLOWED, - &max_access_granted); - - SIVAL(p, 0, NT_STATUS_V(status)); - SIVAL(p, 4, max_access_granted); - - status = smb2_create_blob_add(state, - &out_context_blobs, - SMB2_CREATE_TAG_MXAC, - blob); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - } - } - - if (qfid) { - uint8_t p[32]; - DATA_BLOB blob = data_blob_const(p, sizeof(p)); - - ZERO_STRUCT(p); - - /* TODO: maybe use result->file_id */ - SIVAL(p, 0, result->fsp_name->st.st_ex_ino);/* FileIndexLow */ - SIVAL(p, 4, result->fsp_name->st.st_ex_dev);/* FileIndexHigh */ - - status = smb2_create_blob_add(state, &out_context_blobs, - SMB2_CREATE_TAG_QFID, - blob); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - } - } - - smb2req->compat_chain_fsp = smbreq->chain_fsp; - - state->out_oplock_level = 0; - if ((in_create_disposition == FILE_SUPERSEDE) - && (info == FILE_WAS_OVERWRITTEN)) { - state->out_create_action = FILE_WAS_SUPERSEDED; - } else { - state->out_create_action = info; - } - state->out_file_attributes = dos_mode(result->conn, - result->fsp_name); - /* Deal with other possible opens having a modified - write time. JRA. */ - ZERO_STRUCT(write_time_ts); - get_file_infos(result->file_id, NULL, &write_time_ts); - if (!null_timespec(write_time_ts)) { - update_stat_ex_mtime(&result->fsp_name->st, write_time_ts); - } - - unix_timespec_to_nt_time(&state->out_creation_time, - get_create_timespec(smbreq->conn, result, - result->fsp_name)); - unix_timespec_to_nt_time(&state->out_last_access_time, - result->fsp_name->st.st_ex_atime); - unix_timespec_to_nt_time(&state->out_last_write_time, - result->fsp_name->st.st_ex_mtime); - unix_timespec_to_nt_time(&state->out_change_time, - get_change_timespec(smbreq->conn, result, - result->fsp_name)); - state->out_allocation_size = - result->fsp_name->st.st_ex_blksize * - result->fsp_name->st.st_ex_blocks; - state->out_end_of_file = result->fsp_name->st.st_ex_size; - if (state->out_file_attributes == 0) { - state->out_file_attributes = FILE_ATTRIBUTE_NORMAL; - } - state->out_file_id_volatile = result->fnum; - state->out_context_blobs = out_context_blobs; - - tevent_req_done(req); - return tevent_req_post(req, ev); -} - -static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - uint8_t *out_oplock_level, - uint32_t *out_create_action, - NTTIME *out_creation_time, - NTTIME *out_last_access_time, - NTTIME *out_last_write_time, - NTTIME *out_change_time, - uint64_t *out_allocation_size, - uint64_t *out_end_of_file, - uint32_t *out_file_attributes, - uint64_t *out_file_id_volatile, - struct smb2_create_blobs *out_context_blobs) -{ - NTSTATUS status; - struct smbd_smb2_create_state *state = tevent_req_data(req, - struct smbd_smb2_create_state); - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - *out_oplock_level = state->out_oplock_level; - *out_create_action = state->out_create_action; - *out_creation_time = state->out_creation_time; - *out_last_access_time = state->out_last_access_time; - *out_last_write_time = state->out_last_write_time; - *out_change_time = state->out_change_time; - *out_allocation_size = state->out_allocation_size; - *out_end_of_file = state->out_end_of_file; - *out_file_attributes = state->out_file_attributes; - *out_file_id_volatile = state->out_file_id_volatile; - *out_context_blobs = state->out_context_blobs; - - talloc_steal(mem_ctx, state->out_context_blobs.blobs); - - tevent_req_received(req); - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_find.c b/source3/smbd/smb2_find.c deleted file mode 100644 index 546aed8db3..0000000000 --- a/source3/smbd/smb2_find.c +++ /dev/null @@ -1,454 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static struct tevent_req *smbd_smb2_find_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint8_t in_file_info_class, - uint8_t in_flags, - uint32_t in_file_index, - uint64_t in_file_id_volatile, - uint32_t in_output_buffer_length, - const char *in_file_name); -static NTSTATUS smbd_smb2_find_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out_output_buffer); - -static void smbd_smb2_request_find_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_find(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - size_t expected_body_size = 0x21; - size_t body_size; - uint8_t in_file_info_class; - uint8_t in_flags; - uint32_t in_file_index; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - uint16_t in_file_name_offset; - uint16_t in_file_name_length; - DATA_BLOB in_file_name_buffer; - char *in_file_name_string; - size_t in_file_name_string_size; - uint32_t in_output_buffer_length; - struct tevent_req *subreq; - bool ok; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_file_info_class = CVAL(inbody, 0x02); - in_flags = CVAL(inbody, 0x03); - in_file_index = IVAL(inbody, 0x04); - in_file_id_persistent = BVAL(inbody, 0x08); - in_file_id_volatile = BVAL(inbody, 0x10); - in_file_name_offset = SVAL(inbody, 0x18); - in_file_name_length = SVAL(inbody, 0x1A); - in_output_buffer_length = IVAL(inbody, 0x1C); - - if (in_file_name_offset == 0 && in_file_name_length == 0) { - /* This is ok */ - } else if (in_file_name_offset != - (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (in_file_name_length > req->in.vector[i+2].iov_len) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_file_name_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base; - in_file_name_buffer.length = in_file_name_length; - - ok = convert_string_talloc(req, CH_UTF16, CH_UNIX, - in_file_name_buffer.data, - in_file_name_buffer.length, - &in_file_name_string, - &in_file_name_string_size, false); - if (!ok) { - return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER); - } - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - subreq = smbd_smb2_find_send(req, - req->sconn->smb2.event_ctx, - req, - in_file_info_class, - in_flags, - in_file_index, - in_file_id_volatile, - in_output_buffer_length, - in_file_name_string); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_find_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_find_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - int i = req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - DATA_BLOB outdyn; - uint16_t out_output_buffer_offset; - DATA_BLOB out_output_buffer = data_blob_null; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_find_recv(subreq, - req, - &out_output_buffer); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - out_output_buffer_offset = SMB2_HDR_BODY + 0x08; - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - outbody = data_blob_talloc(req->out.vector, NULL, 0x08); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x08 + 1); /* struct size */ - SSVAL(outbody.data, 0x02, - out_output_buffer_offset); /* output buffer offset */ - SIVAL(outbody.data, 0x04, - out_output_buffer.length); /* output buffer length */ - - outdyn = out_output_buffer; - - error = smbd_smb2_request_done(req, outbody, &outdyn); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } -} - -struct smbd_smb2_find_state { - struct smbd_smb2_request *smb2req; - DATA_BLOB out_output_buffer; -}; - -static struct tevent_req *smbd_smb2_find_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint8_t in_file_info_class, - uint8_t in_flags, - uint32_t in_file_index, - uint64_t in_file_id_volatile, - uint32_t in_output_buffer_length, - const char *in_file_name) -{ - struct tevent_req *req; - struct smbd_smb2_find_state *state; - struct smb_request *smbreq; - connection_struct *conn = smb2req->tcon->compat_conn; - files_struct *fsp; - NTSTATUS status; - NTSTATUS empty_status; - uint32_t info_level; - uint32_t max_count; - char *pdata; - char *base_data; - char *end_data; - int last_entry_off = 0; - uint64_t off = 0; - uint32_t num = 0; - uint32_t dirtype = aHIDDEN | aSYSTEM | aDIR; - const char *directory; - bool dont_descend = false; - bool ask_sharemode = true; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_find_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - state->out_output_buffer = data_blob_null; - - DEBUG(10,("smbd_smb2_find_send: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (conn != fsp->conn) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smb2req->session->vuid != fsp->vuid) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - if (!fsp->is_directory) { - tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); - return tevent_req_post(req, ev); - } - - directory = fsp->fsp_name->base_name; - - if (strcmp(in_file_name, "") == 0) { - tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID); - return tevent_req_post(req, ev); - } - if (strcmp(in_file_name, "\\") == 0) { - tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID); - return tevent_req_post(req, ev); - } - if (strcmp(in_file_name, "/") == 0) { - tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID); - return tevent_req_post(req, ev); - } - - if (in_output_buffer_length > 0x10000) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - switch (in_file_info_class) { - case SMB2_FIND_DIRECTORY_INFO: - info_level = SMB_FIND_FILE_DIRECTORY_INFO; - break; - - case SMB2_FIND_FULL_DIRECTORY_INFO: - info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO; - break; - - case SMB2_FIND_BOTH_DIRECTORY_INFO: - info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO; - break; - - case SMB2_FIND_NAME_INFO: - info_level = SMB_FIND_FILE_NAMES_INFO; - break; - - case SMB2_FIND_ID_BOTH_DIRECTORY_INFO: - info_level = SMB_FIND_ID_BOTH_DIRECTORY_INFO; - break; - - case SMB2_FIND_ID_FULL_DIRECTORY_INFO: - info_level = SMB_FIND_ID_FULL_DIRECTORY_INFO; - break; - - default: - tevent_req_nterror(req, NT_STATUS_INVALID_INFO_CLASS); - return tevent_req_post(req, ev); - } - - if (in_flags & SMB2_CONTINUE_FLAG_REOPEN) { - if (fsp->dptr) { - dptr_CloseDir(fsp->dptr); - fsp->dptr = NULL; - } - } - - if (fsp->dptr == NULL) { - bool wcard_has_wild; - - if (!(fsp->access_mask & SEC_DIR_LIST)) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return tevent_req_post(req, ev); - } - - wcard_has_wild = ms_has_wild(in_file_name); - - status = dptr_create(conn, - directory, - false, /* old_handle */ - false, /* expect_close */ - 0, /* spid */ - in_file_name, /* wcard */ - wcard_has_wild, - dirtype, - &fsp->dptr); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - empty_status = NT_STATUS_NO_SUCH_FILE; - } else { - empty_status = STATUS_NO_MORE_FILES; - } - - if (in_flags & SMB2_CONTINUE_FLAG_RESTART) { - dptr_SeekDir(fsp->dptr, 0); - } - - if (in_flags & SMB2_CONTINUE_FLAG_SINGLE) { - max_count = 1; - } else { - max_count = UINT16_MAX; - } - -#define DIR_ENTRY_SAFETY_MARGIN 4096 - - state->out_output_buffer = data_blob_talloc(state, NULL, - in_output_buffer_length + DIR_ENTRY_SAFETY_MARGIN); - if (tevent_req_nomem(state->out_output_buffer.data, req)) { - return tevent_req_post(req, ev); - } - - state->out_output_buffer.length = 0; - pdata = (char *)state->out_output_buffer.data; - base_data = pdata; - end_data = pdata + in_output_buffer_length; - last_entry_off = 0; - off = 0; - num = 0; - - DEBUG(8,("smbd_smb2_find_send: dirpath=<%s> dontdescend=<%s>\n", - directory, lp_dontdescend(SNUM(conn)))); - if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) { - dont_descend = true; - } - - ask_sharemode = lp_parm_bool(SNUM(conn), - "smbd", "search ask sharemode", - true); - - while (true) { - bool ok; - bool got_exact_match = false; - bool out_of_space = false; - int space_remaining = in_output_buffer_length - off; - - ok = smbd_dirptr_lanman2_entry(state, - conn, - fsp->dptr, - smbreq->flags2, - in_file_name, - dirtype, - info_level, - false, /* requires_resume_key */ - dont_descend, - ask_sharemode, - 8, /* align to 8 bytes */ - false, /* no padding */ - &pdata, - base_data, - end_data, - space_remaining, - &out_of_space, - &got_exact_match, - &last_entry_off, - NULL); - - off = PTR_DIFF(pdata, base_data); - - if (!ok) { - if (num > 0) { - SIVAL(state->out_output_buffer.data, last_entry_off, 0); - tevent_req_done(req); - return tevent_req_post(req, ev); - } else if (out_of_space) { - tevent_req_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH); - return tevent_req_post(req, ev); - } else { - tevent_req_nterror(req, empty_status); - return tevent_req_post(req, ev); - } - } - - num++; - state->out_output_buffer.length = off; - - if (num < max_count) { - continue; - } - - SIVAL(state->out_output_buffer.data, last_entry_off, 0); - tevent_req_done(req); - return tevent_req_post(req, ev); - } - - tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); - return tevent_req_post(req, ev); -} - -static NTSTATUS smbd_smb2_find_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out_output_buffer) -{ - NTSTATUS status; - struct smbd_smb2_find_state *state = tevent_req_data(req, - struct smbd_smb2_find_state); - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - *out_output_buffer = state->out_output_buffer; - talloc_steal(mem_ctx, out_output_buffer->data); - - tevent_req_received(req); - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_flush.c b/source3/smbd/smb2_flush.c deleted file mode 100644 index 561e690582..0000000000 --- a/source3/smbd/smb2_flush.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint64_t in_file_id_volatile); -static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req); - -static void smbd_smb2_request_flush_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - size_t expected_body_size = 0x18; - size_t body_size; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - struct tevent_req *subreq; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_file_id_persistent = BVAL(inbody, 0x08); - in_file_id_volatile = BVAL(inbody, 0x10); - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - subreq = smbd_smb2_flush_send(req, - req->sconn->smb2.event_ctx, - req, - in_file_id_volatile); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_flush_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_flush_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - DATA_BLOB outbody; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_flush_recv(subreq); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - outbody = data_blob_talloc(req->out.vector, NULL, 0x10); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x04); /* struct size */ - SSVAL(outbody.data, 0x02, 0); /* reserved */ - - error = smbd_smb2_request_done(req, outbody, NULL); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } -} - -struct smbd_smb2_flush_state { - struct smbd_smb2_request *smb2req; -}; - -static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint64_t in_file_id_volatile) -{ - struct tevent_req *req; - struct smbd_smb2_flush_state *state; - NTSTATUS status; - struct smb_request *smbreq; - files_struct *fsp; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_flush_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - - DEBUG(10,("smbd_smb2_flush: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - - if (IS_IPC(smbreq->conn)) { - tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); - return tevent_req_post(req, ev); - } - - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smbreq->conn != fsp->conn) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smb2req->session->vuid != fsp->vuid) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - if (!CHECK_WRITE(fsp)) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return tevent_req_post(req, ev); - } - - status = sync_file(smbreq->conn, fsp, true); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(5,("smbd_smb2_flush: sync_file for %s returned %s\n", - fsp_str_dbg(fsp), nt_errstr(status))); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - tevent_req_done(req); - return tevent_req_post(req, ev); -} - -static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req) -{ - NTSTATUS status; - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - tevent_req_received(req); - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c deleted file mode 100644 index 3b50ab9cd7..0000000000 --- a/source3/smbd/smb2_getinfo.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint8_t in_info_type, - uint8_t in_file_info_class, - uint32_t in_output_buffer_length, - DATA_BLOB in_input_buffer, - uint32_t in_additional_information, - uint32_t in_flags, - uint64_t in_file_id_volatile); -static NTSTATUS smbd_smb2_getinfo_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out_output_buffer); - -static void smbd_smb2_request_getinfo_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_getinfo(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - size_t expected_body_size = 0x29; - size_t body_size; - uint8_t in_info_type; - uint8_t in_file_info_class; - uint32_t in_output_buffer_length; - uint16_t in_input_buffer_offset; - uint32_t in_input_buffer_length; - DATA_BLOB in_input_buffer; - uint32_t in_additional_information; - uint32_t in_flags; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - struct tevent_req *subreq; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_info_type = CVAL(inbody, 0x02); - in_file_info_class = CVAL(inbody, 0x03); - in_output_buffer_length = IVAL(inbody, 0x04); - in_input_buffer_offset = SVAL(inbody, 0x08); - /* 0x0A 2 bytes reserved */ - in_input_buffer_length = IVAL(inbody, 0x0C); - in_additional_information = IVAL(inbody, 0x10); - in_flags = IVAL(inbody, 0x14); - in_file_id_persistent = BVAL(inbody, 0x18); - in_file_id_volatile = BVAL(inbody, 0x20); - - if (in_input_buffer_offset == 0 && in_input_buffer_length == 0) { - /* This is ok */ - } else if (in_input_buffer_offset != - (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (in_input_buffer_length > req->in.vector[i+2].iov_len) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_input_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base; - in_input_buffer.length = in_input_buffer_length; - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - subreq = smbd_smb2_getinfo_send(req, - req->sconn->smb2.event_ctx, - req, - in_info_type, - in_file_info_class, - in_output_buffer_length, - in_input_buffer, - in_additional_information, - in_flags, - in_file_id_volatile); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_getinfo_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_getinfo_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - int i = req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - DATA_BLOB outdyn; - uint16_t out_output_buffer_offset; - DATA_BLOB out_output_buffer = data_blob_null; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_getinfo_recv(subreq, - req, - &out_output_buffer); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - out_output_buffer_offset = SMB2_HDR_BODY + 0x08; - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - outbody = data_blob_talloc(req->out.vector, NULL, 0x08); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x08 + 1); /* struct size */ - SSVAL(outbody.data, 0x02, - out_output_buffer_offset); /* output buffer offset */ - SIVAL(outbody.data, 0x04, - out_output_buffer.length); /* output buffer length */ - - outdyn = out_output_buffer; - - error = smbd_smb2_request_done(req, outbody, &outdyn); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } -} - -struct smbd_smb2_getinfo_state { - struct smbd_smb2_request *smb2req; - NTSTATUS status; - DATA_BLOB out_output_buffer; -}; - -static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint8_t in_info_type, - uint8_t in_file_info_class, - uint32_t in_output_buffer_length, - DATA_BLOB in_input_buffer, - uint32_t in_additional_information, - uint32_t in_flags, - uint64_t in_file_id_volatile) -{ - struct tevent_req *req; - struct smbd_smb2_getinfo_state *state; - struct smb_request *smbreq; - connection_struct *conn = smb2req->tcon->compat_conn; - files_struct *fsp; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_getinfo_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - state->status = NT_STATUS_INTERNAL_ERROR; - state->out_output_buffer = data_blob_null; - - DEBUG(10,("smbd_smb2_getinfo_send: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (conn != fsp->conn) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smb2req->session->vuid != fsp->vuid) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - if (IS_IPC(conn)) { - tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); - return tevent_req_post(req, ev); - } - - switch (in_info_type) { - case 0x01:/* SMB2_GETINFO_FILE */ - { - uint16_t file_info_level; - char *data = NULL; - unsigned int data_size = 0; - bool delete_pending = false; - struct timespec write_time_ts; - struct file_id fileid; - struct ea_list *ea_list = NULL; - int lock_data_count = 0; - char *lock_data = NULL; - bool ms_dfs_link = false; - NTSTATUS status; - - ZERO_STRUCT(write_time_ts); - - switch (in_file_info_class) { - case 0x0F:/* RAW_FILEINFO_SMB2_ALL_EAS */ - file_info_level = 0xFF00 | in_file_info_class; - break; - - case 0x12:/* RAW_FILEINFO_SMB2_ALL_INFORMATION */ - file_info_level = 0xFF00 | in_file_info_class; - break; - - default: - /* the levels directly map to the passthru levels */ - file_info_level = in_file_info_class + 1000; - break; - } - - if (fsp->fake_file_handle) { - /* - * This is actually for the QUOTA_FAKE_FILE --metze - */ - - /* We know this name is ok, it's already passed the checks. */ - - } else if (fsp && (fsp->is_directory || fsp->fh->fd == -1)) { - /* - * This is actually a QFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ - - if (INFO_LEVEL_IS_UNIX(file_info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, fsp->fsp_name)) { - DEBUG(3,("smbd_smb2_getinfo_send: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", fsp_str_dbg(fsp), - strerror(errno))); - status = map_nt_error_from_unix(errno); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - } else if (SMB_VFS_STAT(conn, fsp->fsp_name)) { - DEBUG(3,("smbd_smb2_getinfo_send: " - "SMB_VFS_STAT of %s failed (%s)\n", - fsp_str_dbg(fsp), - strerror(errno))); - status = map_nt_error_from_unix(errno); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - fileid = vfs_file_id_from_sbuf(conn, - &fsp->fsp_name->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); - } else { - /* - * Original code - this is an open file. - */ - - if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) { - DEBUG(3, ("smbd_smb2_getinfo_send: " - "fstat of fnum %d failed (%s)\n", - fsp->fnum, strerror(errno))); - status = map_nt_error_from_unix(errno); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - fileid = vfs_file_id_from_sbuf(conn, - &fsp->fsp_name->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); - } - - status = smbd_do_qfilepathinfo(conn, state, - file_info_level, - fsp, - fsp->fsp_name, - delete_pending, - write_time_ts, - ms_dfs_link, - ea_list, - lock_data_count, - lock_data, - STR_UNICODE, - in_output_buffer_length, - &data, - &data_size); - if (!NT_STATUS_IS_OK(status)) { - SAFE_FREE(data); - if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { - status = NT_STATUS_INVALID_INFO_CLASS; - } - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - if (data_size > 0) { - state->out_output_buffer = data_blob_talloc(state, - data, - data_size); - SAFE_FREE(data); - if (tevent_req_nomem(state->out_output_buffer.data, req)) { - return tevent_req_post(req, ev); - } - } - SAFE_FREE(data); - break; - } - - case 0x02:/* SMB2_GETINFO_FS */ - { - uint16_t file_info_level; - char *data = NULL; - int data_size = 0; - NTSTATUS status; - - /* the levels directly map to the passthru levels */ - file_info_level = in_file_info_class + 1000; - - status = smbd_do_qfsinfo(conn, state, - file_info_level, - STR_UNICODE, - in_output_buffer_length, - &data, - &data_size); - if (!NT_STATUS_IS_OK(status)) { - SAFE_FREE(data); - if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { - status = NT_STATUS_INVALID_INFO_CLASS; - } - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - if (data_size > 0) { - state->out_output_buffer = data_blob_talloc(state, - data, - data_size); - SAFE_FREE(data); - if (tevent_req_nomem(state->out_output_buffer.data, req)) { - return tevent_req_post(req, ev); - } - } - SAFE_FREE(data); - break; - } - - default: - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - tevent_req_done(req); - return tevent_req_post(req, ev); -} - -static NTSTATUS smbd_smb2_getinfo_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out_output_buffer) -{ - NTSTATUS status; - struct smbd_smb2_getinfo_state *state = tevent_req_data(req, - struct smbd_smb2_getinfo_state); - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - *out_output_buffer = state->out_output_buffer; - talloc_steal(mem_ctx, out_output_buffer->data); - - tevent_req_received(req); - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_glue.c b/source3/smbd/smb2_glue.c deleted file mode 100644 index d5a6217aa3..0000000000 --- a/source3/smbd/smb2_glue.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req) -{ - struct smb_request *smbreq; - const uint8_t *inhdr; - int i = req->current_idx; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - - smbreq = talloc_zero(req, struct smb_request); - if (smbreq == NULL) { - return NULL; - } - - smbreq->vuid = req->session->compat_vuser->vuid; - smbreq->tid = req->tcon->compat_conn->cnum; - smbreq->conn = req->tcon->compat_conn; - smbreq->smbpid = (uint16_t)IVAL(inhdr, SMB2_HDR_PID); - smbreq->flags2 = FLAGS2_UNICODE_STRINGS | - FLAGS2_32_BIT_ERROR_CODES | - FLAGS2_LONG_PATH_COMPONENTS | - FLAGS2_IS_LONG_NAME; - if (IVAL(inhdr, SMB2_HDR_FLAGS) & SMB2_HDR_FLAG_DFS) { - smbreq->flags2 |= FLAGS2_DFS_PATHNAMES; - } - smbreq->chain_fsp = req->compat_chain_fsp; - - return smbreq; -} diff --git a/source3/smbd/smb2_ioctl.c b/source3/smbd/smb2_ioctl.c deleted file mode 100644 index 0041e5f7d0..0000000000 --- a/source3/smbd/smb2_ioctl.c +++ /dev/null @@ -1,461 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint32_t in_ctl_code, - uint64_t in_file_id_volatile, - DATA_BLOB in_input, - uint32_t in_max_output, - uint32_t in_flags); -static NTSTATUS smbd_smb2_ioctl_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out_output); - -static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - size_t expected_body_size = 0x39; - size_t body_size; - uint32_t in_ctl_code; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - uint32_t in_input_offset; - uint32_t in_input_length; - DATA_BLOB in_input_buffer; - uint32_t in_max_output_length; - uint32_t in_flags; - struct tevent_req *subreq; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_ctl_code = IVAL(inbody, 0x04); - in_file_id_persistent = BVAL(inbody, 0x08); - in_file_id_volatile = BVAL(inbody, 0x10); - in_input_offset = IVAL(inbody, 0x18); - in_input_length = IVAL(inbody, 0x1C); - in_max_output_length = IVAL(inbody, 0x2C); - in_flags = IVAL(inbody, 0x30); - - if (in_input_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (in_input_length > req->in.vector[i+2].iov_len) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_input_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base; - in_input_buffer.length = in_input_length; - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent == UINT64_MAX && - in_file_id_volatile == UINT64_MAX) { - /* without a handle */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - subreq = smbd_smb2_ioctl_send(req, - req->sconn->smb2.event_ctx, - req, - in_ctl_code, - in_file_id_volatile, - in_input_buffer, - in_max_output_length, - in_flags); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_ioctl_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - const uint8_t *inbody; - int i = req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - DATA_BLOB outdyn; - uint32_t in_ctl_code; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - uint32_t out_input_offset; - uint32_t out_output_offset; - DATA_BLOB out_output_buffer = data_blob_null; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_ioctl_recv(subreq, req, &out_output_buffer); - TALLOC_FREE(subreq); - if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) { - /* also ok */ - } else if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - out_input_offset = SMB2_HDR_BODY + 0x30; - out_output_offset = SMB2_HDR_BODY + 0x30; - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - in_ctl_code = IVAL(inbody, 0x04); - in_file_id_persistent = BVAL(inbody, 0x08); - in_file_id_volatile = BVAL(inbody, 0x10); - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - outbody = data_blob_talloc(req->out.vector, NULL, 0x30); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x30 + 1); /* struct size */ - SSVAL(outbody.data, 0x02, 0); /* reserved */ - SIVAL(outbody.data, 0x04, - in_ctl_code); /* ctl code */ - SBVAL(outbody.data, 0x08, - in_file_id_persistent); /* file id (persistent) */ - SBVAL(outbody.data, 0x10, - in_file_id_volatile); /* file id (volatile) */ - SIVAL(outbody.data, 0x18, - out_input_offset); /* input offset */ - SIVAL(outbody.data, 0x1C, 0); /* input count */ - SIVAL(outbody.data, 0x20, - out_output_offset); /* output offset */ - SIVAL(outbody.data, 0x24, - out_output_buffer.length); /* output count */ - SIVAL(outbody.data, 0x28, 0); /* flags */ - SIVAL(outbody.data, 0x2C, 0); /* reserved */ - - /* - * Note: Windows Vista and 2008 send back also the - * input from the request. But it was fixed in - * Windows 7. - */ - outdyn = out_output_buffer; - - error = smbd_smb2_request_done_ex(req, status, outbody, &outdyn, - __location__); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } -} - -struct smbd_smb2_ioctl_state { - struct smbd_smb2_request *smb2req; - struct smb_request *smbreq; - files_struct *fsp; - DATA_BLOB in_input; - uint32_t in_max_output; - DATA_BLOB out_output; -}; - -static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq); -static void smbd_smb2_ioctl_pipe_read_done(struct tevent_req *subreq); - -static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint32_t in_ctl_code, - uint64_t in_file_id_volatile, - DATA_BLOB in_input, - uint32_t in_max_output, - uint32_t in_flags) -{ - struct tevent_req *req; - struct smbd_smb2_ioctl_state *state; - struct smb_request *smbreq; - files_struct *fsp = NULL; - struct tevent_req *subreq; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_ioctl_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - state->smbreq = NULL; - state->fsp = NULL; - state->in_input = in_input; - state->in_max_output = in_max_output; - state->out_output = data_blob_null; - - DEBUG(10,("smbd_smb2_ioctl: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - state->smbreq = smbreq; - - if (in_file_id_volatile != UINT64_MAX) { - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smbreq->conn != fsp->conn) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smb2req->session->vuid != fsp->vuid) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - state->fsp = fsp; - } - - switch (in_ctl_code) { - case 0x00060194: /* FSCTL_DFS_GET_REFERRALS */ - { - uint16_t in_max_referral_level; - DATA_BLOB in_file_name_buffer; - char *in_file_name_string; - size_t in_file_name_string_size; - bool ok; - bool overflow = false; - NTSTATUS status; - int dfs_size; - char *dfs_data = NULL; - - if (!IS_IPC(smbreq->conn)) { - tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST); - return tevent_req_post(req, ev); - } - - if (!lp_host_msdfs()) { - tevent_req_nterror(req, NT_STATUS_FS_DRIVER_REQUIRED); - return tevent_req_post(req, ev); - } - - if (in_input.length < (2 + 2)) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - in_max_referral_level = SVAL(in_input.data, 0); - in_file_name_buffer.data = in_input.data + 2; - in_file_name_buffer.length = in_input.length - 2; - - ok = convert_string_talloc(state, CH_UTF16, CH_UNIX, - in_file_name_buffer.data, - in_file_name_buffer.length, - &in_file_name_string, - &in_file_name_string_size, false); - if (!ok) { - tevent_req_nterror(req, NT_STATUS_ILLEGAL_CHARACTER); - return tevent_req_post(req, ev); - } - - dfs_size = setup_dfs_referral(smbreq->conn, - in_file_name_string, - in_max_referral_level, - &dfs_data, &status); - if (dfs_size < 0) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - if (dfs_size > in_max_output) { - /* - * TODO: we need a testsuite for this - */ - overflow = true; - dfs_size = in_max_output; - } - - state->out_output = data_blob_talloc(state, - (uint8_t *)dfs_data, - dfs_size); - SAFE_FREE(dfs_data); - if (dfs_size > 0 && - tevent_req_nomem(state->out_output.data, req)) { - return tevent_req_post(req, ev); - } - - if (overflow) { - tevent_req_nterror(req, STATUS_BUFFER_OVERFLOW); - } else { - tevent_req_done(req); - } - return tevent_req_post(req, ev); - } - case 0x0011C017: /* FSCTL_PIPE_TRANSCEIVE */ - - if (!IS_IPC(smbreq->conn)) { - tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); - return tevent_req_post(req, ev); - } - - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - if (!fsp_is_np(fsp)) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - subreq = np_write_send(state, ev, - fsp->fake_file_handle, - in_input.data, - in_input.length); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, - smbd_smb2_ioctl_pipe_write_done, - req); - return req; - - default: - if (IS_IPC(smbreq->conn)) { - tevent_req_nterror(req, NT_STATUS_FS_DRIVER_REQUIRED); - return tevent_req_post(req, ev); - } - tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST); - return tevent_req_post(req, ev); - } - - tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); - return tevent_req_post(req, ev); -} - -static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct smbd_smb2_ioctl_state *state = tevent_req_data(req, - struct smbd_smb2_ioctl_state); - NTSTATUS status; - ssize_t nwritten = -1; - - status = np_write_recv(subreq, &nwritten); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return; - } - - if (nwritten != state->in_input.length) { - tevent_req_nterror(req, NT_STATUS_PIPE_NOT_AVAILABLE); - return; - } - - state->out_output = data_blob_talloc(state, NULL, state->in_max_output); - if (state->in_max_output > 0 && - tevent_req_nomem(state->out_output.data, req)) { - return; - } - - subreq = np_read_send(state->smbreq->conn, - state->smb2req->sconn->smb2.event_ctx, - state->fsp->fake_file_handle, - state->out_output.data, - state->out_output.length); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, smbd_smb2_ioctl_pipe_read_done, req); -} - -static void smbd_smb2_ioctl_pipe_read_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct smbd_smb2_ioctl_state *state = tevent_req_data(req, - struct smbd_smb2_ioctl_state); - NTSTATUS status; - ssize_t nread; - bool is_data_outstanding; - - status = np_read_recv(subreq, &nread, &is_data_outstanding); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return; - } - - state->out_output.length = nread; - - tevent_req_done(req); -} - -static NTSTATUS smbd_smb2_ioctl_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out_output) -{ - NTSTATUS status; - struct smbd_smb2_ioctl_state *state = tevent_req_data(req, - struct smbd_smb2_ioctl_state); - - if (tevent_req_is_nterror(req, &status)) { - if (!NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) { - tevent_req_received(req); - return status; - } - } - - *out_output = state->out_output; - talloc_steal(mem_ctx, out_output->data); - - tevent_req_received(req); - return status; -} diff --git a/source3/smbd/smb2_keepalive.c b/source3/smbd/smb2_keepalive.c deleted file mode 100644 index 6645a00dad..0000000000 --- a/source3/smbd/smb2_keepalive.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -NTSTATUS smbd_smb2_request_process_keepalive(struct smbd_smb2_request *req) -{ - const uint8_t *inbody; - int i = req->current_idx; - DATA_BLOB outbody; - size_t expected_body_size = 0x04; - size_t body_size; - - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - /* TODO: update some time stamps */ - - outbody = data_blob_talloc(req->out.vector, NULL, 0x04); - if (outbody.data == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - - SSVAL(outbody.data, 0x00, 0x04); /* struct size */ - SSVAL(outbody.data, 0x02, 0); /* reserved */ - - return smbd_smb2_request_done(req, outbody, NULL); -} diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c deleted file mode 100644 index 908e1cf8a4..0000000000 --- a/source3/smbd/smb2_lock.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -struct smbd_smb2_lock_element { - uint64_t offset; - uint64_t length; - uint32_t flags; -}; - -static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint32_t in_smbpid, - uint64_t in_file_id_volatile, - uint16_t in_lock_count, - struct smbd_smb2_lock_element *in_locks); -static NTSTATUS smbd_smb2_lock_recv(struct tevent_req *req); - -static void smbd_smb2_request_lock_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - const int i = req->current_idx; - size_t expected_body_size = 0x30; - size_t body_size; - uint32_t in_smbpid; - uint16_t in_lock_count; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - struct smbd_smb2_lock_element *in_locks; - struct tevent_req *subreq; - const uint8_t *lock_buffer; - uint16_t l; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_smbpid = IVAL(inhdr, SMB2_HDR_PID); - - in_lock_count = CVAL(inbody, 0x02); - /* 0x04 - 4 bytes reserved */ - in_file_id_persistent = BVAL(inbody, 0x08); - in_file_id_volatile = BVAL(inbody, 0x10); - - if (in_lock_count < 1) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (((in_lock_count - 1) * 0x18) > req->in.vector[i+2].iov_len) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - in_locks = talloc_array(req, struct smbd_smb2_lock_element, - in_lock_count); - if (in_locks == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - - l = 0; - lock_buffer = inbody + 0x18; - - in_locks[l].offset = BVAL(lock_buffer, 0x00); - in_locks[l].length = BVAL(lock_buffer, 0x08); - in_locks[l].flags = IVAL(lock_buffer, 0x10); - /* 0x14 - 4 reserved bytes */ - - lock_buffer = (const uint8_t *)req->in.vector[i+2].iov_base; - - for (l=1; l < in_lock_count; l++) { - in_locks[l].offset = BVAL(lock_buffer, 0x00); - in_locks[l].length = BVAL(lock_buffer, 0x08); - in_locks[l].flags = IVAL(lock_buffer, 0x10); - /* 0x14 - 4 reserved bytes */ - - lock_buffer += 0x18; - } - - subreq = smbd_smb2_lock_send(req, - req->sconn->smb2.event_ctx, - req, - in_smbpid, - in_file_id_volatile, - in_lock_count, - in_locks); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_lock_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_lock_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - DATA_BLOB outbody; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_lock_recv(subreq); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - outbody = data_blob_talloc(req->out.vector, NULL, 0x04); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x04); /* struct size */ - SSVAL(outbody.data, 0x02, 0); /* reserved */ - - error = smbd_smb2_request_done(req, outbody, NULL); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } -} - -struct smbd_smb2_lock_state { - struct smbd_smb2_request *smb2req; -}; - -static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint32_t in_smbpid, - uint64_t in_file_id_volatile, - uint16_t in_lock_count, - struct smbd_smb2_lock_element *in_locks) -{ - struct tevent_req *req; - struct smbd_smb2_lock_state *state; - struct smb_request *smbreq; - connection_struct *conn = smb2req->tcon->compat_conn; - files_struct *fsp; - int32_t timeout = -1; - bool isunlock = false; - uint16_t i; - struct smbd_lock_element *locks; - NTSTATUS status; - bool async = false; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_lock_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - - DEBUG(10,("smbd_smb2_lock_send: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (conn != fsp->conn) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smb2req->session->vuid != fsp->vuid) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - locks = talloc_array(state, struct smbd_lock_element, in_lock_count); - if (locks == NULL) { - tevent_req_nterror(req, NT_STATUS_NO_MEMORY); - return tevent_req_post(req, ev); - } - - switch (in_locks[0].flags) { - case SMB2_LOCK_FLAG_SHARED: - case SMB2_LOCK_FLAG_EXCLUSIVE: - if (in_lock_count > 1) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - timeout = -1; - break; - - case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: - case SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: - timeout = 0; - break; - - case SMB2_LOCK_FLAG_UNLOCK: - /* only the first lock gives the UNLOCK bit - see - MS-SMB2 3.3.5.14 */ - isunlock = true; - timeout = 0; - break; - - default: - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - for (i=0; i<in_lock_count; i++) { - uint64_t max_count; - bool invalid = false; - - switch (in_locks[i].flags) { - case SMB2_LOCK_FLAG_SHARED: - case SMB2_LOCK_FLAG_EXCLUSIVE: - if (i > 0) { - tevent_req_nterror(req, - NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - if (isunlock) { - tevent_req_nterror(req, - NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - break; - - case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: - case SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: - if (isunlock) { - tevent_req_nterror(req, - NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - break; - - case SMB2_LOCK_FLAG_UNLOCK: - if (!isunlock) { - tevent_req_nterror(req, - NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - break; - - default: - if (isunlock) { - /* - * is the first element was a UNLOCK - * we need to deferr the error response - * to the backend, because we need to process - * all unlock elements before - */ - invalid = true; - break; - } - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - locks[i].smbpid = in_smbpid; - locks[i].offset = in_locks[i].offset; - locks[i].count = in_locks[i].length; - - if (in_locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE) { - locks[i].brltype = WRITE_LOCK; - } else if (in_locks[i].flags & SMB2_LOCK_FLAG_SHARED) { - locks[i].brltype = READ_LOCK; - } else if (invalid) { - /* - * this is an invalid UNLOCK element - * and the backend needs to test for - * brltype != UNLOCK_LOCK and return - * NT_STATUS_INVALID_PARAMER - */ - locks[i].brltype = READ_LOCK; - } else { - locks[i].brltype = UNLOCK_LOCK; - } - - max_count = UINT64_MAX - locks[i].offset; - if (locks[i].count > max_count) { - tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_RANGE); - return tevent_req_post(req, ev); - } - } - - if (isunlock) { - status = smbd_do_locking(smbreq, fsp, - 0, - timeout, - in_lock_count, - locks, - 0, - NULL, - &async); - } else { - status = smbd_do_locking(smbreq, fsp, - 0, - timeout, - 0, - NULL, - in_lock_count, - locks, - &async); - } - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { - status = NT_STATUS_LOCK_NOT_GRANTED; - } - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - if (async) { - tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); - return tevent_req_post(req, ev); - } - - tevent_req_done(req); - return tevent_req_post(req, ev); -} - -static NTSTATUS smbd_smb2_lock_recv(struct tevent_req *req) -{ - NTSTATUS status; - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - tevent_req_received(req); - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c deleted file mode 100644 index 5b97c65d79..0000000000 --- a/source3/smbd/smb2_negprot.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -/* - * 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; -} - -NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req) -{ - const uint8_t *inbody; - const uint8_t *indyn = NULL; - int i = req->current_idx; - DATA_BLOB outbody; - DATA_BLOB outdyn; - DATA_BLOB negprot_spnego_blob; - uint16_t security_offset; - DATA_BLOB security_buffer; - size_t expected_body_size = 0x24; - size_t body_size; - size_t expected_dyn_size = 0; - size_t c; - uint16_t security_mode; - uint16_t dialect_count; - uint16_t dialect = 0; - uint32_t capabilities; - -/* TODO: drop the connection with INVALI_PARAMETER */ - - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - dialect_count = SVAL(inbody, 0x02); - if (dialect_count == 0) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - expected_dyn_size = dialect_count * 2; - if (req->in.vector[i+2].iov_len < expected_dyn_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - indyn = (const uint8_t *)req->in.vector[i+2].iov_base; - - for (c=0; c < dialect_count; c++) { - dialect = SVAL(indyn, c*2); - if (dialect == SMB2_DIALECT_REVISION_202) { - break; - } - } - - if (dialect != SMB2_DIALECT_REVISION_202) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - set_Protocol(PROTOCOL_SMB2); - - if (get_remote_arch() != RA_SAMBA) { - set_remote_arch(RA_VISTA); - } - - /* negprot_spnego() returns a the server guid in the first 16 bytes */ - negprot_spnego_blob = negprot_spnego(); - if (negprot_spnego_blob.data == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - talloc_steal(req, negprot_spnego_blob.data); - - if (negprot_spnego_blob.length < 16) { - return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR); - } - - security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; - if (lp_server_signing() == Required) { - security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED; - } - - capabilities = 0; - if (lp_host_msdfs()) { - capabilities |= SMB2_CAP_DFS; - } - - security_offset = SMB2_HDR_BODY + 0x40; - -#if 1 - /* Try SPNEGO auth... */ - security_buffer = data_blob_const(negprot_spnego_blob.data + 16, - negprot_spnego_blob.length - 16); -#else - /* for now we want raw NTLMSSP */ - security_buffer = data_blob_const(NULL, 0); -#endif - - outbody = data_blob_talloc(req->out.vector, NULL, 0x40); - if (outbody.data == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - - SSVAL(outbody.data, 0x00, 0x40 + 1); /* struct size */ - SSVAL(outbody.data, 0x02, - security_mode); /* security mode */ - SSVAL(outbody.data, 0x04, dialect); /* dialect revision */ - SSVAL(outbody.data, 0x06, 0); /* reserved */ - memcpy(outbody.data + 0x08, - negprot_spnego_blob.data, 16); /* server guid */ - SIVAL(outbody.data, 0x18, - capabilities); /* capabilities */ - SIVAL(outbody.data, 0x1C, 0x00010000); /* max transact size */ - SIVAL(outbody.data, 0x20, 0x00010000); /* max read size */ - SIVAL(outbody.data, 0x24, 0x00010000); /* max write size */ - SBVAL(outbody.data, 0x28, 0); /* system time */ - SBVAL(outbody.data, 0x30, 0); /* server start time */ - SSVAL(outbody.data, 0x38, - security_offset); /* security buffer offset */ - SSVAL(outbody.data, 0x3A, - security_buffer.length); /* security buffer length */ - SIVAL(outbody.data, 0x3C, 0); /* reserved */ - - outdyn = security_buffer; - - return smbd_smb2_request_done(req, outbody, &outdyn); -} diff --git a/source3/smbd/smb2_notify.c b/source3/smbd/smb2_notify.c deleted file mode 100644 index fb465abff9..0000000000 --- a/source3/smbd/smb2_notify.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static struct tevent_req *smbd_smb2_notify_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint16_t in_flags, - uint32_t in_output_buffer_length, - uint64_t in_file_id_volatile, - uint64_t in_completion_filter); -static NTSTATUS smbd_smb2_notify_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out_output_buffer); - -static void smbd_smb2_request_notify_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_notify(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - size_t expected_body_size = 0x20; - size_t body_size; - uint16_t in_flags; - uint32_t in_output_buffer_length; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - uint64_t in_completion_filter; - struct tevent_req *subreq; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_flags = SVAL(inbody, 0x02); - in_output_buffer_length = IVAL(inbody, 0x04); - in_file_id_persistent = BVAL(inbody, 0x08); - in_file_id_volatile = BVAL(inbody, 0x10); - in_completion_filter = IVAL(inbody, 0x18); - - /* - * 0x00010000 is what Windows 7 uses, - * Windows 2008 uses 0x00080000 - */ - if (in_output_buffer_length > 0x00010000) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - subreq = smbd_smb2_notify_send(req, - req->sconn->smb2.event_ctx, - req, - in_flags, - in_output_buffer_length, - in_file_id_volatile, - in_completion_filter); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_notify_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_notify_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - int i = req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - DATA_BLOB outdyn; - uint16_t out_output_buffer_offset; - DATA_BLOB out_output_buffer = data_blob_null; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_notify_recv(subreq, - req, - &out_output_buffer); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - out_output_buffer_offset = SMB2_HDR_BODY + 0x08; - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - outbody = data_blob_talloc(req->out.vector, NULL, 0x08); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x08 + 1); /* struct size */ - SSVAL(outbody.data, 0x02, - out_output_buffer_offset); /* output buffer offset */ - SIVAL(outbody.data, 0x04, - out_output_buffer.length); /* output buffer length */ - - outdyn = out_output_buffer; - - error = smbd_smb2_request_done(req, outbody, &outdyn); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } -} - -struct smbd_smb2_notify_state { - struct smbd_smb2_request *smb2req; - struct smb_request *smbreq; - struct tevent_immediate *im; - NTSTATUS status; - DATA_BLOB out_output_buffer; -}; - -static void smbd_smb2_notify_reply(struct smb_request *smbreq, - NTSTATUS error_code, - uint8_t *buf, size_t len); -static void smbd_smb2_notify_reply_trigger(struct tevent_context *ctx, - struct tevent_immediate *im, - void *private_data); -static bool smbd_smb2_notify_cancel(struct tevent_req *req); - -static struct tevent_req *smbd_smb2_notify_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint16_t in_flags, - uint32_t in_output_buffer_length, - uint64_t in_file_id_volatile, - uint64_t in_completion_filter) -{ - struct tevent_req *req; - struct smbd_smb2_notify_state *state; - struct smb_request *smbreq; - connection_struct *conn = smb2req->tcon->compat_conn; - files_struct *fsp; - bool recursive = (in_flags & 0x0001) ? true : false; - NTSTATUS status; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_notify_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - state->status = NT_STATUS_INTERNAL_ERROR; - state->out_output_buffer = data_blob_null; - state->im = NULL; - - DEBUG(10,("smbd_smb2_notify_send: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - - state->smbreq = smbreq; - smbreq->async_priv = (void *)req; - - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (conn != fsp->conn) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smb2req->session->vuid != fsp->vuid) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - { - char *filter_string; - - filter_string = notify_filter_string(NULL, in_completion_filter); - if (tevent_req_nomem(filter_string, req)) { - return tevent_req_post(req, ev); - } - - DEBUG(3,("smbd_smb2_notify_send: notify change " - "called on %s, filter = %s, recursive = %d\n", - fsp_str_dbg(fsp), filter_string, recursive)); - - TALLOC_FREE(filter_string); - } - - if ((!fsp->is_directory) || (conn != fsp->conn)) { - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - if (fsp->notify == NULL) { - - status = change_notify_create(fsp, - in_completion_filter, - recursive); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("change_notify_create returned %s\n", - nt_errstr(status))); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - } - - if (fsp->notify->num_changes != 0) { - - /* - * We've got changes pending, respond immediately - */ - - /* - * TODO: write a torture test to check the filtering behaviour - * here. - */ - - change_notify_reply(fsp->conn, smbreq, - NT_STATUS_OK, - in_output_buffer_length, - fsp->notify, - smbd_smb2_notify_reply); - - /* - * change_notify_reply() above has independently - * called tevent_req_done(). - */ - return tevent_req_post(req, ev); - } - - state->im = tevent_create_immediate(state); - if (tevent_req_nomem(state->im, req)) { - return tevent_req_post(req, ev); - } - - /* - * No changes pending, queue the request - */ - - status = change_notify_add_request(smbreq, - in_output_buffer_length, - in_completion_filter, - recursive, fsp, - smbd_smb2_notify_reply); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - /* allow this request to be canceled */ - tevent_req_set_cancel_fn(req, smbd_smb2_notify_cancel); - - return req; -} - -static void smbd_smb2_notify_reply(struct smb_request *smbreq, - NTSTATUS error_code, - uint8_t *buf, size_t len) -{ - struct tevent_req *req = talloc_get_type_abort(smbreq->async_priv, - struct tevent_req); - struct smbd_smb2_notify_state *state = tevent_req_data(req, - struct smbd_smb2_notify_state); - - state->status = error_code; - if (!NT_STATUS_IS_OK(error_code)) { - /* nothing */ - } else if (len == 0) { - state->status = STATUS_NOTIFY_ENUM_DIR; - } else { - state->out_output_buffer = data_blob_talloc(state, buf, len); - if (state->out_output_buffer.data == NULL) { - state->status = NT_STATUS_NO_MEMORY; - } - } - - if (state->im == NULL) { - smbd_smb2_notify_reply_trigger(NULL, NULL, req); - return; - } - - /* - * if this is called async, we need to go via an immediate event - * because the caller replies on the smb_request (a child of req - * being arround after calling this function - */ - tevent_schedule_immediate(state->im, - state->smb2req->sconn->smb2.event_ctx, - smbd_smb2_notify_reply_trigger, - req); -} - -static void smbd_smb2_notify_reply_trigger(struct tevent_context *ctx, - struct tevent_immediate *im, - void *private_data) -{ - struct tevent_req *req = talloc_get_type_abort(private_data, - struct tevent_req); - struct smbd_smb2_notify_state *state = tevent_req_data(req, - struct smbd_smb2_notify_state); - - if (!NT_STATUS_IS_OK(state->status)) { - tevent_req_nterror(req, state->status); - return; - } - - tevent_req_done(req); -} - -static bool smbd_smb2_notify_cancel(struct tevent_req *req) -{ - struct smbd_smb2_notify_state *state = tevent_req_data(req, - struct smbd_smb2_notify_state); - - smbd_notify_cancel_by_smbreq(state->smb2req->sconn, - state->smbreq); - - return true; -} - -static NTSTATUS smbd_smb2_notify_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out_output_buffer) -{ - NTSTATUS status; - struct smbd_smb2_notify_state *state = tevent_req_data(req, - struct smbd_smb2_notify_state); - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - *out_output_buffer = state->out_output_buffer; - talloc_steal(mem_ctx, out_output_buffer->data); - - tevent_req_received(req); - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c deleted file mode 100644 index 3f316e0b71..0000000000 --- a/source3/smbd/smb2_read.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint32_t in_smbpid, - uint64_t in_file_id_volatile, - uint32_t in_length, - uint64_t in_offset, - uint32_t in_minimum, - uint32_t in_remaining); -static NTSTATUS smbd_smb2_read_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out_data, - uint32_t *out_remaining); - -static void smbd_smb2_request_read_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - size_t expected_body_size = 0x31; - size_t body_size; - uint32_t in_smbpid; - uint32_t in_length; - uint64_t in_offset; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - uint32_t in_minimum_count; - uint32_t in_remaining_bytes; - struct tevent_req *subreq; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_smbpid = IVAL(inhdr, SMB2_HDR_PID); - - in_length = IVAL(inbody, 0x04); - in_offset = BVAL(inbody, 0x08); - in_file_id_persistent = BVAL(inbody, 0x10); - in_file_id_volatile = BVAL(inbody, 0x18); - in_minimum_count = IVAL(inbody, 0x20); - in_remaining_bytes = IVAL(inbody, 0x28); - - /* check the max read size */ - if (in_length > 0x00010000) { - DEBUG(0,("here:%s: 0x%08X: 0x%08X\n", - __location__, in_length, 0x00010000)); - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - subreq = smbd_smb2_read_send(req, - req->sconn->smb2.event_ctx, - req, - in_smbpid, - in_file_id_volatile, - in_length, - in_offset, - in_minimum_count, - in_remaining_bytes); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_read_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - int i = req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - DATA_BLOB outdyn; - uint8_t out_data_offset; - DATA_BLOB out_data_buffer = data_blob_null; - uint32_t out_data_remaining = 0; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_read_recv(subreq, - req, - &out_data_buffer, - &out_data_remaining); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - out_data_offset = SMB2_HDR_BODY + 0x10; - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - outbody = data_blob_talloc(req->out.vector, NULL, 0x10); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x10 + 1); /* struct size */ - SCVAL(outbody.data, 0x02, - out_data_offset); /* data offset */ - SCVAL(outbody.data, 0x03, 0); /* reserved */ - SIVAL(outbody.data, 0x04, - out_data_buffer.length); /* data length */ - SIVAL(outbody.data, 0x08, - out_data_remaining); /* data remaining */ - SIVAL(outbody.data, 0x0C, 0); /* reserved */ - - outdyn = out_data_buffer; - - error = smbd_smb2_request_done(req, outbody, &outdyn); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } -} - -struct smbd_smb2_read_state { - struct smbd_smb2_request *smb2req; - DATA_BLOB out_data; - uint32_t out_remaining; -}; - -static void smbd_smb2_read_pipe_done(struct tevent_req *subreq); - -static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint32_t in_smbpid, - uint64_t in_file_id_volatile, - uint32_t in_length, - uint64_t in_offset, - uint32_t in_minimum, - uint32_t in_remaining) -{ - struct tevent_req *req; - struct smbd_smb2_read_state *state; - struct smb_request *smbreq; - connection_struct *conn = smb2req->tcon->compat_conn; - files_struct *fsp; - ssize_t nread = -1; - struct lock_struct lock; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_read_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - state->out_data = data_blob_null; - state->out_remaining = 0; - - DEBUG(10,("smbd_smb2_read: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (conn != fsp->conn) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smb2req->session->vuid != fsp->vuid) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - state->out_data = data_blob_talloc(state, NULL, in_length); - if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) { - return tevent_req_post(req, ev); - } - - if (IS_IPC(smbreq->conn)) { - struct tevent_req *subreq; - - if (!fsp_is_np(fsp)) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - subreq = np_read_send(state, smbd_event_context(), - fsp->fake_file_handle, - state->out_data.data, - state->out_data.length); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, - smbd_smb2_read_pipe_done, - req); - return req; - } - - if (!CHECK_READ(fsp, smbreq)) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return tevent_req_post(req, ev); - } - - init_strict_lock_struct(fsp, - in_smbpid, - in_offset, - in_length, - READ_LOCK, - &lock); - - if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); - return tevent_req_post(req, ev); - } - - nread = read_file(fsp, - (char *)state->out_data.data, - in_offset, - in_length); - - SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); - - if (nread < 0) { - DEBUG(5,("smbd_smb2_read: read_file[%s] nread[%lld]\n", - fsp_str_dbg(fsp), (long long)nread)); - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return tevent_req_post(req, ev); - } - if (nread == 0 && in_length != 0) { - DEBUG(5,("smbd_smb2_read: read_file[%s] end of file\n", - fsp_str_dbg(fsp))); - tevent_req_nterror(req, NT_STATUS_END_OF_FILE); - return tevent_req_post(req, ev); - } - - state->out_data.length = nread; - state->out_remaining = 0; - tevent_req_done(req); - return tevent_req_post(req, ev); -} - -static void smbd_smb2_read_pipe_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct smbd_smb2_read_state *state = tevent_req_data(req, - struct smbd_smb2_read_state); - NTSTATUS status; - ssize_t nread = -1; - bool is_data_outstanding; - - status = np_read_recv(subreq, &nread, &is_data_outstanding); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return; - } - - if (nread == 0 && state->out_data.length != 0) { - tevent_req_nterror(req, NT_STATUS_END_OF_FILE); - return; - } - - state->out_data.length = nread; - state->out_remaining = 0; - - tevent_req_done(req); -} - -static NTSTATUS smbd_smb2_read_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - DATA_BLOB *out_data, - uint32_t *out_remaining) -{ - NTSTATUS status; - struct smbd_smb2_read_state *state = tevent_req_data(req, - struct smbd_smb2_read_state); - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - *out_data = state->out_data; - talloc_steal(mem_ctx, out_data->data); - *out_remaining = state->out_remaining; - - tevent_req_received(req); - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c deleted file mode 100644 index 9e5be404ef..0000000000 --- a/source3/smbd/smb2_server.c +++ /dev/null @@ -1,1586 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" -#include "../lib/tsocket/tsocket.h" - -bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size) -{ - if (size < (4 + SMB2_HDR_BODY)) { - return false; - } - - if (IVAL(inbuf, 4) != SMB2_MAGIC) { - return false; - } - - return true; -} - -static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn) -{ - NTSTATUS status; - int ret; - - TALLOC_FREE(sconn->smb1.fde); - - sconn->smb2.event_ctx = smbd_event_context(); - - sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue"); - if (sconn->smb2.recv_queue == NULL) { - return NT_STATUS_NO_MEMORY; - } - - sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue"); - if (sconn->smb2.send_queue == NULL) { - return NT_STATUS_NO_MEMORY; - } - - sconn->smb2.sessions.idtree = idr_init(sconn); - if (sconn->smb2.sessions.idtree == NULL) { - return NT_STATUS_NO_MEMORY; - } - sconn->smb2.sessions.limit = 0x0000FFFE; - sconn->smb2.sessions.list = NULL; - - ret = tstream_bsd_existing_socket(sconn, smbd_server_fd(), - &sconn->smb2.stream); - if (ret == -1) { - status = map_nt_error_from_unix(errno); - return status; - } - - /* Ensure child is set to non-blocking mode */ - set_blocking(smbd_server_fd(),false); - return NT_STATUS_OK; -} - -#define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16)) -#define _smb2_setlen(_buf,len) do { \ - uint8_t *buf = (uint8_t *)_buf; \ - buf[0] = 0; \ - buf[1] = ((len)&0xFF0000)>>16; \ - buf[2] = ((len)&0xFF00)>>8; \ - buf[3] = (len)&0xFF; \ -} while (0) - -static void smb2_setup_nbt_length(struct iovec *vector, int count) -{ - size_t len = 0; - int i; - - for (i=1; i < count; i++) { - len += vector[i].iov_len; - } - - _smb2_setlen(vector[0].iov_base, len); -} - -static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request **req) -{ - if (*req) { - (*req)->parent = NULL; - (*req)->mem_pool = NULL; - } - - return 0; -} - -static int smbd_smb2_request_destructor(struct smbd_smb2_request *req) -{ - if (req->out.vector) { - DLIST_REMOVE(req->sconn->smb2.requests, req); - } - - if (req->parent) { - *req->parent = NULL; - talloc_free(req->mem_pool); - } - - return 0; -} - -static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx) -{ - TALLOC_CTX *mem_pool; - struct smbd_smb2_request **parent; - struct smbd_smb2_request *req; - - mem_pool = talloc_pool(mem_ctx, 8192); - if (mem_pool == NULL) { - return NULL; - } - - parent = talloc(mem_pool, struct smbd_smb2_request *); - if (parent == NULL) { - talloc_free(mem_pool); - return NULL; - } - - req = talloc_zero(parent, struct smbd_smb2_request); - if (req == NULL) { - talloc_free(mem_pool); - return NULL; - } - *parent = req; - req->mem_pool = mem_pool; - req->parent = parent; - - talloc_set_destructor(parent, smbd_smb2_request_parent_destructor); - talloc_set_destructor(req, smbd_smb2_request_destructor); - - return req; -} - -static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn, - const uint8_t *inbuf, size_t size, - struct smbd_smb2_request **_req) -{ - struct smbd_smb2_request *req; - uint32_t protocol_version; - const uint8_t *inhdr = NULL; - off_t ofs = 0; - uint16_t cmd; - uint32_t next_command_ofs; - - if (size < (4 + SMB2_HDR_BODY + 2)) { - DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size)); - return NT_STATUS_INVALID_PARAMETER; - } - - inhdr = inbuf + 4; - - protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID); - if (protocol_version != SMB2_MAGIC) { - DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n", - protocol_version)); - return NT_STATUS_INVALID_PARAMETER; - } - - cmd = SVAL(inhdr, SMB2_HDR_OPCODE); - if (cmd != SMB2_OP_NEGPROT) { - DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n", - cmd)); - return NT_STATUS_INVALID_PARAMETER; - } - - next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND); - if (next_command_ofs != 0) { - DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n", - next_command_ofs)); - return NT_STATUS_INVALID_PARAMETER; - } - - req = smbd_smb2_request_allocate(sconn); - if (req == NULL) { - return NT_STATUS_NO_MEMORY; - } - req->sconn = sconn; - - talloc_steal(req, inbuf); - - req->in.vector = talloc_array(req, struct iovec, 4); - if (req->in.vector == NULL) { - TALLOC_FREE(req); - return NT_STATUS_NO_MEMORY; - } - req->in.vector_count = 4; - - memcpy(req->in.nbt_hdr, inbuf, 4); - - ofs = 0; - req->in.vector[0].iov_base = (void *)req->in.nbt_hdr; - req->in.vector[0].iov_len = 4; - ofs += req->in.vector[0].iov_len; - - req->in.vector[1].iov_base = (void *)(inbuf + ofs); - req->in.vector[1].iov_len = SMB2_HDR_BODY; - ofs += req->in.vector[1].iov_len; - - req->in.vector[2].iov_base = (void *)(inbuf + ofs); - req->in.vector[2].iov_len = SVAL(inbuf, ofs) & 0xFFFE; - ofs += req->in.vector[2].iov_len; - - if (ofs > size) { - return NT_STATUS_INVALID_PARAMETER; - } - - req->in.vector[3].iov_base = (void *)(inbuf + ofs); - req->in.vector[3].iov_len = size - ofs; - ofs += req->in.vector[3].iov_len; - - req->current_idx = 1; - - *_req = req; - return NT_STATUS_OK; -} - -static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req) -{ - int count; - int idx; - bool compound_related = false; - - count = req->in.vector_count; - - if (count < 4) { - /* It's not a SMB2 request */ - return NT_STATUS_INVALID_PARAMETER; - } - - for (idx=1; idx < count; idx += 3) { - const uint8_t *inhdr = NULL; - uint32_t flags; - - if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (req->in.vector[idx+1].iov_len < 2) { - return NT_STATUS_INVALID_PARAMETER; - } - - inhdr = (const uint8_t *)req->in.vector[idx].iov_base; - - /* setup the SMB2 header */ - if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) { - return NT_STATUS_INVALID_PARAMETER; - } - - flags = IVAL(inhdr, SMB2_HDR_FLAGS); - if (idx == 1) { - /* - * the 1st request should never have the - * SMB2_HDR_FLAG_CHAINED flag set - */ - if (flags & SMB2_HDR_FLAG_CHAINED) { - req->next_status = NT_STATUS_INVALID_PARAMETER; - return NT_STATUS_OK; - } - } else if (idx == 4) { - /* - * the 2nd request triggers related vs. unrelated - * compounded requests - */ - if (flags & SMB2_HDR_FLAG_CHAINED) { - compound_related = true; - } - } else if (idx > 4) { -#if 0 - /* - * It seems the this tests are wrong - * see the SMB2-COMPOUND test - */ - - /* - * all other requests should match the 2nd one - */ - if (flags & SMB2_HDR_FLAG_CHAINED) { - if (!compound_related) { - req->next_status = - NT_STATUS_INVALID_PARAMETER; - return NT_STATUS_OK; - } - } else { - if (compound_related) { - req->next_status = - NT_STATUS_INVALID_PARAMETER; - return NT_STATUS_OK; - } - } -#endif - } - } - - return NT_STATUS_OK; -} - -static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req) -{ - struct iovec *vector; - int count; - int idx; - - count = req->in.vector_count; - vector = talloc_array(req, struct iovec, count); - if (vector == NULL) { - return NT_STATUS_NO_MEMORY; - } - - vector[0].iov_base = req->out.nbt_hdr; - vector[0].iov_len = 4; - SIVAL(req->out.nbt_hdr, 0, 0); - - for (idx=1; idx < count; idx += 3) { - const uint8_t *inhdr = NULL; - uint32_t in_flags; - uint8_t *outhdr = NULL; - uint8_t *outbody = NULL; - uint32_t next_command_ofs = 0; - struct iovec *current = &vector[idx]; - - if ((idx + 3) < count) { - /* we have a next command */ - next_command_ofs = SMB2_HDR_BODY + 8; - } - - inhdr = (const uint8_t *)req->in.vector[idx].iov_base; - in_flags = IVAL(inhdr, SMB2_HDR_FLAGS); - - outhdr = talloc_array(vector, uint8_t, - SMB2_HDR_BODY + 8); - if (outhdr == NULL) { - return NT_STATUS_NO_MEMORY; - } - - outbody = outhdr + SMB2_HDR_BODY; - - current[0].iov_base = (void *)outhdr; - current[0].iov_len = SMB2_HDR_BODY; - - current[1].iov_base = (void *)outbody; - current[1].iov_len = 8; - - current[2].iov_base = NULL; - current[2].iov_len = 0; - - /* setup the SMB2 header */ - SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC); - SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); - SSVAL(outhdr, SMB2_HDR_EPOCH, 0); - SIVAL(outhdr, SMB2_HDR_STATUS, - NT_STATUS_V(NT_STATUS_INTERNAL_ERROR)); - SSVAL(outhdr, SMB2_HDR_OPCODE, - SVAL(inhdr, SMB2_HDR_OPCODE)); - /* Make up a number for now... JRA. FIXME ! FIXME !*/ - SSVAL(outhdr, SMB2_HDR_CREDIT, 20); - SIVAL(outhdr, SMB2_HDR_FLAGS, - IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT); - SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs); - SBVAL(outhdr, SMB2_HDR_MESSAGE_ID, - BVAL(inhdr, SMB2_HDR_MESSAGE_ID)); - SIVAL(outhdr, SMB2_HDR_PID, - IVAL(inhdr, SMB2_HDR_PID)); - SIVAL(outhdr, SMB2_HDR_TID, - IVAL(inhdr, SMB2_HDR_TID)); - SBVAL(outhdr, SMB2_HDR_SESSION_ID, - BVAL(inhdr, SMB2_HDR_SESSION_ID)); - memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16); - - /* setup error body header */ - SSVAL(outbody, 0x00, 0x08 + 1); - SSVAL(outbody, 0x02, 0); - SIVAL(outbody, 0x04, 0); - } - - req->out.vector = vector; - req->out.vector_count = count; - - /* setup the length of the NBT packet */ - smb2_setup_nbt_length(req->out.vector, req->out.vector_count); - - DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *); - - return NT_STATUS_OK; -} - -void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn, - const char *reason, - const char *location) -{ - DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n", - reason, location)); - exit_server_cleanly(reason); -} - -struct smbd_smb2_request_pending_state { - struct smbd_server_connection *sconn; - uint8_t buf[4 + SMB2_HDR_BODY + 0x08]; - struct iovec vector; -}; - -static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq); - -NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req, - struct tevent_req *subreq) -{ - struct smbd_smb2_request_pending_state *state; - uint8_t *outhdr; - int i = req->current_idx; - uint32_t flags; - uint64_t message_id; - uint64_t async_id; - uint8_t *hdr; - uint8_t *body; - - if (!tevent_req_is_in_progress(subreq)) { - return NT_STATUS_OK; - } - - req->subreq = subreq; - subreq = NULL; - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - flags = IVAL(outhdr, SMB2_HDR_FLAGS); - message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID); - - async_id = message_id; /* keep it simple for now... */ - SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC); - SBVAL(outhdr, SMB2_HDR_PID, async_id); - - /* TODO: add a paramter to delay this */ - state = talloc(req->sconn, struct smbd_smb2_request_pending_state); - if (state == NULL) { - return NT_STATUS_NO_MEMORY; - } - state->sconn = req->sconn; - - state->vector.iov_base = (void *)state->buf; - state->vector.iov_len = sizeof(state->buf); - - _smb2_setlen(state->buf, sizeof(state->buf) - 4); - hdr = state->buf + 4; - body = hdr + SMB2_HDR_BODY; - - SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC); - SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); - SSVAL(hdr, SMB2_HDR_EPOCH, 0); - SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING)); - SSVAL(hdr, SMB2_HDR_OPCODE, - SVAL(outhdr, SMB2_HDR_OPCODE)); - SSVAL(hdr, SMB2_HDR_CREDIT, 1); - SIVAL(hdr, SMB2_HDR_FLAGS, - IVAL(outhdr, SMB2_HDR_FLAGS)); - SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0); - SBVAL(hdr, SMB2_HDR_MESSAGE_ID, - BVAL(outhdr, SMB2_HDR_MESSAGE_ID)); - SBVAL(hdr, SMB2_HDR_PID, - BVAL(outhdr, SMB2_HDR_PID)); - SBVAL(hdr, SMB2_HDR_SESSION_ID, - BVAL(outhdr, SMB2_HDR_SESSION_ID)); - memset(hdr+SMB2_HDR_SIGNATURE, 0, 16); - - SSVAL(body, 0x00, 0x08 + 1); - - SCVAL(body, 0x02, 0); - SCVAL(body, 0x03, 0); - SIVAL(body, 0x04, 0); - - subreq = tstream_writev_queue_send(state, - req->sconn->smb2.event_ctx, - req->sconn->smb2.stream, - req->sconn->smb2.send_queue, - &state->vector, 1); - if (subreq == NULL) { - return NT_STATUS_NO_MEMORY; - } - tevent_req_set_callback(subreq, - smbd_smb2_request_pending_writev_done, - state); - - return NT_STATUS_OK; -} - -static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request_pending_state *state = - tevent_req_callback_data(subreq, - struct smbd_smb2_request_pending_state); - struct smbd_server_connection *sconn = state->sconn; - int ret; - int sys_errno; - - ret = tstream_writev_queue_recv(subreq, &sys_errno); - TALLOC_FREE(subreq); - if (ret == -1) { - NTSTATUS status = map_nt_error_from_unix(sys_errno); - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } - - TALLOC_FREE(state); -} - -static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req) -{ - struct smbd_server_connection *sconn = req->sconn; - struct smbd_smb2_request *cur; - const uint8_t *inhdr; - int i = req->current_idx; - uint32_t flags; - uint64_t search_message_id; - uint64_t search_async_id; - - inhdr = (const uint8_t *)req->in.vector[i].iov_base; - - flags = IVAL(inhdr, SMB2_HDR_FLAGS); - search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID); - search_async_id = BVAL(inhdr, SMB2_HDR_PID); - - /* - * we don't need the request anymore - * cancel requests never have a response - */ - TALLOC_FREE(req); - - for (cur = sconn->smb2.requests; cur; cur = cur->next) { - const uint8_t *outhdr; - uint64_t message_id; - uint64_t async_id; - - i = cur->current_idx; - - outhdr = (const uint8_t *)cur->out.vector[i].iov_base; - - message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID); - async_id = BVAL(outhdr, SMB2_HDR_PID); - - if (flags & SMB2_HDR_FLAG_ASYNC) { - if (search_async_id == async_id) { - break; - } - } else { - if (search_message_id == message_id) { - break; - } - } - } - - if (cur && cur->subreq) { - tevent_req_cancel(cur->subreq); - } - - return NT_STATUS_OK; -} - -static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - int i = req->current_idx; - uint16_t opcode; - uint32_t flags; - NTSTATUS status; - NTSTATUS session_status; - uint32_t allowed_flags; - - inhdr = (const uint8_t *)req->in.vector[i].iov_base; - - /* TODO: verify more things */ - - flags = IVAL(inhdr, SMB2_HDR_FLAGS); - opcode = IVAL(inhdr, SMB2_HDR_OPCODE); - DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode)); - - allowed_flags = SMB2_HDR_FLAG_CHAINED | - SMB2_HDR_FLAG_SIGNED | - SMB2_HDR_FLAG_DFS; - if (opcode == SMB2_OP_CANCEL) { - allowed_flags |= SMB2_HDR_FLAG_ASYNC; - } - if ((flags & ~allowed_flags) != 0) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - session_status = smbd_smb2_request_check_session(req); - - req->do_signing = false; - if (flags & SMB2_HDR_FLAG_SIGNED) { - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - - req->do_signing = true; - status = smb2_signing_check_pdu(req->session->session_key, - &req->in.vector[i], 3); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - } else if (req->session && req->session->do_signing) { - return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED); - } - - if (flags & SMB2_HDR_FLAG_CHAINED) { - /* - * This check is mostly for giving the correct error code - * for compounded requests. - * - * TODO: we may need to move this after the session - * and tcon checks. - */ - if (!NT_STATUS_IS_OK(req->next_status)) { - return smbd_smb2_request_error(req, req->next_status); - } - } else { - req->compat_chain_fsp = NULL; - } - - switch (opcode) { - case SMB2_OP_NEGPROT: - return smbd_smb2_request_process_negprot(req); - - case SMB2_OP_SESSSETUP: - return smbd_smb2_request_process_sesssetup(req); - - case SMB2_OP_LOGOFF: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - return smbd_smb2_request_process_logoff(req); - - case SMB2_OP_TCON: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_session(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_tcon(req); - - case SMB2_OP_TDIS: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_tdis(req); - - case SMB2_OP_CREATE: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_create(req); - - case SMB2_OP_CLOSE: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_close(req); - - case SMB2_OP_FLUSH: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_flush(req); - - case SMB2_OP_READ: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_read(req); - - case SMB2_OP_WRITE: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_write(req); - - case SMB2_OP_LOCK: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_lock(req); - - case SMB2_OP_IOCTL: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_ioctl(req); - - case SMB2_OP_CANCEL: - return smbd_smb2_request_process_cancel(req); - - case SMB2_OP_KEEPALIVE: - return smbd_smb2_request_process_keepalive(req); - - case SMB2_OP_FIND: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_find(req); - - case SMB2_OP_NOTIFY: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_notify(req); - - case SMB2_OP_GETINFO: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_getinfo(req); - - case SMB2_OP_SETINFO: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_setinfo(req); - - case SMB2_OP_BREAK: - if (!NT_STATUS_IS_OK(session_status)) { - return smbd_smb2_request_error(req, session_status); - } - status = smbd_smb2_request_check_tcon(req); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - return smbd_smb2_request_process_break(req); - } - - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); -} - -static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq); -static void smbd_smb2_request_writev_done(struct tevent_req *subreq); - -static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) -{ - struct tevent_req *subreq; - - req->subreq = NULL; - - smb2_setup_nbt_length(req->out.vector, req->out.vector_count); - - if (req->do_signing) { - int i = req->current_idx; - NTSTATUS status; - status = smb2_signing_sign_pdu(req->session->session_key, - &req->out.vector[i], 3); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - } - - req->current_idx += 3; - - if (req->current_idx < req->out.vector_count) { - struct timeval zero = timeval_zero(); - subreq = tevent_wakeup_send(req, - req->sconn->smb2.event_ctx, - zero); - if (subreq == NULL) { - return NT_STATUS_NO_MEMORY; - } - tevent_req_set_callback(subreq, - smbd_smb2_request_dispatch_compound, - req); - - return NT_STATUS_OK; - } - - subreq = tstream_writev_queue_send(req, - req->sconn->smb2.event_ctx, - req->sconn->smb2.stream, - req->sconn->smb2.send_queue, - req->out.vector, - req->out.vector_count); - if (subreq == NULL) { - return NT_STATUS_NO_MEMORY; - } - tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req); - - return NT_STATUS_OK; -} - -static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - struct smbd_server_connection *sconn = req->sconn; - NTSTATUS status; - - tevent_wakeup_recv(subreq); - TALLOC_FREE(subreq); - - DEBUG(10,("smbd_smb2_request_dispatch_compound: idx[%d] of %d vectors\n", - req->current_idx, req->in.vector_count)); - - status = smbd_smb2_request_dispatch(req); - if (!NT_STATUS_IS_OK(status)) { - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } -} - -static void smbd_smb2_request_writev_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - struct smbd_server_connection *sconn = req->sconn; - int ret; - int sys_errno; - - ret = tstream_writev_queue_recv(subreq, &sys_errno); - TALLOC_FREE(subreq); - TALLOC_FREE(req); - if (ret == -1) { - NTSTATUS status = map_nt_error_from_unix(sys_errno); - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } -} - -NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req, - NTSTATUS status, - DATA_BLOB *info, - const char *location) -{ - uint8_t *outhdr; - uint8_t *outbody; - int i = req->current_idx; - - DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n", - i, nt_errstr(status), info ? " +info" : "", - location)); - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status)); - - outbody = outhdr + SMB2_HDR_BODY; - - req->out.vector[i+1].iov_base = (void *)outbody; - req->out.vector[i+1].iov_len = 8; - - if (info) { - SIVAL(outbody, 0x04, info->length); - req->out.vector[i+2].iov_base = (void *)info->data; - req->out.vector[i+2].iov_len = info->length; - } else { - req->out.vector[i+2].iov_base = NULL; - req->out.vector[i+2].iov_len = 0; - } - - /* - * if a request fails, all other remaining - * compounded requests should fail too - */ - req->next_status = NT_STATUS_INVALID_PARAMETER; - - return smbd_smb2_request_reply(req); -} - -NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req, - NTSTATUS status, - DATA_BLOB body, DATA_BLOB *dyn, - const char *location) -{ - uint8_t *outhdr; - uint8_t *outdyn; - int i = req->current_idx; - uint32_t next_command_ofs; - - DEBUG(10,("smbd_smb2_request_done_ex: " - "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n", - i, nt_errstr(status), (unsigned int)body.length, - dyn ? "yes": "no", - (unsigned int)(dyn ? dyn->length : 0), - location)); - - if (body.length < 2) { - return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR); - } - - if ((body.length % 2) != 0) { - return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR); - } - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - /* the fallback dynamic buffer */ - outdyn = outhdr + SMB2_HDR_BODY + 8; - - next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND); - SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status)); - - req->out.vector[i+1].iov_base = (void *)body.data; - req->out.vector[i+1].iov_len = body.length; - - if (dyn) { - req->out.vector[i+2].iov_base = (void *)dyn->data; - req->out.vector[i+2].iov_len = dyn->length; - } else { - req->out.vector[i+2].iov_base = NULL; - req->out.vector[i+2].iov_len = 0; - } - - /* see if we need to recalculate the offset to the next response */ - if (next_command_ofs > 0) { - next_command_ofs = SMB2_HDR_BODY; - next_command_ofs += req->out.vector[i+1].iov_len; - next_command_ofs += req->out.vector[i+2].iov_len; - } - - if ((next_command_ofs % 8) != 0) { - size_t pad_size = 8 - (next_command_ofs % 8); - if (req->out.vector[i+2].iov_len == 0) { - /* - * if the dyn buffer is empty - * we can use it to add padding - */ - uint8_t *pad; - - pad = talloc_zero_array(req->out.vector, - uint8_t, pad_size); - if (pad == NULL) { - return smbd_smb2_request_error(req, - NT_STATUS_NO_MEMORY); - } - - req->out.vector[i+2].iov_base = (void *)pad; - req->out.vector[i+2].iov_len = pad_size; - } else { - /* - * For now we copy the dynamic buffer - * and add the padding to the new buffer - */ - size_t old_size; - uint8_t *old_dyn; - size_t new_size; - uint8_t *new_dyn; - - old_size = req->out.vector[i+2].iov_len; - old_dyn = (uint8_t *)req->out.vector[i+2].iov_base; - - new_size = old_size + pad_size; - new_dyn = talloc_array(req->out.vector, - uint8_t, new_size); - if (new_dyn == NULL) { - return smbd_smb2_request_error(req, - NT_STATUS_NO_MEMORY); - } - - memcpy(new_dyn, old_dyn, old_size); - memset(new_dyn + old_size, 0, pad_size); - - req->out.vector[i+2].iov_base = (void *)new_dyn; - req->out.vector[i+2].iov_len = new_size; - - TALLOC_FREE(old_dyn); - } - next_command_ofs += pad_size; - } - - SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs); - - return smbd_smb2_request_reply(req); -} - -struct smbd_smb2_send_oplock_break_state { - struct smbd_server_connection *sconn; - uint8_t buf[4 + SMB2_HDR_BODY + 0x18]; - struct iovec vector; -}; - -static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq); - -NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn, - uint64_t file_id_persistent, - uint64_t file_id_volatile, - uint8_t oplock_level) -{ - struct smbd_smb2_send_oplock_break_state *state; - struct tevent_req *subreq; - uint8_t *hdr; - uint8_t *body; - - state = talloc(sconn, struct smbd_smb2_send_oplock_break_state); - if (state == NULL) { - return NT_STATUS_NO_MEMORY; - } - state->sconn = sconn; - - state->vector.iov_base = (void *)state->buf; - state->vector.iov_len = sizeof(state->buf); - - _smb2_setlen(state->buf, sizeof(state->buf) - 4); - hdr = state->buf + 4; - body = hdr + SMB2_HDR_BODY; - - SIVAL(hdr, 0, SMB2_MAGIC); - SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); - SSVAL(hdr, SMB2_HDR_EPOCH, 0); - SIVAL(hdr, SMB2_HDR_STATUS, 0); - SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK); - SSVAL(hdr, SMB2_HDR_CREDIT, 0); - SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT); - SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0); - SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX); - SIVAL(hdr, SMB2_HDR_PID, 0); - SIVAL(hdr, SMB2_HDR_TID, 0); - SBVAL(hdr, SMB2_HDR_SESSION_ID, 0); - memset(hdr+SMB2_HDR_SIGNATURE, 0, 16); - - SSVAL(body, 0x00, 0x18); - - SCVAL(body, 0x02, oplock_level); - SCVAL(body, 0x03, 0); /* reserved */ - SIVAL(body, 0x04, 0); /* reserved */ - SBVAL(body, 0x08, file_id_persistent); - SBVAL(body, 0x10, file_id_volatile); - - subreq = tstream_writev_queue_send(state, - sconn->smb2.event_ctx, - sconn->smb2.stream, - sconn->smb2.send_queue, - &state->vector, 1); - if (subreq == NULL) { - return NT_STATUS_NO_MEMORY; - } - tevent_req_set_callback(subreq, - smbd_smb2_oplock_break_writev_done, - state); - - return NT_STATUS_OK; -} - -static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq) -{ - struct smbd_smb2_send_oplock_break_state *state = - tevent_req_callback_data(subreq, - struct smbd_smb2_send_oplock_break_state); - struct smbd_server_connection *sconn = state->sconn; - int ret; - int sys_errno; - - ret = tstream_writev_queue_recv(subreq, &sys_errno); - TALLOC_FREE(subreq); - if (ret == -1) { - NTSTATUS status = map_nt_error_from_unix(sys_errno); - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } - - TALLOC_FREE(state); -} - -struct smbd_smb2_request_read_state { - size_t missing; - bool asked_for_header; - struct smbd_smb2_request *smb2_req; -}; - -static int smbd_smb2_request_next_vector(struct tstream_context *stream, - void *private_data, - TALLOC_CTX *mem_ctx, - struct iovec **_vector, - size_t *_count); -static void smbd_smb2_request_read_done(struct tevent_req *subreq); - -static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_server_connection *sconn) -{ - struct tevent_req *req; - struct smbd_smb2_request_read_state *state; - struct tevent_req *subreq; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_request_read_state); - if (req == NULL) { - return NULL; - } - state->missing = 0; - state->asked_for_header = false; - - state->smb2_req = smbd_smb2_request_allocate(state); - if (tevent_req_nomem(state->smb2_req, req)) { - return tevent_req_post(req, ev); - } - state->smb2_req->sconn = sconn; - - subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream, - sconn->smb2.recv_queue, - smbd_smb2_request_next_vector, - state); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req); - - return req; -} - -static int smbd_smb2_request_next_vector(struct tstream_context *stream, - void *private_data, - TALLOC_CTX *mem_ctx, - struct iovec **_vector, - size_t *_count) -{ - struct smbd_smb2_request_read_state *state = - talloc_get_type_abort(private_data, - struct smbd_smb2_request_read_state); - struct smbd_smb2_request *req = state->smb2_req; - struct iovec *vector; - int idx = req->in.vector_count; - size_t len = 0; - uint8_t *buf = NULL; - - if (req->in.vector_count == 0) { - /* - * first we need to get the NBT header - */ - req->in.vector = talloc_array(req, struct iovec, - req->in.vector_count + 1); - if (req->in.vector == NULL) { - return -1; - } - req->in.vector_count += 1; - - req->in.vector[idx].iov_base = (void *)req->in.nbt_hdr; - req->in.vector[idx].iov_len = 4; - - vector = talloc_array(mem_ctx, struct iovec, 1); - if (vector == NULL) { - return -1; - } - - vector[0] = req->in.vector[idx]; - - *_vector = vector; - *_count = 1; - return 0; - } - - if (req->in.vector_count == 1) { - /* - * Now we analyze the NBT header - */ - state->missing = smb2_len(req->in.vector[0].iov_base); - - if (state->missing == 0) { - /* if there're no remaining bytes, we're done */ - *_vector = NULL; - *_count = 0; - return 0; - } - - req->in.vector = talloc_realloc(req, req->in.vector, - struct iovec, - req->in.vector_count + 1); - if (req->in.vector == NULL) { - return -1; - } - req->in.vector_count += 1; - - if (CVAL(req->in.vector[0].iov_base, 0) != 0) { - /* - * it's a special NBT message, - * so get all remaining bytes - */ - len = state->missing; - } else if (state->missing < (SMB2_HDR_BODY + 2)) { - /* - * it's an invalid message, just read what we can get - * and let the caller handle the error - */ - len = state->missing; - } else { - /* - * We assume it's a SMB2 request, - * and we first get the header and the - * first 2 bytes (the struct size) of the body - */ - len = SMB2_HDR_BODY + 2; - - state->asked_for_header = true; - } - - state->missing -= len; - - buf = talloc_array(req->in.vector, uint8_t, len); - if (buf == NULL) { - return -1; - } - - req->in.vector[idx].iov_base = (void *)buf; - req->in.vector[idx].iov_len = len; - - vector = talloc_array(mem_ctx, struct iovec, 1); - if (vector == NULL) { - return -1; - } - - vector[0] = req->in.vector[idx]; - - *_vector = vector; - *_count = 1; - return 0; - } - - if (state->missing == 0) { - /* if there're no remaining bytes, we're done */ - *_vector = NULL; - *_count = 0; - return 0; - } - - if (state->asked_for_header) { - const uint8_t *hdr; - size_t full_size; - size_t next_command_ofs; - size_t body_size; - uint8_t *body; - size_t dyn_size; - uint8_t *dyn; - bool invalid = false; - - state->asked_for_header = false; - - /* - * We got the SMB2 header and the first 2 bytes - * of the body. We fix the size to just the header - * and manually copy the 2 first bytes to the body section - */ - req->in.vector[idx-1].iov_len = SMB2_HDR_BODY; - hdr = (const uint8_t *)req->in.vector[idx-1].iov_base; - - /* allocate vectors for body and dynamic areas */ - req->in.vector = talloc_realloc(req, req->in.vector, - struct iovec, - req->in.vector_count + 2); - if (req->in.vector == NULL) { - return -1; - } - req->in.vector_count += 2; - - full_size = state->missing + SMB2_HDR_BODY + 2; - next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND); - body_size = SVAL(hdr, SMB2_HDR_BODY); - - if (next_command_ofs != 0) { - if (next_command_ofs < (SMB2_HDR_BODY + 2)) { - /* - * this is invalid, just return a zero - * body and let the caller deal with the error - */ - invalid = true; - } else if (next_command_ofs > full_size) { - /* - * this is invalid, just return a zero - * body and let the caller deal with the error - */ - invalid = true; - } else { - full_size = next_command_ofs; - } - } - - if (!invalid) { - if (body_size < 2) { - /* - * this is invalid, just return a zero - * body and let the caller deal with the error - */ - invalid = true; - } - - if ((body_size % 2) != 0) { - body_size -= 1; - } - - if (body_size > (full_size - SMB2_HDR_BODY)) { - /* - * this is invalid, just return a zero - * body and let the caller deal with the error - */ - invalid = true; - } - } - - if (invalid) { - /* the caller should check this */ - body_size = 2; - } - - dyn_size = full_size - (SMB2_HDR_BODY + body_size); - - state->missing -= (body_size - 2) + dyn_size; - - body = talloc_array(req->in.vector, uint8_t, body_size); - if (body == NULL) { - return -1; - } - - dyn = talloc_array(req->in.vector, uint8_t, dyn_size); - if (dyn == NULL) { - return -1; - } - - req->in.vector[idx].iov_base = (void *)body; - req->in.vector[idx].iov_len = body_size; - req->in.vector[idx+1].iov_base = (void *)dyn; - req->in.vector[idx+1].iov_len = dyn_size; - - vector = talloc_array(mem_ctx, struct iovec, 2); - if (vector == NULL) { - return -1; - } - - /* - * the first 2 bytes of the body were already fetched - * together with the header - */ - memcpy(body, hdr + SMB2_HDR_BODY, 2); - vector[0].iov_base = body + 2; - vector[0].iov_len = body_size - 2; - - vector[1] = req->in.vector[idx+1]; - - *_vector = vector; - *_count = 2; - return 0; - } - - /* - * when we endup here, we're looking for a new SMB2 request - * next. And we ask for its header and the first 2 bytes of - * the body (like we did for the first SMB2 request). - */ - - req->in.vector = talloc_realloc(req, req->in.vector, - struct iovec, - req->in.vector_count + 1); - if (req->in.vector == NULL) { - return -1; - } - req->in.vector_count += 1; - - /* - * We assume it's a SMB2 request, - * and we first get the header and the - * first 2 bytes (the struct size) of the body - */ - len = SMB2_HDR_BODY + 2; - - if (len > state->missing) { - /* let the caller handle the error */ - len = state->missing; - } - - state->missing -= len; - state->asked_for_header = true; - - buf = talloc_array(req->in.vector, uint8_t, len); - if (buf == NULL) { - return -1; - } - - req->in.vector[idx].iov_base = (void *)buf; - req->in.vector[idx].iov_len = len; - - vector = talloc_array(mem_ctx, struct iovec, 1); - if (vector == NULL) { - return -1; - } - - vector[0] = req->in.vector[idx]; - - *_vector = vector; - *_count = 1; - return 0; -} - -static void smbd_smb2_request_read_done(struct tevent_req *subreq) -{ - struct tevent_req *req = - tevent_req_callback_data(subreq, - struct tevent_req); - int ret; - int sys_errno; - NTSTATUS status; - - ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno); - if (ret == -1) { - status = map_nt_error_from_unix(sys_errno); - tevent_req_nterror(req, status); - return; - } - - tevent_req_done(req); -} - -static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - struct smbd_smb2_request **_smb2_req) -{ - struct smbd_smb2_request_read_state *state = - tevent_req_data(req, - struct smbd_smb2_request_read_state); - NTSTATUS status; - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - talloc_steal(mem_ctx, state->smb2_req->mem_pool); - *_smb2_req = state->smb2_req; - tevent_req_received(req); - return NT_STATUS_OK; -} - -static void smbd_smb2_request_incoming(struct tevent_req *subreq); - -void smbd_smb2_first_negprot(struct smbd_server_connection *sconn, - const uint8_t *inbuf, size_t size) -{ - NTSTATUS status; - struct smbd_smb2_request *req; - struct tevent_req *subreq; - - DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n", - (unsigned int)size)); - - status = smbd_initialize_smb2(sconn); - if (!NT_STATUS_IS_OK(status)) { - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } - - status = smbd_smb2_request_create(sconn, inbuf, size, &req); - if (!NT_STATUS_IS_OK(status)) { - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } - - status = smbd_smb2_request_setup_out(req); - if (!NT_STATUS_IS_OK(status)) { - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } - - status = smbd_smb2_request_dispatch(req); - if (!NT_STATUS_IS_OK(status)) { - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } - - /* ask for the next request */ - subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn); - if (subreq == NULL) { - smbd_server_connection_terminate(sconn, "no memory for reading"); - return; - } - tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn); -} - -static void smbd_smb2_request_incoming(struct tevent_req *subreq) -{ - struct smbd_server_connection *sconn = tevent_req_callback_data(subreq, - struct smbd_server_connection); - NTSTATUS status; - struct smbd_smb2_request *req = NULL; - - status = smbd_smb2_request_read_recv(subreq, sconn, &req); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } - - if (req->in.nbt_hdr[0] != 0x00) { - DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n", - req->in.nbt_hdr[0])); - TALLOC_FREE(req); - goto next; - } - - req->current_idx = 1; - - DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n", - req->current_idx, req->in.vector_count)); - - status = smbd_smb2_request_validate(req); - if (!NT_STATUS_IS_OK(status)) { - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } - - status = smbd_smb2_request_setup_out(req); - if (!NT_STATUS_IS_OK(status)) { - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } - - status = smbd_smb2_request_dispatch(req); - if (!NT_STATUS_IS_OK(status)) { - smbd_server_connection_terminate(sconn, nt_errstr(status)); - return; - } - -next: - /* ask for the next request (this constructs the main loop) */ - subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn); - if (subreq == NULL) { - smbd_server_connection_terminate(sconn, "no memory for reading"); - return; - } - tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn); -} diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c deleted file mode 100644 index dc24124b54..0000000000 --- a/source3/smbd/smb2_sesssetup.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" -#include "../libcli/auth/spnego.h" - -static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *req, - 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); - -NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - DATA_BLOB outdyn; - size_t expected_body_size = 0x19; - size_t body_size; - uint64_t in_session_id; - uint8_t in_security_mode; - uint16_t in_security_offset; - uint16_t in_security_length; - DATA_BLOB in_security_buffer; - uint16_t out_session_flags; - uint64_t out_session_id; - uint16_t out_security_offset; - DATA_BLOB out_security_buffer; - NTSTATUS status; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_security_offset = SVAL(inbody, 0x0C); - in_security_length = SVAL(inbody, 0x0E); - - if (in_security_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (in_security_length > req->in.vector[i+2].iov_len) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID); - in_security_mode = CVAL(inbody, 0x03); - in_security_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base; - in_security_buffer.length = in_security_length; - - status = smbd_smb2_session_setup(req, - in_session_id, - in_security_mode, - in_security_buffer, - &out_session_flags, - &out_security_buffer, - &out_session_id); - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - status = nt_status_squash(status); - return smbd_smb2_request_error(req, status); - } - - out_security_offset = SMB2_HDR_BODY + 0x08; - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - outbody = data_blob_talloc(req->out.vector, NULL, 0x08); - if (outbody.data == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - - SBVAL(outhdr, SMB2_HDR_SESSION_ID, out_session_id); - - SSVAL(outbody.data, 0x00, 0x08 + 1); /* struct size */ - SSVAL(outbody.data, 0x02, - out_session_flags); /* session flags */ - SSVAL(outbody.data, 0x04, - out_security_offset); /* security buffer offset */ - SSVAL(outbody.data, 0x06, - out_security_buffer.length); /* security buffer length */ - - outdyn = out_security_buffer; - - return smbd_smb2_request_done_ex(req, status, outbody, &outdyn, - __location__); -} - -static int smbd_smb2_session_destructor(struct smbd_smb2_session *session) -{ - if (session->sconn == NULL) { - return 0; - } - - /* first free all tcons */ - while (session->tcons.list) { - talloc_free(session->tcons.list); - } - - idr_remove(session->sconn->smb2.sessions.idtree, session->vuid); - DLIST_REMOVE(session->sconn->smb2.sessions.list, session); - invalidate_vuid(session->sconn, session->vuid); - - session->vuid = 0; - session->status = NT_STATUS_USER_SESSION_DELETED; - session->sconn = NULL; - - return 0; -} - -static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *req, - 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; - NTSTATUS status; - - *out_session_flags = 0; - *out_session_id = 0; - - if (in_session_id == 0) { - int id; - - /* create a new session */ - session = talloc_zero(req->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(req->sconn->smb2.sessions.idtree, - session, - req->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(req->sconn->smb2.sessions.list, session, - struct smbd_smb2_session *); - session->sconn = req->sconn; - talloc_set_destructor(session, smbd_smb2_session_destructor); - } else { - void *p; - - /* lookup an existing session */ - p = idr_find(req->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 (session->auth_ntlmssp_state == NULL) { - status = auth_ntlmssp_start(&session->auth_ntlmssp_state); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(session); - return status; - } - } - - if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) { - DATA_BLOB secblob_in; - DATA_BLOB chal_out; - char *kerb_mech = NULL; - - status = parse_spnego_mechanisms(in_security_buffer, - &secblob_in, &kerb_mech); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(session); - return nt_status_squash(status); - } - - /* For now, just SPNEGO NTLMSSP - krb5 goes here later.. */ - status = auth_ntlmssp_update(session->auth_ntlmssp_state, - secblob_in, - &chal_out); - - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - auth_ntlmssp_end(&session->auth_ntlmssp_state); - TALLOC_FREE(session); - return nt_status_squash(status); - } - - *out_security_buffer = spnego_gen_auth_response(&chal_out, - status, OID_NTLMSSP); - - *out_session_id = session->vuid; - return status; - } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) { - DATA_BLOB auth = data_blob_null; - DATA_BLOB auth_out = data_blob_null; - - /* its an auth packet */ - if (!spnego_parse_auth(in_security_buffer, &auth)) { - TALLOC_FREE(session); - return NT_STATUS_LOGON_FAILURE; - } - /* For now, just SPNEGO NTLMSSP - krb5 goes here later.. */ - status = auth_ntlmssp_update(session->auth_ntlmssp_state, - auth, - &auth_out); - if (!NT_STATUS_IS_OK(status)) { - auth_ntlmssp_end(&session->auth_ntlmssp_state); - TALLOC_FREE(session); - return nt_status_squash(status); - } - - *out_security_buffer = spnego_gen_auth_response(&auth_out, - status, NULL); - - *out_session_id = session->vuid; - } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) { - - /* RAW NTLMSSP */ - status = auth_ntlmssp_update(session->auth_ntlmssp_state, - in_security_buffer, - out_security_buffer); - - if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - *out_session_id = session->vuid; - return status; - } - if (!NT_STATUS_IS_OK(status)) { - auth_ntlmssp_end(&session->auth_ntlmssp_state); - TALLOC_FREE(session); - return nt_status_squash(status); - } - *out_session_id = session->vuid; - } - - /* TODO: setup session key for signing */ - - if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || - lp_server_signing() == Required) { - session->do_signing = true; - } - - if (session->auth_ntlmssp_state->server_info->guest) { - /* we map anonymous to guest internally */ - *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST; - *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL; - /* force no signing */ - session->do_signing = false; - } - - session->server_info = session->auth_ntlmssp_state->server_info; - data_blob_free(&session->server_info->user_session_key); - session->server_info->user_session_key = - data_blob_talloc( - session->server_info, - session->auth_ntlmssp_state->ntlmssp_state->session_key.data, - session->auth_ntlmssp_state->ntlmssp_state->session_key.length); - if (session->auth_ntlmssp_state->ntlmssp_state->session_key.length > 0) { - if (session->server_info->user_session_key.data == NULL) { - TALLOC_FREE(session); - return NT_STATUS_NO_MEMORY; - } - } - session->session_key = session->server_info->user_session_key; - - session->compat_vuser = talloc_zero(session, user_struct); - if (session->compat_vuser == NULL) { - TALLOC_FREE(session); - return NT_STATUS_NO_MEMORY; - } - session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state; - session->compat_vuser->homes_snum = -1; - session->compat_vuser->server_info = session->server_info; - session->compat_vuser->session_keystr = NULL; - session->compat_vuser->vuid = session->vuid; - DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser); - - session->status = NT_STATUS_OK; - - /* - * we attach the session to the request - * so that the response can be signed - */ - req->session = session; - if (session->do_signing) { - req->do_signing = true; - } - - *out_session_id = session->vuid; - return status; -} - -NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - int i = req->current_idx; - uint64_t in_session_id; - void *p; - struct smbd_smb2_session *session; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - - in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID); - - /* lookup an existing session */ - p = idr_find(req->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_ACCESS_DENIED; - } - - set_current_user_info(session->server_info->sanitized_username, - session->server_info->unix_name, - pdb_get_domain(session->server_info->sam_account)); - - req->session = session; - return NT_STATUS_OK; -} - -NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) -{ - const uint8_t *inbody; - int i = req->current_idx; - DATA_BLOB outbody; - size_t expected_body_size = 0x04; - size_t body_size; - - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - /* - * TODO: cancel all outstanding requests on the session - * and delete all tree connections. - */ - smbd_smb2_session_destructor(req->session); - /* - * we may need to sign the response, so we need to keep - * the session until the response is sent to the wire. - */ - talloc_steal(req, req->session); - - outbody = data_blob_talloc(req->out.vector, NULL, 0x04); - if (outbody.data == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - - SSVAL(outbody.data, 0x00, 0x04); /* struct size */ - SSVAL(outbody.data, 0x02, 0); /* reserved */ - - return smbd_smb2_request_done(req, outbody, NULL); -} diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c deleted file mode 100644 index f3e3fc964f..0000000000 --- a/source3/smbd/smb2_setinfo.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint8_t in_info_type, - uint8_t in_file_info_class, - DATA_BLOB in_input_buffer, - uint32_t in_additional_information, - uint64_t in_file_id_volatile); -static NTSTATUS smbd_smb2_setinfo_recv(struct tevent_req *req); - -static void smbd_smb2_request_setinfo_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_setinfo(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - size_t expected_body_size = 0x21; - size_t body_size; - uint8_t in_info_type; - uint8_t in_file_info_class; - uint16_t in_input_buffer_offset; - uint32_t in_input_buffer_length; - DATA_BLOB in_input_buffer; - uint32_t in_additional_information; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - struct tevent_req *subreq; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_info_type = CVAL(inbody, 0x02); - in_file_info_class = CVAL(inbody, 0x03); - in_input_buffer_length = IVAL(inbody, 0x04); - in_input_buffer_offset = SVAL(inbody, 0x08); - /* 0x0A 2 bytes reserved */ - in_additional_information = IVAL(inbody, 0x0C); - in_file_id_persistent = BVAL(inbody, 0x10); - in_file_id_volatile = BVAL(inbody, 0x18); - - if (in_input_buffer_offset == 0 && in_input_buffer_length == 0) { - /* This is ok */ - } else if (in_input_buffer_offset != - (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (in_input_buffer_length > req->in.vector[i+2].iov_len) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_input_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base; - in_input_buffer.length = in_input_buffer_length; - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - subreq = smbd_smb2_setinfo_send(req, - req->sconn->smb2.event_ctx, - req, - in_info_type, - in_file_info_class, - in_input_buffer, - in_additional_information, - in_file_id_volatile); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_setinfo_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_setinfo_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - DATA_BLOB outbody; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_setinfo_recv(subreq); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - outbody = data_blob_talloc(req->out.vector, NULL, 0x02); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x02); /* struct size */ - - error = smbd_smb2_request_done(req, outbody, NULL); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } -} - -struct smbd_smb2_setinfo_state { - struct smbd_smb2_request *smb2req; -}; - -static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint8_t in_info_type, - uint8_t in_file_info_class, - DATA_BLOB in_input_buffer, - uint32_t in_additional_information, - uint64_t in_file_id_volatile) -{ - struct tevent_req *req; - struct smbd_smb2_setinfo_state *state; - struct smb_request *smbreq; - connection_struct *conn = smb2req->tcon->compat_conn; - files_struct *fsp; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_setinfo_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - - DEBUG(10,("smbd_smb2_setinfo_send: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (conn != fsp->conn) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smb2req->session->vuid != fsp->vuid) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - if (IS_IPC(conn)) { - tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); - return tevent_req_post(req, ev); - } - - switch (in_info_type) { - case 0x01:/* SMB2_SETINFO_FILE */ - { - uint16_t file_info_level; - char *data; - int data_size; - int ret_size = 0; - NTSTATUS status; - - - file_info_level = in_file_info_class + 1000; - if (file_info_level == SMB_FILE_RENAME_INFORMATION) { - file_info_level = 0xFF00 + in_file_info_class; - } - - if (fsp->is_directory || fsp->fh->fd == -1) { - /* - * This is actually a SETFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ - if (INFO_LEVEL_IS_UNIX(file_info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, fsp->fsp_name)) { - DEBUG(3,("smbd_smb2_setinfo_send: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", fsp_str_dbg(fsp), - strerror(errno))); - status = map_nt_error_from_unix(errno); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - } else { - if (SMB_VFS_STAT(conn, fsp->fsp_name) != 0) { - DEBUG(3,("smbd_smb2_setinfo_send: " - "fileinfo of %s failed (%s)\n", - fsp_str_dbg(fsp), - strerror(errno))); - status = map_nt_error_from_unix(errno); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - } - } else if (fsp->print_file) { - /* - * Doing a DELETE_ON_CLOSE should cancel a print job. - */ - if ((file_info_level == SMB_SET_FILE_DISPOSITION_INFO) - && in_input_buffer.length >= 1 - && CVAL(in_input_buffer.data,0)) { - fsp->fh->private_options |= FILE_DELETE_ON_CLOSE; - - DEBUG(3,("smbd_smb2_setinfo_send: " - "Cancelling print job (%s)\n", - fsp_str_dbg(fsp))); - - tevent_req_done(req); - return tevent_req_post(req, ev); - } else { - tevent_req_nterror(req, - NT_STATUS_OBJECT_PATH_INVALID); - return tevent_req_post(req, ev); - } - } else { - /* - * Original code - this is an open file. - */ - - if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) { - DEBUG(3,("smbd_smb2_setinfo_send: fstat " - "of fnum %d failed (%s)\n", fsp->fnum, - strerror(errno))); - status = map_nt_error_from_unix(errno); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - } - - data = NULL; - data_size = in_input_buffer.length; - if (data_size > 0) { - data = (char *)SMB_MALLOC_ARRAY(char, data_size); - if (tevent_req_nomem(data, req)) { - - } - memcpy(data, in_input_buffer.data, data_size); - } - - status = smbd_do_setfilepathinfo(conn, smbreq, state, - file_info_level, - fsp, - fsp->fsp_name, - &data, - data_size, - &ret_size); - SAFE_FREE(data); - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { - status = NT_STATUS_INVALID_INFO_CLASS; - } - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - break; - } - - default: - tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - - tevent_req_done(req); - return tevent_req_post(req, ev); -} - -static NTSTATUS smbd_smb2_setinfo_recv(struct tevent_req *req) -{ - NTSTATUS status; - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - tevent_req_received(req); - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_signing.c b/source3/smbd/smb2_signing.c deleted file mode 100644 index a7d2605318..0000000000 --- a/source3/smbd/smb2_signing.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB2 signing - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" -#include "../lib/crypto/crypto.h" - -NTSTATUS smb2_signing_sign_pdu(DATA_BLOB session_key, - struct iovec *vector, - int count) -{ - uint8_t *hdr; - uint64_t session_id; - struct HMACSHA256Context m; - uint8_t res[SHA256_DIGEST_LENGTH]; - int i; - - if (count < 2) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (vector[0].iov_len != SMB2_HDR_BODY) { - return NT_STATUS_INVALID_PARAMETER; - } - - hdr = (uint8_t *)vector[0].iov_base; - - session_id = BVAL(hdr, SMB2_HDR_SESSION_ID); - if (session_id == 0) { - /* - * do not sign messages with a zero session_id. - * See MS-SMB2 3.2.4.1.1 - */ - return NT_STATUS_OK; - } - - if (session_key.length == 0) { - DEBUG(2,("Wrong session key length %u for SMB2 signing\n", - (unsigned)session_key.length)); - return NT_STATUS_ACCESS_DENIED; - } - - memset(hdr + SMB2_HDR_SIGNATURE, 0, 16); - - SIVAL(hdr, SMB2_HDR_FLAGS, IVAL(hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED); - - ZERO_STRUCT(m); - hmac_sha256_init(session_key.data, MIN(session_key.length, 16), &m); - for (i=0; i < count; i++) { - hmac_sha256_update((const uint8_t *)vector[i].iov_base, - vector[i].iov_len, &m); - } - hmac_sha256_final(res, &m); - DEBUG(5,("signed SMB2 message\n")); - - memcpy(hdr + SMB2_HDR_SIGNATURE, res, 16); - - return NT_STATUS_OK; -} - -NTSTATUS smb2_signing_check_pdu(DATA_BLOB session_key, - const struct iovec *vector, - int count) -{ - const uint8_t *hdr; - const uint8_t *sig; - uint64_t session_id; - struct HMACSHA256Context m; - uint8_t res[SHA256_DIGEST_LENGTH]; - static const uint8_t zero_sig[16] = { 0, }; - int i; - - if (count < 2) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (vector[0].iov_len != SMB2_HDR_BODY) { - return NT_STATUS_INVALID_PARAMETER; - } - - hdr = (const uint8_t *)vector[0].iov_base; - - session_id = BVAL(hdr, SMB2_HDR_SESSION_ID); - if (session_id == 0) { - /* - * do not sign messages with a zero session_id. - * See MS-SMB2 3.2.4.1.1 - */ - return NT_STATUS_OK; - } - - if (session_key.length == 0) { - /* we don't have the session key yet */ - return NT_STATUS_OK; - } - - sig = hdr+SMB2_HDR_SIGNATURE; - - ZERO_STRUCT(m); - hmac_sha256_init(session_key.data, MIN(session_key.length, 16), &m); - hmac_sha256_update(hdr, SMB2_HDR_SIGNATURE, &m); - hmac_sha256_update(zero_sig, 16, &m); - for (i=1; i < count; i++) { - hmac_sha256_update((const uint8_t *)vector[i].iov_base, - vector[i].iov_len, &m); - } - hmac_sha256_final(res, &m); - - if (memcmp(res, sig, 16) != 0) { - DEBUG(0,("Bad SMB2 signature for message\n")); - dump_data(0, sig, 16); - dump_data(0, res, 16); - return NT_STATUS_ACCESS_DENIED; - } - - return NT_STATUS_OK; -} diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c deleted file mode 100644 index 70c5e8845e..0000000000 --- a/source3/smbd/smb2_tcon.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req, - const char *in_path, - uint8_t *out_share_type, - uint32_t *out_share_flags, - uint32_t *out_capabilities, - uint32_t *out_maximal_access, - uint32_t *out_tree_id); - -NTSTATUS smbd_smb2_request_process_tcon(struct smbd_smb2_request *req) -{ - const uint8_t *inbody; - int i = req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - size_t expected_body_size = 0x09; - size_t body_size; - uint16_t in_path_offset; - uint16_t in_path_length; - DATA_BLOB in_path_buffer; - char *in_path_string; - size_t in_path_string_size; - uint8_t out_share_type; - uint32_t out_share_flags; - uint32_t out_capabilities; - uint32_t out_maximal_access; - uint32_t out_tree_id; - NTSTATUS status; - bool ok; - - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_path_offset = SVAL(inbody, 0x04); - in_path_length = SVAL(inbody, 0x06); - - if (in_path_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (in_path_length > req->in.vector[i+2].iov_len) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_path_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base; - in_path_buffer.length = in_path_length; - - ok = convert_string_talloc(req, CH_UTF16, CH_UNIX, - in_path_buffer.data, - in_path_buffer.length, - &in_path_string, - &in_path_string_size, false); - if (!ok) { - return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER); - } - - status = smbd_smb2_tree_connect(req, in_path_string, - &out_share_type, - &out_share_flags, - &out_capabilities, - &out_maximal_access, - &out_tree_id); - if (!NT_STATUS_IS_OK(status)) { - return smbd_smb2_request_error(req, status); - } - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - outbody = data_blob_talloc(req->out.vector, NULL, 0x10); - if (outbody.data == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - - SIVAL(outhdr, SMB2_HDR_TID, out_tree_id); - - SSVAL(outbody.data, 0x00, 0x10); /* struct size */ - SCVAL(outbody.data, 0x02, - out_share_type); /* share type */ - SCVAL(outbody.data, 0x03, 0); /* reserved */ - SIVAL(outbody.data, 0x04, - out_share_flags); /* share flags */ - SIVAL(outbody.data, 0x08, - out_capabilities); /* capabilities */ - SIVAL(outbody.data, 0x0C, - out_maximal_access); /* maximal access */ - - return smbd_smb2_request_done(req, outbody, NULL); -} - -static int smbd_smb2_tcon_destructor(struct smbd_smb2_tcon *tcon) -{ - if (tcon->session == NULL) { - return 0; - } - - idr_remove(tcon->session->tcons.idtree, tcon->tid); - DLIST_REMOVE(tcon->session->tcons.list, tcon); - - if (tcon->compat_conn) { - conn_free(tcon->compat_conn); - } - - tcon->compat_conn = NULL; - tcon->tid = 0; - tcon->session = NULL; - - return 0; -} - -static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req, - const char *in_path, - uint8_t *out_share_type, - uint32_t *out_share_flags, - uint32_t *out_capabilities, - uint32_t *out_maximal_access, - uint32_t *out_tree_id) -{ - const char *share = in_path; - fstring service; - int snum = -1; - struct smbd_smb2_tcon *tcon; - int id; - NTSTATUS status; - - if (strncmp(share, "\\\\", 2) == 0) { - const char *p = strchr(share+2, '\\'); - if (p) { - share = p + 1; - } - } - - DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n", - in_path, share)); - - fstrcpy(service, share); - - strlower_m(service); - - snum = find_service(service); - if (snum < 0) { - DEBUG(3,("smbd_smb2_tree_connect: couldn't find service %s\n", - service)); - return NT_STATUS_BAD_NETWORK_NAME; - } - - /* TODO: do more things... */ - - /* create a new tcon as child of the session */ - tcon = talloc_zero(req->session, struct smbd_smb2_tcon); - if (tcon == NULL) { - return NT_STATUS_NO_MEMORY; - } - id = idr_get_new_random(req->session->tcons.idtree, - tcon, - req->session->tcons.limit); - if (id == -1) { - TALLOC_FREE(tcon); - return NT_STATUS_INSUFFICIENT_RESOURCES; - } - tcon->tid = id; - tcon->snum = snum; - - DLIST_ADD_END(req->session->tcons.list, tcon, - struct smbd_smb2_tcon *); - tcon->session = req->session; - talloc_set_destructor(tcon, smbd_smb2_tcon_destructor); - - tcon->compat_conn = make_connection_snum(req->sconn, - snum, req->session->compat_vuser, - data_blob_null, "???", - &status); - if (tcon->compat_conn == NULL) { - TALLOC_FREE(tcon); - return status; - } - tcon->compat_conn->cnum = tcon->tid; - - *out_share_type = 0x01; - *out_share_flags = SMB2_SHAREFLAG_ALL; - *out_capabilities = 0; - *out_maximal_access = FILE_GENERIC_ALL; - - *out_tree_id = tcon->tid; - return NT_STATUS_OK; -} - -NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - int i = req->current_idx; - uint32_t in_tid; - void *p; - struct smbd_smb2_tcon *tcon; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - - in_tid = IVAL(inhdr, SMB2_HDR_TID); - - /* lookup an existing session */ - p = idr_find(req->session->tcons.idtree, in_tid); - if (p == NULL) { - return NT_STATUS_NETWORK_NAME_DELETED; - } - tcon = talloc_get_type_abort(p, struct smbd_smb2_tcon); - - if (!change_to_user(tcon->compat_conn,req->session->vuid)) { - return NT_STATUS_ACCESS_DENIED; - } - - /* should we pass FLAG_CASELESS_PATHNAMES here? */ - if (!set_current_service(tcon->compat_conn, 0, true)) { - return NT_STATUS_ACCESS_DENIED; - } - - req->tcon = tcon; - return NT_STATUS_OK; -} - -NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) -{ - const uint8_t *inbody; - int i = req->current_idx; - DATA_BLOB outbody; - size_t expected_body_size = 0x04; - size_t body_size; - - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - /* - * TODO: cancel all outstanding requests on the tcon - * and delete all file handles. - */ - TALLOC_FREE(req->tcon); - - outbody = data_blob_talloc(req->out.vector, NULL, 0x04); - if (outbody.data == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - - SSVAL(outbody.data, 0x00, 0x04); /* struct size */ - SSVAL(outbody.data, 0x02, 0); /* reserved */ - - return smbd_smb2_request_done(req, outbody, NULL); -} diff --git a/source3/smbd/smb2_write.c b/source3/smbd/smb2_write.c deleted file mode 100644 index fa209fafc7..0000000000 --- a/source3/smbd/smb2_write.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Core SMB2 server - - Copyright (C) Stefan Metzmacher 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/smb/smb_common.h" - -static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint32_t in_smbpid, - uint64_t in_file_id_volatile, - DATA_BLOB in_data, - uint64_t in_offset, - uint32_t in_flags); -static NTSTATUS smbd_smb2_write_recv(struct tevent_req *req, - uint32_t *out_count); - -static void smbd_smb2_request_write_done(struct tevent_req *subreq); -NTSTATUS smbd_smb2_request_process_write(struct smbd_smb2_request *req) -{ - const uint8_t *inhdr; - const uint8_t *inbody; - int i = req->current_idx; - size_t expected_body_size = 0x31; - size_t body_size; - uint32_t in_smbpid; - uint16_t in_data_offset; - uint32_t in_data_length; - DATA_BLOB in_data_buffer; - uint64_t in_offset; - uint64_t in_file_id_persistent; - uint64_t in_file_id_volatile; - uint32_t in_flags; - struct tevent_req *subreq; - - inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; - if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - inbody = (const uint8_t *)req->in.vector[i+1].iov_base; - - body_size = SVAL(inbody, 0x00); - if (body_size != expected_body_size) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_smbpid = IVAL(inhdr, SMB2_HDR_PID); - - in_data_offset = SVAL(inbody, 0x02); - in_data_length = IVAL(inbody, 0x04); - in_offset = BVAL(inbody, 0x08); - in_file_id_persistent = BVAL(inbody, 0x10); - in_file_id_volatile = BVAL(inbody, 0x18); - in_flags = IVAL(inbody, 0x2C); - - if (in_data_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - if (in_data_length > req->in.vector[i+2].iov_len) { - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - /* check the max write size */ - if (in_data_length > 0x00010000) { - DEBUG(0,("here:%s: 0x%08X: 0x%08X\n", - __location__, in_data_length, 0x00010000)); - return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); - } - - in_data_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base; - in_data_buffer.length = in_data_length; - - if (req->compat_chain_fsp) { - /* skip check */ - } else if (in_file_id_persistent != 0) { - return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); - } - - subreq = smbd_smb2_write_send(req, - req->sconn->smb2.event_ctx, - req, - in_smbpid, - in_file_id_volatile, - in_data_buffer, - in_offset, - in_flags); - if (subreq == NULL) { - return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - } - tevent_req_set_callback(subreq, smbd_smb2_request_write_done, req); - - return smbd_smb2_request_pending_queue(req, subreq); -} - -static void smbd_smb2_request_write_done(struct tevent_req *subreq) -{ - struct smbd_smb2_request *req = tevent_req_callback_data(subreq, - struct smbd_smb2_request); - int i = req->current_idx; - uint8_t *outhdr; - DATA_BLOB outbody; - DATA_BLOB outdyn; - uint32_t out_count = 0; - NTSTATUS status; - NTSTATUS error; /* transport error */ - - status = smbd_smb2_write_recv(subreq, &out_count); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - error = smbd_smb2_request_error(req, status); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - outhdr = (uint8_t *)req->out.vector[i].iov_base; - - outbody = data_blob_talloc(req->out.vector, NULL, 0x10); - if (outbody.data == NULL) { - error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, - nt_errstr(error)); - return; - } - return; - } - - SSVAL(outbody.data, 0x00, 0x10 + 1); /* struct size */ - SSVAL(outbody.data, 0x02, 0); /* reserved */ - SIVAL(outbody.data, 0x04, out_count); /* count */ - SIVAL(outbody.data, 0x08, 0); /* remaining */ - SSVAL(outbody.data, 0x0C, 0); /* write channel info offset */ - SSVAL(outbody.data, 0x0E, 0); /* write channel info length */ - - outdyn = data_blob_const(NULL, 0); - - error = smbd_smb2_request_done(req, outbody, &outdyn); - if (!NT_STATUS_IS_OK(error)) { - smbd_server_connection_terminate(req->sconn, nt_errstr(error)); - return; - } -} - -struct smbd_smb2_write_state { - struct smbd_smb2_request *smb2req; - uint32_t in_length; - uint32_t out_count; -}; - -static void smbd_smb2_write_pipe_done(struct tevent_req *subreq); - -static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct smbd_smb2_request *smb2req, - uint32_t in_smbpid, - uint64_t in_file_id_volatile, - DATA_BLOB in_data, - uint64_t in_offset, - uint32_t in_flags) -{ - NTSTATUS status; - struct tevent_req *req; - struct smbd_smb2_write_state *state; - struct smb_request *smbreq; - connection_struct *conn = smb2req->tcon->compat_conn; - files_struct *fsp; - ssize_t nwritten; - bool write_through = false; - struct lock_struct lock; - - req = tevent_req_create(mem_ctx, &state, - struct smbd_smb2_write_state); - if (req == NULL) { - return NULL; - } - state->smb2req = smb2req; - state->in_length = in_data.length; - state->out_count = 0; - - DEBUG(10,("smbd_smb2_write: file_id[0x%016llX]\n", - (unsigned long long)in_file_id_volatile)); - - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { - return tevent_req_post(req, ev); - } - - fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile); - if (fsp == NULL) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (conn != fsp->conn) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - if (smb2req->session->vuid != fsp->vuid) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - if (IS_IPC(smbreq->conn)) { - struct tevent_req *subreq; - - if (!fsp_is_np(fsp)) { - tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); - return tevent_req_post(req, ev); - } - - subreq = np_write_send(state, smbd_event_context(), - fsp->fake_file_handle, - in_data.data, - in_data.length); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, - smbd_smb2_write_pipe_done, - req); - return req; - } - - if (!CHECK_WRITE(fsp)) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return tevent_req_post(req, ev); - } - - init_strict_lock_struct(fsp, - in_smbpid, - in_offset, - in_data.length, - WRITE_LOCK, - &lock); - - if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); - return tevent_req_post(req, ev); - } - - nwritten = write_file(smbreq, fsp, - (const char *)in_data.data, - in_offset, - in_data.length); - - if (((nwritten == 0) && (in_data.length != 0)) || (nwritten < 0)) { - DEBUG(5,("smbd_smb2_write: write_file[%s] disk full\n", - fsp_str_dbg(fsp))); - SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); - tevent_req_nterror(req, NT_STATUS_DISK_FULL); - return tevent_req_post(req, ev); - } - - DEBUG(3,("smbd_smb2_write: fnum=[%d/%s] length=%d offset=%d wrote=%d\n", - fsp->fnum, fsp_str_dbg(fsp), (int)in_data.length, - (int)in_offset, (int)nwritten)); - - if (in_flags & 0x00000001) { - write_through = true; - } - - status = sync_file(conn, fsp, write_through); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(5,("smbd_smb2_write: sync_file for %s returned %s\n", - fsp_str_dbg(fsp), nt_errstr(status))); - SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - - SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); - - state->out_count = nwritten; - - tevent_req_done(req); - return tevent_req_post(req, ev); -} - -static void smbd_smb2_write_pipe_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct smbd_smb2_write_state *state = tevent_req_data(req, - struct smbd_smb2_write_state); - NTSTATUS status; - ssize_t nwritten = -1; - - status = np_write_recv(subreq, &nwritten); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return; - } - - if ((nwritten == 0 && state->in_length != 0) || (nwritten < 0)) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - - state->out_count = nwritten; - - tevent_req_done(req); -} - -static NTSTATUS smbd_smb2_write_recv(struct tevent_req *req, - uint32_t *out_count) -{ - NTSTATUS status; - struct smbd_smb2_write_state *state = tevent_req_data(req, - struct smbd_smb2_write_state); - - if (tevent_req_is_nterror(req, &status)) { - tevent_req_received(req); - return status; - } - - *out_count = state->out_count; - - tevent_req_received(req); - return NT_STATUS_OK; -} diff --git a/source3/smbd/srvstr.c b/source3/smbd/srvstr.c index d3f341138c..62b0fe1617 100644 --- a/source3/smbd/srvstr.c +++ b/source3/smbd/srvstr.c @@ -32,8 +32,8 @@ size_t srvstr_push_fn(const char *function, unsigned int line, } /* 'normal' push into size-specified buffer */ - return push_string_base(function, line, base_ptr, smb_flags2, dest, src, - dest_len, flags); + return push_string_fn(function, line, base_ptr, smb_flags2, dest, src, + dest_len, flags); } /******************************************************************* diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c index db347b5b7e..72fed008a2 100644 --- a/source3/smbd/statcache.c +++ b/source3/smbd/statcache.c @@ -175,7 +175,6 @@ bool stat_cache_lookup(connection_struct *conn, DATA_BLOB data_val; char *name; TALLOC_CTX *ctx = talloc_tos(); - struct smb_filename smb_fname; *pp_dirpath = NULL; *pp_start = *pp_name; @@ -206,7 +205,7 @@ bool stat_cache_lookup(connection_struct *conn, } else { chk_name = talloc_strdup_upper(ctx,name); if (!chk_name) { - DEBUG(0, ("stat_cache_lookup: talloc_strdup_upper failed!\n")); + DEBUG(0, ("stat_cache_lookup: strdup_upper failed!\n")); return False; } @@ -275,10 +274,7 @@ bool stat_cache_lookup(connection_struct *conn, "-> [%s]\n", chk_name, translated_path )); DO_PROFILE_INC(statcache_hits); - ZERO_STRUCT(smb_fname); - smb_fname.base_name = translated_path; - - if (SMB_VFS_STAT(conn, &smb_fname) != 0) { + if (SMB_VFS_STAT(conn, translated_path, pst) != 0) { /* Discard this entry - it doesn't exist in the filesystem. */ memcache_delete(smbd_memcache(), STAT_CACHE, data_blob_const(chk_name, strlen(chk_name))); @@ -286,7 +282,6 @@ bool stat_cache_lookup(connection_struct *conn, TALLOC_FREE(translated_path); return False; } - *pst = smb_fname.st; if (!sizechanged) { memcpy(*pp_name, translated_path, diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 5620a2fd0d..e6d2b0ab8d 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -26,7 +26,8 @@ #include "includes.h" #include "version.h" #include "smbd/globals.h" -#include "../libcli/auth/libcli_auth.h" + +extern enum protocol_types Protocol; #define DIR_ENTRY_SAFETY_MARGIN 4096 @@ -70,8 +71,6 @@ static bool samba_private_attr_name(const char *unix_ea_name) static const char * const prohibited_ea_names[] = { SAMBA_POSIX_INHERITANCE_EA_NAME, SAMBA_XATTR_DOS_ATTRIB, - SAMBA_XATTR_MARKER, - XATTR_NTACL_NAME, NULL }; @@ -155,9 +154,7 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, ssize_t sizeret = -1; if (!lp_ea_support(SNUM(conn))) { - if (pnames) { - *pnames = NULL; - } + *pnames = NULL; *pnum_names = 0; return NT_STATUS_OK; } @@ -208,9 +205,7 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, if (sizeret == 0) { TALLOC_FREE(names); - if (pnames) { - *pnames = NULL; - } + *pnames = NULL; *pnum_names = 0; return NT_STATUS_OK; } @@ -247,11 +242,7 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, names[num_names++] = p; } - if (pnames) { - *pnames = names; - } else { - TALLOC_FREE(names); - } + *pnames = names; *pnum_names = num_names; return NT_STATUS_OK; } @@ -375,69 +366,6 @@ static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned in return ret_data_size; } -static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx, - char *pdata, - unsigned int total_data_size, - unsigned int *ret_data_size, - connection_struct *conn, - struct ea_list *ea_list) -{ - uint8_t *p = (uint8_t *)pdata; - uint8_t *last_start = NULL; - - *ret_data_size = 0; - - if (!lp_ea_support(SNUM(conn))) { - return NT_STATUS_NO_EAS_ON_FILE; - } - - for (; ea_list; ea_list = ea_list->next) { - size_t dos_namelen; - fstring dos_ea_name; - size_t this_size; - - if (last_start) { - SIVAL(last_start, 0, PTR_DIFF(p, last_start)); - } - last_start = p; - - push_ascii_fstring(dos_ea_name, ea_list->ea.name); - dos_namelen = strlen(dos_ea_name); - if (dos_namelen > 255 || dos_namelen == 0) { - return NT_STATUS_INTERNAL_ERROR; - } - if (ea_list->ea.value.length > 65535) { - return NT_STATUS_INTERNAL_ERROR; - } - - this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length; - - if (ea_list->next) { - size_t pad = 4 - (this_size % 4); - this_size += pad; - } - - if (this_size > total_data_size) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - - /* We know we have room. */ - SIVAL(p, 0x00, 0); /* next offset */ - SCVAL(p, 0x04, ea_list->ea.flags); - SCVAL(p, 0x05, dos_namelen); - SSVAL(p, 0x06, ea_list->ea.value.length); - fstrcpy((char *)(p+0x08), dos_ea_name); - memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length); - - total_data_size -= this_size; - p += this_size; - } - - *ret_data_size = PTR_DIFF(p, pdata); - DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size)); - return NT_STATUS_OK; -} - static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname) { size_t total_ea_len = 0; @@ -475,18 +403,12 @@ static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, con Set or delete an extended attribute. ****************************************************************************/ -NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, - const struct smb_filename *smb_fname, struct ea_list *ea_list) +NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname, struct ea_list *ea_list) { - char *fname = NULL; - if (!lp_ea_support(SNUM(conn))) { return NT_STATUS_EAS_NOT_SUPPORTED; } - /* For now setting EAs on streams isn't supported. */ - fname = smb_fname->base_name; - for (;ea_list; ea_list = ea_list->next) { int ret; fstring unix_ea_name; @@ -506,9 +428,8 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, if (ea_list->ea.value.length == 0) { /* Remove the attribute. */ if (fsp && (fsp->fh->fd != -1)) { - DEBUG(10,("set_ea: deleting ea name %s on " - "file %s by file descriptor.\n", - unix_ea_name, fsp_str_dbg(fsp))); + DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n", + unix_ea_name, fsp->fsp_name)); ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name); } else { DEBUG(10,("set_ea: deleting ea name %s on file %s.\n", @@ -525,9 +446,8 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, #endif } else { if (fsp && (fsp->fh->fd != -1)) { - DEBUG(10,("set_ea: setting ea name %s on file " - "%s by file descriptor.\n", - unix_ea_name, fsp_str_dbg(fsp))); + DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n", + unix_ea_name, fsp->fsp_name)); ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name, ea_list->ea.value.data, ea_list->ea.value.length, 0); } else { @@ -761,8 +681,6 @@ void send_trans2_replies(connection_struct *conn, int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */ int data_alignment_offset = 0; bool overflow = False; - struct smbd_server_connection *sconn = smbd_server_conn; - int max_send = sconn->smb1.sessions.max_send; /* Modify the data_to_send and datasize and set the error if we're trying to send more than max_data_bytes. We still send @@ -781,14 +699,6 @@ void send_trans2_replies(connection_struct *conn, if(params_to_send == 0 && data_to_send == 0) { reply_outbuf(req, 10, 0); show_msg((char *)req->outbuf); - if (!srv_send_smb(smbd_server_fd(), - (char *)req->outbuf, - true, req->seqnum+1, - IS_CONN_ENCRYPTED(conn), - &req->pcd)) { - exit_server_cleanly("send_trans2_replies: srv_send_smb failed."); - } - TALLOC_FREE(req->outbuf); return; } @@ -922,7 +832,6 @@ void send_trans2_replies(connection_struct *conn, show_msg((char *)req->outbuf); if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf, - true, req->seqnum+1, IS_CONN_ENCRYPTED(conn), &req->pcd)) exit_server_cleanly("send_trans2_replies: srv_send_smb failed."); @@ -956,7 +865,6 @@ static void call_trans2open(connection_struct *conn, char **ppdata, int total_data, unsigned int max_data_bytes) { - struct smb_filename *smb_fname = NULL; char *params = *pparams; char *pdata = *ppdata; int deny_mode; @@ -974,6 +882,7 @@ static void call_trans2open(connection_struct *conn, SMB_OFF_T size=0; int fattr=0,mtime=0; SMB_INO_T inode = 0; + SMB_STRUCT_STAT sbuf; int smb_action = 0; files_struct *fsp; struct ea_list *ea_list = NULL; @@ -985,13 +894,15 @@ static void call_trans2open(connection_struct *conn, uint32 create_options = 0; TALLOC_CTX *ctx = talloc_tos(); + SET_STAT_INVALID(sbuf); + /* * Ensure we have enough parameters to perform the operation. */ if (total_params < 29) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } flags = SVAL(params, 0); @@ -1012,8 +923,8 @@ static void call_trans2open(connection_struct *conn, pname = ¶ms[28]; if (IS_IPC(conn)) { - reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED); - goto out; + reply_doserror(req, ERRSRV, ERRaccess); + return; } srvstr_get_path(ctx, params, req->flags2, &fname, pname, @@ -1021,79 +932,63 @@ static void call_trans2open(connection_struct *conn, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + return; } DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n", fname, (unsigned int)deny_mode, (unsigned int)open_attr, (unsigned int)open_ofun, open_size)); - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - goto out; - } - reply_nterror(req, status); - goto out; - } - if (open_ofun == 0) { reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION); - goto out; + return; } - if (!map_open_params_to_ntcreate(smb_fname, deny_mode, open_ofun, - &access_mask, &share_mode, - &create_disposition, - &create_options)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - goto out; + if (!map_open_params_to_ntcreate(fname, deny_mode, open_ofun, + &access_mask, + &share_mode, + &create_disposition, + &create_options)) { + reply_doserror(req, ERRDOS, ERRbadaccess); + return; } /* Any data in this call is an EA list. */ if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) { reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); - goto out; + return; } if (total_data != 4) { if (total_data < 10) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } if (IVAL(pdata,0) > total_data) { DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n", IVAL(pdata,0), (unsigned int)total_data)); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } ea_list = read_ea_list(talloc_tos(), pdata + 4, total_data - 4); if (!ea_list) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } } else if (IVAL(pdata,0) != 4) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + CFF_DOS_PATH, /* create_file_flags */ access_mask, /* access_mask */ share_mode, /* share_access */ create_disposition, /* create_disposition*/ @@ -1104,32 +999,33 @@ static void call_trans2open(connection_struct *conn, NULL, /* sd */ ea_list, /* ea_list */ &fsp, /* result */ - &smb_action); /* psbuf */ + &smb_action, /* pinfo */ + &sbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - goto out; + return; } reply_openerror(req, status); - goto out; + return; } - size = get_file_size_stat(&smb_fname->st); - fattr = dos_mode(conn, smb_fname); - mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime); - inode = smb_fname->st.st_ex_ino; + size = get_file_size_stat(&sbuf); + fattr = dos_mode(conn,fsp->fsp_name,&sbuf); + mtime = sbuf.st_mtime; + inode = sbuf.st_ino; if (fattr & aDIR) { close_file(req, fsp, ERROR_CLOSE); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - goto out; + reply_doserror(req, ERRDOS,ERRnoaccess); + return; } /* Realloc the size of parameters and data we will return */ *pparams = (char *)SMB_REALLOC(*pparams, 30); if(*pparams == NULL ) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + return; } params = *pparams; @@ -1153,8 +1049,7 @@ static void call_trans2open(connection_struct *conn, SIVAL(params,20,inode); SSVAL(params,24,0); /* Padding. */ if (flags & 8) { - uint32 ea_size = estimate_ea_size(conn, fsp, - fsp->fsp_name->base_name); + uint32 ea_size = estimate_ea_size(conn, fsp, fsp->fsp_name); SIVAL(params, 26, ea_size); } else { SIVAL(params, 26, 0); @@ -1162,8 +1057,6 @@ static void call_trans2open(connection_struct *conn, /* Send the required number of replies */ send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes); - out: - TALLOC_FREE(smb_fname); } /********************************************************* @@ -1173,24 +1066,19 @@ static void call_trans2open(connection_struct *conn, Case can be significant or not. **********************************************************/ -static bool exact_match(bool has_wild, - bool case_sensitive, - const char *str, - const char *mask) +static bool exact_match(connection_struct *conn, + const char *str, + const char *mask) { - if (mask[0] == '.' && mask[1] == 0) { - return false; - } - - if (has_wild) { - return false; + if (mask[0] == '.' && mask[1] == 0) + return False; + if (dptr_has_wild(conn->dirptr)) { + return False; } - - if (case_sensitive) { + if (conn->case_sensitive) return strcmp(str,mask)==0; - } else { + else return StrCaseCmp(str,mask) == 0; - } } /**************************************************************************** @@ -1235,7 +1123,7 @@ static uint32 unix_filetype(mode_t mode) enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_DIR}; static NTSTATUS unix_perms_from_wire( connection_struct *conn, - const SMB_STRUCT_STAT *psbuf, + SMB_STRUCT_STAT *psbuf, uint32 perms, enum perm_type ptype, mode_t *ret_perms) @@ -1246,7 +1134,7 @@ static NTSTATUS unix_perms_from_wire( connection_struct *conn, if (!VALID_STAT(*psbuf)) { return NT_STATUS_INVALID_PARAMETER; } else { - *ret_perms = psbuf->st_ex_mode; + *ret_perms = psbuf->st_mode; return NT_STATUS_OK; } } @@ -1317,7 +1205,7 @@ static bool check_msdfs_link(connection_struct *conn, DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s " "as a directory\n", pathname)); - psbuf->st_ex_mode = (psbuf->st_ex_mode & 0xFFF) | S_IFDIR; + psbuf->st_mode = (psbuf->st_mode & 0xFFF) | S_IFDIR; errno = saved_errno; return true; } @@ -1330,699 +1218,640 @@ static bool check_msdfs_link(connection_struct *conn, Get a level dependent lanman2 dir entry. ****************************************************************************/ -struct smbd_dirptr_lanman2_state { - connection_struct *conn; - uint32_t info_level; - bool check_mangled_names; - bool has_wild; - bool got_exact_match; -}; - -static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx, - void *private_data, - const char *dname, - const char *mask, - char **_fname) +static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, + connection_struct *conn, + uint16 flags2, + const char *path_mask, + uint32 dirtype, + int info_level, + int requires_resume_key, + bool dont_descend, + bool ask_sharemode, + char **ppdata, + char *base_data, + char *end_data, + int space_remaining, + bool *out_of_space, + bool *got_exact_match, + int *last_entry_off, + struct ea_list *name_list) { - struct smbd_dirptr_lanman2_state *state = - (struct smbd_dirptr_lanman2_state *)private_data; - bool ok; + char *dname; + bool found = False; + SMB_STRUCT_STAT sbuf; + const char *mask = NULL; + char *pathreal = NULL; + char *fname = NULL; + char *p, *q, *pdata = *ppdata; + uint32 reskey=0; + long prev_dirpos=0; + uint32 mode=0; + SMB_OFF_T file_size = 0; + uint64_t allocation_size = 0; + uint32 len; + struct timespec mdate_ts, adate_ts, create_date_ts; + time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0; + char *nameptr; + char *last_entry_ptr; + bool was_8_3; + bool needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); + bool check_mangled_names = lp_manglednames(conn->params); char mangled_name[13]; /* mangled 8.3 name. */ - bool got_match; - const char *fname; - /* Mangle fname if it's an illegal name. */ - if (mangle_must_mangle(dname, state->conn->params)) { - ok = name_to_8_3(dname, mangled_name, - true, state->conn->params); - if (!ok) { - return false; + *out_of_space = False; + *got_exact_match = False; + + ZERO_STRUCT(mdate_ts); + ZERO_STRUCT(adate_ts); + ZERO_STRUCT(create_date_ts); + + if (!conn->dirptr) { + return(False); + } + + p = strrchr_m(path_mask,'/'); + if(p != NULL) { + if(p[1] == '\0') { + mask = talloc_strdup(ctx,"*.*"); + } else { + mask = p+1; } - fname = mangled_name; } else { - fname = dname; + mask = path_mask; } - got_match = exact_match(state->has_wild, - state->conn->case_sensitive, - fname, mask); - state->got_exact_match = got_match; - if (!got_match) { - got_match = mask_match(fname, mask, - state->conn->case_sensitive); - } + while (!found) { + bool got_match; + bool ms_dfs_link = False; + + /* Needed if we run out of space */ + long curr_dirpos = prev_dirpos = dptr_TellDir(conn->dirptr); + dname = dptr_ReadDirName(ctx,conn->dirptr,&curr_dirpos,&sbuf); - if(!got_match && state->check_mangled_names && - !mangle_is_8_3(fname, false, state->conn->params)) { /* - * It turns out that NT matches wildcards against - * both long *and* short names. This may explain some - * of the wildcard wierdness from old DOS clients - * that some people have been seeing.... JRA. + * Due to bugs in NT client redirectors we are not using + * resume keys any more - set them to zero. + * Check out the related comments in findfirst/findnext. + * JRA. */ - /* Force the mangling into 8.3. */ - ok = name_to_8_3(fname, mangled_name, - false, state->conn->params); - if (!ok) { - return false; - } - got_match = exact_match(state->has_wild, - state->conn->case_sensitive, - mangled_name, mask); - state->got_exact_match = got_match; - if (!got_match) { - got_match = mask_match(mangled_name, mask, - state->conn->case_sensitive); - } - } + reskey = 0; - if (!got_match) { - return false; - } + DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %ld\n", + (long)conn->dirptr,curr_dirpos)); - *_fname = talloc_strdup(ctx, fname); - if (*_fname == NULL) { - return false; - } + if (!dname) { + return(False); + } - return true; -} + /* + * fname may get mangled, dname is never mangled. + * Whenever we're accessing the filesystem we use + * pathreal which is composed from dname. + */ -static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx, - void *private_data, - struct smb_filename *smb_fname, - uint32_t *_mode) -{ - struct smbd_dirptr_lanman2_state *state = - (struct smbd_dirptr_lanman2_state *)private_data; - bool ms_dfs_link = false; - uint32_t mode = 0; + pathreal = NULL; + fname = dname; - if (INFO_LEVEL_IS_UNIX(state->info_level)) { - if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) { - DEBUG(5,("smbd_dirptr_lanman2_mode_fn: " - "Couldn't lstat [%s] (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - return false; + /* Mangle fname if it's an illegal name. */ + if (mangle_must_mangle(dname,conn->params)) { + if (!name_to_8_3(dname,mangled_name,True,conn->params)) { + TALLOC_FREE(fname); + continue; /* Error - couldn't mangle. */ + } + fname = talloc_strdup(ctx, mangled_name); + if (!fname) { + return False; + } } - } else if (!VALID_STAT(smb_fname->st) && - SMB_VFS_STAT(state->conn, smb_fname) != 0) { - /* Needed to show the msdfs symlinks as - * directories */ - ms_dfs_link = check_msdfs_link(state->conn, - smb_fname->base_name, - &smb_fname->st); - if (!ms_dfs_link) { - DEBUG(5,("smbd_dirptr_lanman2_mode_fn: " - "Couldn't stat [%s] (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - return false; + if(!(got_match = *got_exact_match = exact_match(conn, fname, mask))) { + got_match = mask_match(fname, mask, conn->case_sensitive); } - } - if (ms_dfs_link) { - mode = dos_mode_msdfs(state->conn, smb_fname); - } else { - mode = dos_mode(state->conn, smb_fname); - } + if(!got_match && check_mangled_names && + !mangle_is_8_3(fname, False, conn->params)) { + /* + * It turns out that NT matches wildcards against + * both long *and* short names. This may explain some + * of the wildcard wierdness from old DOS clients + * that some people have been seeing.... JRA. + */ + /* Force the mangling into 8.3. */ + if (!name_to_8_3( fname, mangled_name, False, conn->params)) { + TALLOC_FREE(fname); + continue; /* Error - couldn't mangle. */ + } - *_mode = mode; - return true; -} + if(!(got_match = *got_exact_match = exact_match(conn, mangled_name, mask))) { + got_match = mask_match(mangled_name, mask, conn->case_sensitive); + } + } -static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, - connection_struct *conn, - uint16_t flags2, - uint32_t info_level, - struct ea_list *name_list, - bool check_mangled_names, - bool requires_resume_key, - uint32_t mode, - const char *fname, - const struct smb_filename *smb_fname, - uint64_t space_remaining, - uint8_t align, - bool do_pad, - char *base_data, - char **ppdata, - char *end_data, - bool *out_of_space, - uint64_t *last_entry_off) -{ - char *p, *q, *pdata = *ppdata; - uint32_t reskey=0; - uint64_t file_size = 0; - uint64_t allocation_size = 0; - uint32_t len; - struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts; - time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0; - time_t c_date = (time_t)0; - char *nameptr; - char *last_entry_ptr; - bool was_8_3; - off_t off; - off_t pad = 0; + if (got_match) { + bool isdots = (ISDOT(dname) || ISDOTDOT(dname)); - *out_of_space = false; + if (dont_descend && !isdots) { + TALLOC_FREE(fname); + continue; + } - ZERO_STRUCT(mdate_ts); - ZERO_STRUCT(adate_ts); - ZERO_STRUCT(create_date_ts); - ZERO_STRUCT(cdate_ts); + if (needslash) { + pathreal = NULL; + pathreal = talloc_asprintf(ctx, + "%s/%s", + conn->dirpath, + dname); + } else { + pathreal = talloc_asprintf(ctx, + "%s%s", + conn->dirpath, + dname); + } - if (!(mode & aDIR)) { - file_size = get_file_size_stat(&smb_fname->st); - } - allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st); + if (!pathreal) { + TALLOC_FREE(fname); + return False; + } - mdate_ts = smb_fname->st.st_ex_mtime; - adate_ts = smb_fname->st.st_ex_atime; - create_date_ts = get_create_timespec(conn, NULL, smb_fname); - cdate_ts = get_change_timespec(conn, NULL, smb_fname); + if (INFO_LEVEL_IS_UNIX(info_level)) { + if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) { + DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n", + pathreal,strerror(errno))); + TALLOC_FREE(pathreal); + TALLOC_FREE(fname); + continue; + } + } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) { + /* Needed to show the msdfs symlinks as + * directories */ + + ms_dfs_link = check_msdfs_link(conn, pathreal, &sbuf); + if (!ms_dfs_link) { + DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n", + pathreal,strerror(errno))); + TALLOC_FREE(pathreal); + TALLOC_FREE(fname); + continue; + } + } - if (lp_dos_filetime_resolution(SNUM(conn))) { - dos_filetime_timespec(&create_date_ts); - dos_filetime_timespec(&mdate_ts); - dos_filetime_timespec(&adate_ts); - dos_filetime_timespec(&cdate_ts); - } + if (ms_dfs_link) { + mode = dos_mode_msdfs(conn,pathreal,&sbuf); + } else { + mode = dos_mode(conn,pathreal,&sbuf); + } + + if (!dir_check_ftype(conn,mode,dirtype)) { + DEBUG(5,("get_lanman2_dir_entry: [%s] attribs didn't match %x\n",fname,dirtype)); + TALLOC_FREE(pathreal); + TALLOC_FREE(fname); + continue; + } + + if (!(mode & aDIR)) { + file_size = get_file_size_stat(&sbuf); + } + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,NULL,&sbuf); + + mdate_ts = get_mtimespec(&sbuf); + adate_ts = get_atimespec(&sbuf); + create_date_ts = get_create_timespec(&sbuf, + lp_fake_dir_create_times(SNUM(conn))); + + if (ask_sharemode) { + struct timespec write_time_ts; + struct file_id fileid; + + fileid = vfs_file_id_from_sbuf(conn, &sbuf); + get_file_infos(fileid, NULL, &write_time_ts); + if (!null_timespec(write_time_ts)) { + mdate_ts = write_time_ts; + } + } + + if (lp_dos_filetime_resolution(SNUM(conn))) { + dos_filetime_timespec(&create_date_ts); + dos_filetime_timespec(&mdate_ts); + dos_filetime_timespec(&adate_ts); + } + + create_date = convert_timespec_to_time_t(create_date_ts); + mdate = convert_timespec_to_time_t(mdate_ts); + adate = convert_timespec_to_time_t(adate_ts); + + DEBUG(5,("get_lanman2_dir_entry: found %s fname=%s\n", + pathreal,fname)); + + found = True; - create_date = convert_timespec_to_time_t(create_date_ts); - mdate = convert_timespec_to_time_t(mdate_ts); - adate = convert_timespec_to_time_t(adate_ts); - c_date = convert_timespec_to_time_t(cdate_ts); + dptr_DirCacheAdd(conn->dirptr, dname, curr_dirpos); + } - /* align the record */ - off = PTR_DIFF(pdata, base_data); - pad = (off + (align-1)) & ~(align-1); - pad -= off; - off += pad; - /* initialize padding to 0 */ - if (pad) { - memset(pdata, 0, pad); + if (!found) + TALLOC_FREE(fname); } - space_remaining -= pad; - pdata += pad; p = pdata; last_entry_ptr = p; - pad = 0; - off = 0; - switch (info_level) { - case SMB_FIND_INFO_STANDARD: - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_INFO_STANDARD\n")); - if(requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - srv_put_dos_date2(p,0,create_date); - srv_put_dos_date2(p,4,adate); - srv_put_dos_date2(p,8,mdate); - SIVAL(p,12,(uint32)file_size); - SIVAL(p,16,(uint32)allocation_size); - SSVAL(p,20,mode); - p += 23; - nameptr = p; - if (flags2 & FLAGS2_UNICODE_STRINGS) { - p += ucs2_align(base_data, p, 0); - } - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE); - if (flags2 & FLAGS2_UNICODE_STRINGS) { - if (len > 2) { - SCVAL(nameptr, -1, len - 2); - } else { - SCVAL(nameptr, -1, 0); + case SMB_FIND_INFO_STANDARD: + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_INFO_STANDARD\n")); + if(requires_resume_key) { + SIVAL(p,0,reskey); + p += 4; } - } else { - if (len > 1) { - SCVAL(nameptr, -1, len - 1); + srv_put_dos_date2(p,0,create_date); + srv_put_dos_date2(p,4,adate); + srv_put_dos_date2(p,8,mdate); + SIVAL(p,12,(uint32)file_size); + SIVAL(p,16,(uint32)allocation_size); + SSVAL(p,20,mode); + p += 23; + nameptr = p; + if (flags2 & FLAGS2_UNICODE_STRINGS) { + p += ucs2_align(base_data, p, 0); + } + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE); + if (flags2 & FLAGS2_UNICODE_STRINGS) { + if (len > 2) { + SCVAL(nameptr, -1, len - 2); + } else { + SCVAL(nameptr, -1, 0); + } } else { - SCVAL(nameptr, -1, 0); + if (len > 1) { + SCVAL(nameptr, -1, len - 1); + } else { + SCVAL(nameptr, -1, 0); + } } - } - p += len; - break; + p += len; + break; - case SMB_FIND_EA_SIZE: - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_SIZE\n")); - if (requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - srv_put_dos_date2(p,0,create_date); - srv_put_dos_date2(p,4,adate); - srv_put_dos_date2(p,8,mdate); - SIVAL(p,12,(uint32)file_size); - SIVAL(p,16,(uint32)allocation_size); - SSVAL(p,20,mode); - { - unsigned int ea_size = estimate_ea_size(conn, NULL, - smb_fname->base_name); - SIVAL(p,22,ea_size); /* Extended attributes */ - } - p += 27; - nameptr = p - 1; - len = srvstr_push(base_data, flags2, - p, fname, PTR_DIFF(end_data, p), - STR_TERMINATE | STR_NOALIGN); - if (flags2 & FLAGS2_UNICODE_STRINGS) { - if (len > 2) { - len -= 2; - } else { - len = 0; + case SMB_FIND_EA_SIZE: + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_SIZE\n")); + if(requires_resume_key) { + SIVAL(p,0,reskey); + p += 4; } - } else { - if (len > 1) { - len -= 1; + srv_put_dos_date2(p,0,create_date); + srv_put_dos_date2(p,4,adate); + srv_put_dos_date2(p,8,mdate); + SIVAL(p,12,(uint32)file_size); + SIVAL(p,16,(uint32)allocation_size); + SSVAL(p,20,mode); + { + unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal); + SIVAL(p,22,ea_size); /* Extended attributes */ + } + p += 27; + nameptr = p - 1; + len = srvstr_push(base_data, flags2, + p, fname, PTR_DIFF(end_data, p), + STR_TERMINATE | STR_NOALIGN); + if (flags2 & FLAGS2_UNICODE_STRINGS) { + if (len > 2) { + len -= 2; + } else { + len = 0; + } } else { - len = 0; + if (len > 1) { + len -= 1; + } else { + len = 0; + } } - } - SCVAL(nameptr,0,len); - p += len; - SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */ - break; + SCVAL(nameptr,0,len); + p += len; + SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */ + break; - case SMB_FIND_EA_LIST: - { - struct ea_list *file_list = NULL; - size_t ea_len = 0; + case SMB_FIND_EA_LIST: + { + struct ea_list *file_list = NULL; + size_t ea_len = 0; - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n")); - if (!name_list) { - return false; - } - if (requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - srv_put_dos_date2(p,0,create_date); - srv_put_dos_date2(p,4,adate); - srv_put_dos_date2(p,8,mdate); - SIVAL(p,12,(uint32)file_size); - SIVAL(p,16,(uint32)allocation_size); - SSVAL(p,20,mode); - p += 22; /* p now points to the EA area. */ - - file_list = get_ea_list_from_file(ctx, conn, NULL, - smb_fname->base_name, - &ea_len); - name_list = ea_list_union(name_list, file_list, &ea_len); - - /* We need to determine if this entry will fit in the space available. */ - /* Max string size is 255 bytes. */ - if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) { - *out_of_space = true; - DEBUG(9,("smbd_marshall_dir_entry: out of space\n")); - return False; /* Not finished - just out of space */ - } - - /* Push the ea_data followed by the name. */ - p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list); - nameptr = p; - len = srvstr_push(base_data, flags2, - p + 1, fname, PTR_DIFF(end_data, p+1), - STR_TERMINATE | STR_NOALIGN); - if (flags2 & FLAGS2_UNICODE_STRINGS) { - if (len > 2) { - len -= 2; - } else { - len = 0; + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_LIST\n")); + if (!name_list) { + return False; } - } else { - if (len > 1) { - len -= 1; + if(requires_resume_key) { + SIVAL(p,0,reskey); + p += 4; + } + srv_put_dos_date2(p,0,create_date); + srv_put_dos_date2(p,4,adate); + srv_put_dos_date2(p,8,mdate); + SIVAL(p,12,(uint32)file_size); + SIVAL(p,16,(uint32)allocation_size); + SSVAL(p,20,mode); + p += 22; /* p now points to the EA area. */ + + file_list = get_ea_list_from_file(ctx, conn, NULL, pathreal, &ea_len); + name_list = ea_list_union(name_list, file_list, &ea_len); + + /* We need to determine if this entry will fit in the space available. */ + /* Max string size is 255 bytes. */ + if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) { + /* Move the dirptr back to prev_dirpos */ + dptr_SeekDir(conn->dirptr, prev_dirpos); + *out_of_space = True; + DEBUG(9,("get_lanman2_dir_entry: out of space\n")); + return False; /* Not finished - just out of space */ + } + + /* Push the ea_data followed by the name. */ + p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list); + nameptr = p; + len = srvstr_push(base_data, flags2, + p + 1, fname, PTR_DIFF(end_data, p+1), + STR_TERMINATE | STR_NOALIGN); + if (flags2 & FLAGS2_UNICODE_STRINGS) { + if (len > 2) { + len -= 2; + } else { + len = 0; + } } else { - len = 0; + if (len > 1) { + len -= 1; + } else { + len = 0; + } } + SCVAL(nameptr,0,len); + p += len + 1; + SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */ + break; } - SCVAL(nameptr,0,len); - p += len + 1; - SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */ - break; - } - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n")); - was_8_3 = mangle_is_8_3(fname, True, conn->params); - p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; - SOFF_T(p,0,file_size); p += 8; - SOFF_T(p,0,allocation_size); p += 8; - SIVAL(p,0,mode); p += 4; - q = p; p += 4; /* q is placeholder for name length. */ - { - unsigned int ea_size = estimate_ea_size(conn, NULL, - smb_fname->base_name); - SIVAL(p,0,ea_size); /* Extended attributes */ + case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n")); + was_8_3 = mangle_is_8_3(fname, True, conn->params); p += 4; - } - /* Clear the short name buffer. This is - * IMPORTANT as not doing so will trigger - * a Win2k client bug. JRA. - */ - if (!was_8_3 && check_mangled_names) { - char mangled_name[13]; /* mangled 8.3 name. */ - if (!name_to_8_3(fname,mangled_name,True, - conn->params)) { - /* Error - mangle failed ! */ - memset(mangled_name,'\0',12); + SIVAL(p,0,reskey); p += 4; + put_long_date_timespec(conn->ts_res, p,create_date_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,adate_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,mdate_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,mdate_ts); p += 8; + SOFF_T(p,0,file_size); p += 8; + SOFF_T(p,0,allocation_size); p += 8; + SIVAL(p,0,mode); p += 4; + q = p; p += 4; /* q is placeholder for name length. */ + { + unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal); + SIVAL(p,0,ea_size); /* Extended attributes */ + p += 4; } - mangled_name[12] = 0; - len = srvstr_push(base_data, flags2, - p+2, mangled_name, 24, - STR_UPPER|STR_UNICODE); - if (len < 24) { - memset(p + 2 + len,'\0',24 - len); + /* Clear the short name buffer. This is + * IMPORTANT as not doing so will trigger + * a Win2k client bug. JRA. + */ + if (!was_8_3 && check_mangled_names) { + if (!name_to_8_3(fname,mangled_name,True, + conn->params)) { + /* Error - mangle failed ! */ + memset(mangled_name,'\0',12); + } + mangled_name[12] = 0; + len = srvstr_push(base_data, flags2, + p+2, mangled_name, 24, + STR_UPPER|STR_UNICODE); + if (len < 24) { + memset(p + 2 + len,'\0',24 - len); + } + SSVAL(p, 0, len); + } else { + memset(p,'\0',26); } - SSVAL(p, 0, len); - } else { - memset(p,'\0',26); - } - p += 2 + 24; - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); - SIVAL(q,0,len); - p += len; - - len = PTR_DIFF(p, pdata); - pad = (len + (align-1)) & ~(align-1); - /* - * offset to the next entry, the caller - * will overwrite it for the last entry - * that's why we always include the padding - */ - SIVAL(pdata,0,pad); - /* - * set padding to zero - */ - if (do_pad) { - memset(p, 0, pad - len); - p = pdata + pad; - } else { + p += 2 + 24; + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE_ASCII); + SIVAL(q,0,len); + p += len; + SIVAL(p,0,0); /* Ensure any padding is null. */ + len = PTR_DIFF(p, pdata); + len = (len + 3) & ~3; + SIVAL(pdata,0,len); p = pdata + len; - } - break; + break; - case SMB_FIND_FILE_DIRECTORY_INFO: - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n")); - p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; - SOFF_T(p,0,file_size); p += 8; - SOFF_T(p,0,allocation_size); p += 8; - SIVAL(p,0,mode); p += 4; - len = srvstr_push(base_data, flags2, - p + 4, fname, PTR_DIFF(end_data, p+4), - STR_TERMINATE_ASCII); - SIVAL(p,0,len); - p += 4 + len; - - len = PTR_DIFF(p, pdata); - pad = (len + (align-1)) & ~(align-1); - /* - * offset to the next entry, the caller - * will overwrite it for the last entry - * that's why we always include the padding - */ - SIVAL(pdata,0,pad); - /* - * set padding to zero - */ - if (do_pad) { - memset(p, 0, pad - len); - p = pdata + pad; - } else { + case SMB_FIND_FILE_DIRECTORY_INFO: + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n")); + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date_timespec(conn->ts_res, p,create_date_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,adate_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,mdate_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,mdate_ts); p += 8; + SOFF_T(p,0,file_size); p += 8; + SOFF_T(p,0,allocation_size); p += 8; + SIVAL(p,0,mode); p += 4; + len = srvstr_push(base_data, flags2, + p + 4, fname, PTR_DIFF(end_data, p+4), + STR_TERMINATE_ASCII); + SIVAL(p,0,len); + p += 4 + len; + SIVAL(p,0,0); /* Ensure any padding is null. */ + len = PTR_DIFF(p, pdata); + len = (len + 3) & ~3; + SIVAL(pdata,0,len); p = pdata + len; - } - break; + break; - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n")); - p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; - SOFF_T(p,0,file_size); p += 8; - SOFF_T(p,0,allocation_size); p += 8; - SIVAL(p,0,mode); p += 4; - q = p; p += 4; /* q is placeholder for name length. */ - { - unsigned int ea_size = estimate_ea_size(conn, NULL, - smb_fname->base_name); - SIVAL(p,0,ea_size); /* Extended attributes */ - p +=4; - } - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); - SIVAL(q, 0, len); - p += len; - - len = PTR_DIFF(p, pdata); - pad = (len + (align-1)) & ~(align-1); - /* - * offset to the next entry, the caller - * will overwrite it for the last entry - * that's why we always include the padding - */ - SIVAL(pdata,0,pad); - /* - * set padding to zero - */ - if (do_pad) { - memset(p, 0, pad - len); - p = pdata + pad; - } else { + case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n")); + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date_timespec(conn->ts_res, p,create_date_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,adate_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,mdate_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,mdate_ts); p += 8; + SOFF_T(p,0,file_size); p += 8; + SOFF_T(p,0,allocation_size); p += 8; + SIVAL(p,0,mode); p += 4; + q = p; p += 4; /* q is placeholder for name length. */ + { + unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal); + SIVAL(p,0,ea_size); /* Extended attributes */ + p +=4; + } + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE_ASCII); + SIVAL(q, 0, len); + p += len; + + SIVAL(p,0,0); /* Ensure any padding is null. */ + len = PTR_DIFF(p, pdata); + len = (len + 3) & ~3; + SIVAL(pdata,0,len); p = pdata + len; - } - break; + break; - case SMB_FIND_FILE_NAMES_INFO: - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_NAMES_INFO\n")); - p += 4; - SIVAL(p,0,reskey); p += 4; - p += 4; - /* this must *not* be null terminated or w2k gets in a loop trying to set an - acl on a dir (tridge) */ - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); - SIVAL(p, -4, len); - p += len; - - len = PTR_DIFF(p, pdata); - pad = (len + (align-1)) & ~(align-1); - /* - * offset to the next entry, the caller - * will overwrite it for the last entry - * that's why we always include the padding - */ - SIVAL(pdata,0,pad); - /* - * set padding to zero - */ - if (do_pad) { - memset(p, 0, pad - len); - p = pdata + pad; - } else { + case SMB_FIND_FILE_NAMES_INFO: + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n")); + p += 4; + SIVAL(p,0,reskey); p += 4; + p += 4; + /* this must *not* be null terminated or w2k gets in a loop trying to set an + acl on a dir (tridge) */ + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE_ASCII); + SIVAL(p, -4, len); + p += len; + SIVAL(p,0,0); /* Ensure any padding is null. */ + len = PTR_DIFF(p, pdata); + len = (len + 3) & ~3; + SIVAL(pdata,0,len); p = pdata + len; - } - break; + break; - case SMB_FIND_ID_FULL_DIRECTORY_INFO: - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n")); - p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; - SOFF_T(p,0,file_size); p += 8; - SOFF_T(p,0,allocation_size); p += 8; - SIVAL(p,0,mode); p += 4; - q = p; p += 4; /* q is placeholder for name length. */ - { - unsigned int ea_size = estimate_ea_size(conn, NULL, - smb_fname->base_name); - SIVAL(p,0,ea_size); /* Extended attributes */ - p +=4; - } - SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */ - SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */ - SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */ - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); - SIVAL(q, 0, len); - p += len; - - len = PTR_DIFF(p, pdata); - pad = (len + (align-1)) & ~(align-1); - /* - * offset to the next entry, the caller - * will overwrite it for the last entry - * that's why we always include the padding - */ - SIVAL(pdata,0,pad); - /* - * set padding to zero - */ - if (do_pad) { - memset(p, 0, pad - len); - p = pdata + pad; - } else { + case SMB_FIND_ID_FULL_DIRECTORY_INFO: + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n")); + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date_timespec(conn->ts_res, p,create_date_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,adate_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,mdate_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,mdate_ts); p += 8; + SOFF_T(p,0,file_size); p += 8; + SOFF_T(p,0,allocation_size); p += 8; + SIVAL(p,0,mode); p += 4; + q = p; p += 4; /* q is placeholder for name length. */ + { + unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal); + SIVAL(p,0,ea_size); /* Extended attributes */ + p +=4; + } + SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */ + SIVAL(p,0,sbuf.st_ino); p += 4; /* FileIndexLow */ + SIVAL(p,0,sbuf.st_dev); p += 4; /* FileIndexHigh */ + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE_ASCII); + SIVAL(q, 0, len); + p += len; + SIVAL(p,0,0); /* Ensure any padding is null. */ + len = PTR_DIFF(p, pdata); + len = (len + 3) & ~3; + SIVAL(pdata,0,len); p = pdata + len; - } - break; + break; - case SMB_FIND_ID_BOTH_DIRECTORY_INFO: - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n")); - was_8_3 = mangle_is_8_3(fname, True, conn->params); - p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; - put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; - SOFF_T(p,0,file_size); p += 8; - SOFF_T(p,0,allocation_size); p += 8; - SIVAL(p,0,mode); p += 4; - q = p; p += 4; /* q is placeholder for name length */ - { - unsigned int ea_size = estimate_ea_size(conn, NULL, - smb_fname->base_name); - SIVAL(p,0,ea_size); /* Extended attributes */ - p +=4; - } - /* Clear the short name buffer. This is - * IMPORTANT as not doing so will trigger - * a Win2k client bug. JRA. - */ - if (!was_8_3 && check_mangled_names) { - char mangled_name[13]; /* mangled 8.3 name. */ - if (!name_to_8_3(fname,mangled_name,True, - conn->params)) { - /* Error - mangle failed ! */ - memset(mangled_name,'\0',12); + case SMB_FIND_ID_BOTH_DIRECTORY_INFO: + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n")); + was_8_3 = mangle_is_8_3(fname, True, conn->params); + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date_timespec(conn->ts_res, p,create_date_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,adate_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,mdate_ts); p += 8; + put_long_date_timespec(conn->ts_res, p,mdate_ts); p += 8; + SOFF_T(p,0,file_size); p += 8; + SOFF_T(p,0,allocation_size); p += 8; + SIVAL(p,0,mode); p += 4; + q = p; p += 4; /* q is placeholder for name length */ + { + unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal); + SIVAL(p,0,ea_size); /* Extended attributes */ + p +=4; } - mangled_name[12] = 0; - len = srvstr_push(base_data, flags2, - p+2, mangled_name, 24, - STR_UPPER|STR_UNICODE); - SSVAL(p, 0, len); - if (len < 24) { - memset(p + 2 + len,'\0',24 - len); + /* Clear the short name buffer. This is + * IMPORTANT as not doing so will trigger + * a Win2k client bug. JRA. + */ + if (!was_8_3 && check_mangled_names) { + if (!name_to_8_3(fname,mangled_name,True, + conn->params)) { + /* Error - mangle failed ! */ + memset(mangled_name,'\0',12); + } + mangled_name[12] = 0; + len = srvstr_push(base_data, flags2, + p+2, mangled_name, 24, + STR_UPPER|STR_UNICODE); + SSVAL(p, 0, len); + if (len < 24) { + memset(p + 2 + len,'\0',24 - len); + } + SSVAL(p, 0, len); + } else { + memset(p,'\0',26); } - SSVAL(p, 0, len); - } else { - memset(p,'\0',26); - } - p += 26; - SSVAL(p,0,0); p += 2; /* Reserved ? */ - SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */ - SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */ - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); - SIVAL(q,0,len); - p += len; - - len = PTR_DIFF(p, pdata); - pad = (len + (align-1)) & ~(align-1); - /* - * offset to the next entry, the caller - * will overwrite it for the last entry - * that's why we always include the padding - */ - SIVAL(pdata,0,pad); - /* - * set padding to zero - */ - if (do_pad) { - memset(p, 0, pad - len); - p = pdata + pad; - } else { + p += 26; + SSVAL(p,0,0); p += 2; /* Reserved ? */ + SIVAL(p,0,sbuf.st_ino); p += 4; /* FileIndexLow */ + SIVAL(p,0,sbuf.st_dev); p += 4; /* FileIndexHigh */ + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE_ASCII); + SIVAL(q,0,len); + p += len; + SIVAL(p,0,0); /* Ensure any padding is null. */ + len = PTR_DIFF(p, pdata); + len = (len + 3) & ~3; + SIVAL(pdata,0,len); p = pdata + len; - } - break; + break; - /* CIFS UNIX Extension. */ + /* CIFS UNIX Extension. */ - case SMB_FIND_FILE_UNIX: - case SMB_FIND_FILE_UNIX_INFO2: - p+= 4; - SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */ + case SMB_FIND_FILE_UNIX: + case SMB_FIND_FILE_UNIX_INFO2: + p+= 4; + SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */ - /* Begin of SMB_QUERY_FILE_UNIX_BASIC */ + /* Begin of SMB_QUERY_FILE_UNIX_BASIC */ - if (info_level == SMB_FIND_FILE_UNIX) { - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX\n")); - p = store_file_unix_basic(conn, p, - NULL, &smb_fname->st); - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE); - } else { - DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n")); - p = store_file_unix_basic_info2(conn, p, - NULL, &smb_fname->st); - nameptr = p; - p += 4; - len = srvstr_push(base_data, flags2, p, fname, - PTR_DIFF(end_data, p), 0); - SIVAL(nameptr, 0, len); - } + if (info_level == SMB_FIND_FILE_UNIX) { + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n")); + p = store_file_unix_basic(conn, p, + NULL, &sbuf); + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE); + } else { + DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n")); + p = store_file_unix_basic_info2(conn, p, + NULL, &sbuf); + nameptr = p; + p += 4; + len = srvstr_push(base_data, flags2, p, fname, + PTR_DIFF(end_data, p), 0); + SIVAL(nameptr, 0, len); + } - p += len; + p += len; + SIVAL(p,0,0); /* Ensure any padding is null. */ - len = PTR_DIFF(p, pdata); - pad = (len + (align-1)) & ~(align-1); - /* - * offset to the next entry, the caller - * will overwrite it for the last entry - * that's why we always include the padding - */ - SIVAL(pdata,0,pad); - /* - * set padding to zero - */ - if (do_pad) { - memset(p, 0, pad - len); - p = pdata + pad; - } else { + len = PTR_DIFF(p, pdata); + len = (len + 3) & ~3; + SIVAL(pdata,0,len); /* Offset from this structure to the beginning of the next one */ p = pdata + len; - } - /* End of SMB_QUERY_FILE_UNIX_BASIC */ + /* End of SMB_QUERY_FILE_UNIX_BASIC */ - break; + break; - default: - return false; + default: + TALLOC_FREE(fname); + return(False); } + TALLOC_FREE(fname); if (PTR_DIFF(p,pdata) > space_remaining) { - *out_of_space = true; - DEBUG(9,("smbd_marshall_dir_entry: out of space\n")); - return false; /* Not finished - just out of space */ + /* Move the dirptr back to prev_dirpos */ + dptr_SeekDir(conn->dirptr, prev_dirpos); + *out_of_space = True; + DEBUG(9,("get_lanman2_dir_entry: out of space\n")); + return False; /* Not finished - just out of space */ } /* Setup the last entry pointer, as an offset from base_data */ @@ -2030,147 +1859,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, /* Advance the data pointer to the next slot */ *ppdata = p; - return true; -} - -bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx, - connection_struct *conn, - struct dptr_struct *dirptr, - uint16 flags2, - const char *path_mask, - uint32 dirtype, - int info_level, - int requires_resume_key, - bool dont_descend, - bool ask_sharemode, - uint8_t align, - bool do_pad, - char **ppdata, - char *base_data, - char *end_data, - int space_remaining, - bool *out_of_space, - bool *got_exact_match, - int *_last_entry_off, - struct ea_list *name_list) -{ - const char *p; - const char *mask = NULL; - long prev_dirpos = 0; - uint32_t mode = 0; - char *fname = NULL; - struct smb_filename *smb_fname = NULL; - struct smbd_dirptr_lanman2_state state; - bool ok; - uint64_t last_entry_off = 0; - - ZERO_STRUCT(state); - state.conn = conn; - state.info_level = info_level; - state.check_mangled_names = lp_manglednames(conn->params); - state.has_wild = dptr_has_wild(dirptr); - state.got_exact_match = false; - - *out_of_space = false; - *got_exact_match = false; - - p = strrchr_m(path_mask,'/'); - if(p != NULL) { - if(p[1] == '\0') { - mask = "*.*"; - } else { - mask = p+1; - } - } else { - mask = path_mask; - } - - ok = smbd_dirptr_get_entry(ctx, - dirptr, - mask, - dirtype, - dont_descend, - ask_sharemode, - smbd_dirptr_lanman2_match_fn, - smbd_dirptr_lanman2_mode_fn, - &state, - &fname, - &smb_fname, - &mode, - &prev_dirpos); - if (!ok) { - return false; - } - - *got_exact_match = state.got_exact_match; - - ok = smbd_marshall_dir_entry(ctx, - conn, - flags2, - info_level, - name_list, - state.check_mangled_names, - requires_resume_key, - mode, - fname, - smb_fname, - space_remaining, - align, - do_pad, - base_data, - ppdata, - end_data, - out_of_space, - &last_entry_off); - TALLOC_FREE(fname); - TALLOC_FREE(smb_fname); - if (*out_of_space) { - dptr_SeekDir(dirptr, prev_dirpos); - return false; - } - if (!ok) { - return false; - } - - *_last_entry_off = last_entry_off; - return true; -} - -static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, - connection_struct *conn, - struct dptr_struct *dirptr, - uint16 flags2, - const char *path_mask, - uint32 dirtype, - int info_level, - bool requires_resume_key, - bool dont_descend, - bool ask_sharemode, - char **ppdata, - char *base_data, - char *end_data, - int space_remaining, - bool *out_of_space, - bool *got_exact_match, - int *last_entry_off, - struct ea_list *name_list) -{ - uint8_t align = 4; - const bool do_pad = true; - - if (info_level >= 1 && info_level <= 3) { - /* No alignment on earlier info levels. */ - align = 1; - } - - return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2, - path_mask, dirtype, info_level, - requires_resume_key, dont_descend, ask_sharemode, - align, do_pad, - ppdata, base_data, end_data, - space_remaining, - out_of_space, got_exact_match, - last_entry_off, name_list); + return(found); } /**************************************************************************** @@ -2188,7 +1877,6 @@ static void call_trans2findfirst(connection_struct *conn, maxentries then so be it. We assume that the redirector has enough room for the fixed number of parameter bytes it has requested. */ - struct smb_filename *smb_dname = NULL; char *params = *pparams; char *pdata = *ppdata; char *data_end; @@ -2211,16 +1899,15 @@ static void call_trans2findfirst(connection_struct *conn, bool out_of_space = False; int space_remaining; bool mask_contains_wcard = False; + SMB_STRUCT_STAT sbuf; struct ea_list *ea_list = NULL; NTSTATUS ntstatus = NT_STATUS_OK; bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); TALLOC_CTX *ctx = talloc_tos(); - struct dptr_struct *dirptr = NULL; - struct smbd_server_connection *sconn = smbd_server_conn; if (total_params < 13) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } dirtype = SVAL(params,0); @@ -2258,12 +1945,12 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", ask_sharemode = false; if (!lp_unix_extensions()) { reply_nterror(req, NT_STATUS_INVALID_LEVEL); - goto out; + return; } break; default: reply_nterror(req, NT_STATUS_INVALID_LEVEL); - goto out; + return; } srvstr_get_path_wcard(ctx, params, req->flags2, &directory, @@ -2271,29 +1958,35 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", STR_TERMINATE, &ntstatus, &mask_contains_wcard); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); - goto out; + return; } - ntstatus = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - directory, - (UCF_SAVE_LCOMP | - UCF_ALWAYS_ALLOW_WCARD_LCOMP), - &mask_contains_wcard, - &smb_dname); + ntstatus = resolve_dfspath_wcard(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + directory, + &directory, + &mask_contains_wcard); if (!NT_STATUS_IS_OK(ntstatus)) { if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - goto out; + return; } reply_nterror(req, ntstatus); - goto out; + return; } - mask = smb_dname->original_lcomp; + ntstatus = unix_convert(ctx, conn, directory, True, &directory, &mask, &sbuf); + if (!NT_STATUS_IS_OK(ntstatus)) { + reply_nterror(req, ntstatus); + return; + } - directory = smb_dname->base_name; + ntstatus = check_name(conn, directory); + if (!NT_STATUS_IS_OK(ntstatus)) { + reply_nterror(req, ntstatus); + return; + } p = strrchr_m(directory,'/'); if(p == NULL) { @@ -2302,14 +1995,14 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", mask = talloc_strdup(ctx,"*"); if (!mask) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + return; } mask_contains_wcard = True; } directory = talloc_strdup(talloc_tos(), "./"); if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + return; } } else { *p = 0; @@ -2322,7 +2015,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", if (total_data < 4) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } ea_size = IVAL(pdata,0); @@ -2330,19 +2023,19 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) )); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } if (!lp_ea_support(SNUM(conn))) { - reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); - goto out; + reply_doserror(req, ERRDOS, ERReasnotsupported); + return; } /* Pull out the list of names. */ ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4); if (!ea_list) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } } @@ -2350,7 +2043,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN); if(*ppdata == NULL ) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + return; } pdata = *ppdata; data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1; @@ -2359,7 +2052,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd *pparams = (char *)SMB_REALLOC(*pparams, 10); if (*pparams == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + return; } params = *pparams; @@ -2374,25 +2067,24 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd mask, mask_contains_wcard, dirtype, - &dirptr); + &conn->dirptr); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); - goto out; + return; } - dptr_num = dptr_dnum(dirptr); + dptr_num = dptr_dnum(conn->dirptr); DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype)); /* Initialize per TRANS2_FIND_FIRST operation data */ - dptr_init_search_op(dirptr); + dptr_init_search_op(conn->dirptr); /* We don't need to check for VOL here as this is returned by a different TRANS2 call. */ - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", - directory,lp_dontdescend(SNUM(conn)))); - if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn)))); + if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) dont_descend = True; p = pdata; @@ -2410,7 +2102,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } else { finished = !get_lanman2_dir_entry(ctx, conn, - dirptr, req->flags2, mask,dirtype,info_level, requires_resume_key,dont_descend, @@ -2449,7 +2140,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Check if we can close the dirptr */ if(close_after_first || (finished && close_if_end)) { DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num)); - dptr_close(sconn, &dptr_num); + dptr_close(&dptr_num); } /* @@ -2460,14 +2151,14 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd */ if(numentries == 0) { - dptr_close(sconn, &dptr_num); - if (get_Protocol() < PROTOCOL_NT1) { - reply_force_doserror(req, ERRDOS, ERRnofiles); - goto out; + dptr_close(&dptr_num); + if (Protocol < PROTOCOL_NT1) { + reply_doserror(req, ERRDOS, ERRnofiles); + return; } else { reply_botherror(req, NT_STATUS_NO_SUCH_FILE, ERRDOS, ERRbadfile); - goto out; + return; } } @@ -2483,8 +2174,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata), max_data_bytes); - if ((! *directory) && dptr_path(sconn, dptr_num)) { - directory = talloc_strdup(talloc_tos(),dptr_path(sconn, dptr_num)); + if ((! *directory) && dptr_path(dptr_num)) { + directory = talloc_strdup(talloc_tos(),dptr_path(dptr_num)); if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); } @@ -2506,8 +2197,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd char mangled_name[13]; name_to_8_3(mask, mangled_name, True, conn->params); } - out: - TALLOC_FREE(smb_dname); + return; } @@ -2554,8 +2244,6 @@ static void call_trans2findnext(connection_struct *conn, NTSTATUS ntstatus = NT_STATUS_OK; bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); TALLOC_CTX *ctx = talloc_tos(); - struct dptr_struct *dirptr; - struct smbd_server_connection *sconn = smbd_server_conn; if (total_params < 13) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -2649,7 +2337,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } if (!lp_ea_support(SNUM(conn))) { - reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); + reply_doserror(req, ERRDOS, ERReasnotsupported); return; } @@ -2681,39 +2369,39 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd params = *pparams; /* Check that the dptr is valid */ - if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) { - reply_nterror(req, STATUS_NO_MORE_FILES); + if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) { + reply_doserror(req, ERRDOS, ERRnofiles); return; } - directory = dptr_path(sconn, dptr_num); + string_set(&conn->dirpath,dptr_path(dptr_num)); /* Get the wildcard mask from the dptr */ - if((p = dptr_wcard(sconn, dptr_num))== NULL) { + if((p = dptr_wcard(dptr_num))== NULL) { DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num)); - reply_nterror(req, STATUS_NO_MORE_FILES); + reply_doserror(req, ERRDOS, ERRnofiles); return; } mask = p; + directory = conn->dirpath; /* Get the attr mask from the dptr */ - dirtype = dptr_attr(sconn, dptr_num); + dirtype = dptr_attr(dptr_num); DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n", dptr_num, mask, dirtype, - (long)dirptr, - dptr_TellDir(dirptr))); + (long)conn->dirptr, + dptr_TellDir(conn->dirptr))); /* Initialize per TRANS2_FIND_NEXT operation data */ - dptr_init_search_op(dirptr); + dptr_init_search_op(conn->dirptr); /* We don't need to check for VOL here as this is returned by a different TRANS2 call. */ - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", - directory,lp_dontdescend(SNUM(conn)))); - if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn)))); + if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) dont_descend = True; p = pdata; @@ -2755,7 +2443,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd * should already be at the correct place. */ - finished = !dptr_SearchDir(dirptr, resume_name, ¤t_pos, &st); + finished = !dptr_SearchDir(conn->dirptr, resume_name, ¤t_pos, &st); } /* end if resume_name && !continue_bit */ for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) { @@ -2769,7 +2457,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } else { finished = !get_lanman2_dir_entry(ctx, conn, - dirptr, req->flags2, mask,dirtype,info_level, requires_resume_key,dont_descend, @@ -2806,7 +2493,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Check if we can close the dirptr */ if(close_after_request || (finished && close_if_end)) { DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num)); - dptr_close(sconn, &dptr_num); /* This frees up the saved mask */ + dptr_close(&dptr_num); /* This frees up the saved mask */ } /* Set up the return parameter block */ @@ -2862,48 +2549,67 @@ static void samba_extended_info_version(struct smb_extended_info *extended_info) "%s", samba_version_string()); } -NTSTATUS smbd_do_qfsinfo(connection_struct *conn, - TALLOC_CTX *mem_ctx, - uint16_t info_level, - uint16_t flags2, - unsigned int max_data_bytes, - char **ppdata, - int *ret_data_len) +/**************************************************************************** + Reply to a TRANS2_QFSINFO (query filesystem info). +****************************************************************************/ + +static void call_trans2qfsinfo(connection_struct *conn, + struct smb_request *req, + char **pparams, int total_params, + char **ppdata, int total_data, + unsigned int max_data_bytes) { char *pdata, *end_data; - int data_len = 0, len; + char *params = *pparams; + uint16 info_level; + int data_len, len; + SMB_STRUCT_STAT st; const char *vname = volume_label(SNUM(conn)); int snum = SNUM(conn); char *fstype = lp_fstype(SNUM(conn)); uint32 additional_flags = 0; - struct smb_filename smb_fname_dot; - SMB_STRUCT_STAT st; + + if (total_params < 2) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + info_level = SVAL(params,0); if (IS_IPC(conn)) { if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { - DEBUG(0,("smbd_do_qfsinfo: not an allowed " + DEBUG(0,("call_trans2qfsinfo: not an allowed " "info level (0x%x) on IPC$.\n", (unsigned int)info_level)); - return NT_STATUS_ACCESS_DENIED; + reply_nterror(req, NT_STATUS_ACCESS_DENIED); + return; } } - DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level)); + if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) { + if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { + DEBUG(0,("call_trans2qfsinfo: encryption required " + "and info level 0x%x sent.\n", + (unsigned int)info_level)); + exit_server_cleanly("encryption required " + "on connection"); + return; + } + } - ZERO_STRUCT(smb_fname_dot); - smb_fname_dot.base_name = discard_const_p(char, "."); + DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); - if(SMB_VFS_STAT(conn, &smb_fname_dot) != 0) { - DEBUG(2,("stat of . failed (%s)\n", strerror(errno))); - return map_nt_error_from_unix(errno); + if(SMB_VFS_STAT(conn,".",&st)!=0) { + DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); + reply_doserror(req, ERRSRV, ERRinvdevice); + return; } - st = smb_fname_dot.st; - *ppdata = (char *)SMB_REALLOC( *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN); - if (*ppdata == NULL) { - return NT_STATUS_NO_MEMORY; + if (*ppdata == NULL ) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; } pdata = *ppdata; @@ -2916,7 +2622,8 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn, uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; data_len = 18; if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) { - return map_nt_error_from_unix(errno); + reply_unixerror(req, ERRHRD, ERRgeneral); + return; } block_size = lp_block_size(snum); @@ -2935,11 +2642,11 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn, bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \ -cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit, + DEBUG(5,("call_trans2qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \ +cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit, (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); - SIVAL(pdata,l1_idFileSystem,st.st_ex_dev); + SIVAL(pdata,l1_idFileSystem,st.st_dev); SIVAL(pdata,l1_cSectorUnit,sectors_per_unit); SIVAL(pdata,l1_cUnit,dsize); SIVAL(pdata,l1_cUnitAvail,dfree); @@ -2961,15 +2668,14 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u * the pushed string. The change here was adding the STR_TERMINATE. JRA. */ len = srvstr_push( - pdata, flags2, + pdata, req->flags2, pdata+l2_vol_szVolLabel, vname, PTR_DIFF(end_data, pdata+l2_vol_szVolLabel), STR_NOALIGN|STR_TERMINATE); SCVAL(pdata,l2_vol_cch,len); data_len = l2_vol_szVolLabel + len; - DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %d, name = %s\n", - (unsigned)convert_timespec_to_time_t(st.st_ex_ctime), - len, vname)); + DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", + (unsigned)st.st_ctime, len, vname)); break; case SMB_QUERY_FS_ATTRIBUTE_INFO: @@ -2997,7 +2703,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u SIVAL(pdata,4,255); /* Max filename component length */ /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it and will think we can't do long filenames */ - len = srvstr_push(pdata, flags2, pdata+12, fstype, + len = srvstr_push(pdata, req->flags2, pdata+12, fstype, PTR_DIFF(end_data, pdata+12), STR_UNICODE); SIVAL(pdata,8,len); @@ -3006,7 +2712,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u case SMB_QUERY_FS_LABEL_INFO: case SMB_FS_LABEL_INFORMATION: - len = srvstr_push(pdata, flags2, pdata+4, vname, + len = srvstr_push(pdata, req->flags2, pdata+4, vname, PTR_DIFF(end_data, pdata+4), 0); data_len = 4 + len; SIVAL(pdata,0,len); @@ -3023,13 +2729,13 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u (str_checksum(get_local_machine_name())<<16)); /* Max label len is 32 characters. */ - len = srvstr_push(pdata, flags2, pdata+18, vname, + len = srvstr_push(pdata, req->flags2, pdata+18, vname, PTR_DIFF(end_data, pdata+18), STR_UNICODE); SIVAL(pdata,12,len); data_len = 18+len; - DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", + DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", (int)strlen(vname),vname, lp_servicename(snum))); break; @@ -3039,7 +2745,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; data_len = 24; if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) { - return map_nt_error_from_unix(errno); + reply_unixerror(req, ERRHRD, ERRgeneral); + return; } block_size = lp_block_size(snum); if (bsize < block_size) { @@ -3056,7 +2763,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u } bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \ + DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); SBIG_UINT(pdata,0,dsize); @@ -3071,7 +2778,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; data_len = 32; if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) { - return map_nt_error_from_unix(errno); + reply_unixerror(req, ERRHRD, ERRgeneral); + return; } block_size = lp_block_size(snum); if (bsize < block_size) { @@ -3088,7 +2796,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned } bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \ + DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */ @@ -3133,50 +2841,51 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned */ files_struct fsp; SMB_NTQUOTA_STRUCT quotas; - + ZERO_STRUCT(fsp); ZERO_STRUCT(quotas); - + fsp.conn = conn; fsp.fnum = -1; - + /* access check */ - if (conn->server_info->utok.uid != sec_initial_uid()) { + if (conn->server_info->utok.uid != 0) { DEBUG(0,("set_user_quota: access_denied " "service [%s] user [%s]\n", lp_servicename(SNUM(conn)), conn->server_info->unix_name)); - return NT_STATUS_ACCESS_DENIED; + reply_doserror(req, ERRDOS, ERRnoaccess); + return; } - + if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - return map_nt_error_from_unix(errno); + reply_doserror(req, ERRSRV, ERRerror); + return; } data_len = 48; - DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n", - lp_servicename(SNUM(conn)))); - + DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",lp_servicename(SNUM(conn)))); + /* Unknown1 24 NULL bytes*/ SBIG_UINT(pdata,0,(uint64_t)0); SBIG_UINT(pdata,8,(uint64_t)0); SBIG_UINT(pdata,16,(uint64_t)0); - + /* Default Soft Quota 8 bytes */ SBIG_UINT(pdata,24,quotas.softlim); /* Default Hard Quota 8 bytes */ SBIG_UINT(pdata,32,quotas.hardlim); - + /* Quota flag 2 bytes */ SSVAL(pdata,40,quotas.qflags); - + /* Unknown3 6 NULL bytes */ SSVAL(pdata,42,0); SIVAL(pdata,44,0); - + break; } #endif /* HAVE_SYS_QUOTAS */ @@ -3203,12 +2912,13 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned case SMB_QUERY_CIFS_UNIX_INFO: { bool large_write = lp_min_receive_file_size() && - !srv_is_signing_active(smbd_server_conn); - bool large_read = !srv_is_signing_active(smbd_server_conn); + !srv_is_signing_active(); + bool large_read = !srv_is_signing_active(); int encrypt_caps = 0; if (!lp_unix_extensions()) { - return NT_STATUS_INVALID_LEVEL; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } switch (conn->encrypt_level) { @@ -3253,7 +2963,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned vfs_statvfs_struct svfs; if (!lp_unix_extensions()) { - return NT_STATUS_INVALID_LEVEL; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } rc = SMB_VFS_STATVFS(conn, ".", &svfs); @@ -3268,14 +2979,16 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned SBIG_UINT(pdata,32,svfs.TotalFileNodes); SBIG_UINT(pdata,40,svfs.FreeFileNodes); SBIG_UINT(pdata,48,svfs.FsIdentifier); - DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n")); + DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n")); #ifdef EOPNOTSUPP } else if (rc == EOPNOTSUPP) { - return NT_STATUS_INVALID_LEVEL; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; #endif /* EOPNOTSUPP */ } else { DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - return NT_STATUS_DOS(ERRSRV, ERRerror); + reply_doserror(req, ERRSRV, ERRerror); + return; } break; } @@ -3287,11 +3000,13 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int i; if (!lp_unix_extensions()) { - return NT_STATUS_INVALID_LEVEL; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } if (max_data_bytes < 40) { - return NT_STATUS_BUFFER_TOO_SMALL; + reply_nterror(req, NT_STATUS_BUFFER_TOO_SMALL); + return; } /* We ARE guest if global_sid_Builtin_Guests is @@ -3405,59 +3120,12 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned } /* drop through */ default: - return NT_STATUS_INVALID_LEVEL; - } - - *ret_data_len = data_len; - return NT_STATUS_OK; -} - -/**************************************************************************** - Reply to a TRANS2_QFSINFO (query filesystem info). -****************************************************************************/ - -static void call_trans2qfsinfo(connection_struct *conn, - struct smb_request *req, - char **pparams, int total_params, - char **ppdata, int total_data, - unsigned int max_data_bytes) -{ - char *params = *pparams; - uint16_t info_level; - int data_len = 0; - NTSTATUS status; - - if (total_params < 2) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - info_level = SVAL(params,0); - - if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) { - if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { - DEBUG(0,("call_trans2qfsinfo: encryption required " - "and info level 0x%x sent.\n", - (unsigned int)info_level)); - exit_server_cleanly("encryption required " - "on connection"); + reply_nterror(req, NT_STATUS_INVALID_LEVEL); return; - } } - DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); - - status = smbd_do_qfsinfo(conn, req, - info_level, - req->flags2, - max_data_bytes, - ppdata, &data_len); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - send_trans2_replies(conn, req, params, 0, *ppdata, data_len, + send_trans2_replies(conn, req, params, 0, pdata, data_len, max_data_bytes); DEBUG( 4, ( "%s info_level = %d\n", @@ -3624,16 +3292,16 @@ cap_low = 0x%x, cap_high = 0x%x\n", { files_struct *fsp = NULL; SMB_NTQUOTA_STRUCT quotas; - + ZERO_STRUCT(quotas); /* access check */ - if ((conn->server_info->utok.uid != sec_initial_uid()) + if ((conn->server_info->utok.uid != 0) ||!CAN_WRITE(conn)) { DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", lp_servicename(SNUM(conn)), conn->server_info->unix_name)); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRSRV, ERRaccess); return; } @@ -3659,9 +3327,9 @@ cap_low = 0x%x, cap_high = 0x%x\n", NT_STATUS_INVALID_PARAMETER); return; } - + /* unknown_1 24 NULL bytes in pdata*/ - + /* the soft quotas 8 bytes (uint64_t)*/ quotas.softlim = (uint64_t)IVAL(pdata,24); #ifdef LARGE_SMB_OFF_T @@ -3677,7 +3345,7 @@ cap_low = 0x%x, cap_high = 0x%x\n", return; } #endif /* LARGE_SMB_OFF_T */ - + /* the hard quotas 8 bytes (uint64_t)*/ quotas.hardlim = (uint64_t)IVAL(pdata,32); #ifdef LARGE_SMB_OFF_T @@ -3693,19 +3361,19 @@ cap_low = 0x%x, cap_high = 0x%x\n", return; } #endif /* LARGE_SMB_OFF_T */ - + /* quota_flags 2 bytes **/ quotas.qflags = SVAL(pdata,40); - + /* unknown_2 6 NULL bytes follow*/ - + /* now set the quotas */ if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - reply_nterror(req, map_nt_error_from_unix(errno)); + reply_doserror(req, ERRSRV, ERRerror); return; } - + break; } default: @@ -3785,7 +3453,7 @@ static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_ switch (tagtype) { case SMB_ACL_USER_OBJ: SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ); - own_grp = (unsigned int)pst->st_ex_uid; + own_grp = (unsigned int)pst->st_uid; SIVAL(pdata,2,own_grp); SIVAL(pdata,6,0); break; @@ -3805,7 +3473,7 @@ static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_ } case SMB_ACL_GROUP_OBJ: SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ); - own_grp = (unsigned int)pst->st_ex_gid; + own_grp = (unsigned int)pst->st_gid; SIVAL(pdata,2,own_grp); SIVAL(pdata,6,0); break; @@ -3854,7 +3522,7 @@ static char *store_file_unix_basic(connection_struct *conn, const SMB_STRUCT_STAT *psbuf) { DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n")); - DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode)); + DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_mode)); SOFF_T(pdata,0,get_file_size_stat(psbuf)); /* File size 64 Bit */ pdata += 8; @@ -3862,38 +3530,38 @@ static char *store_file_unix_basic(connection_struct *conn, SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */ pdata += 8; - put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, psbuf->st_ex_ctime); /* Change Time 64 Bit */ - put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, psbuf->st_ex_atime); /* Last access time 64 Bit */ - put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, psbuf->st_ex_mtime); /* Last modification time 64 Bit */ + put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata,get_ctimespec(psbuf)); /* Change Time 64 Bit */ + put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+8,get_atimespec(psbuf)); /* Last access time 64 Bit */ + put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16,get_mtimespec(psbuf)); /* Last modification time 64 Bit */ pdata += 24; - SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */ + SIVAL(pdata,0,psbuf->st_uid); /* user id for the owner */ SIVAL(pdata,4,0); pdata += 8; - SIVAL(pdata,0,psbuf->st_ex_gid); /* group id of owner */ + SIVAL(pdata,0,psbuf->st_gid); /* group id of owner */ SIVAL(pdata,4,0); pdata += 8; - SIVAL(pdata,0,unix_filetype(psbuf->st_ex_mode)); + SIVAL(pdata,0,unix_filetype(psbuf->st_mode)); pdata += 4; - SIVAL(pdata,0,unix_dev_major(psbuf->st_ex_rdev)); /* Major device number if type is device */ + SIVAL(pdata,0,unix_dev_major(psbuf->st_rdev)); /* Major device number if type is device */ SIVAL(pdata,4,0); pdata += 8; - SIVAL(pdata,0,unix_dev_minor(psbuf->st_ex_rdev)); /* Minor device number if type is device */ + SIVAL(pdata,0,unix_dev_minor(psbuf->st_rdev)); /* Minor device number if type is device */ SIVAL(pdata,4,0); pdata += 8; - SINO_T_VAL(pdata,0,(SMB_INO_T)psbuf->st_ex_ino); /* inode number */ + SINO_T_VAL(pdata,0,(SMB_INO_T)psbuf->st_ino); /* inode number */ pdata += 8; - - SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */ + + SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_mode)); /* Standard UNIX file permissions */ SIVAL(pdata,4,0); pdata += 8; - SIVAL(pdata,0,psbuf->st_ex_nlink); /* number of hard links */ + SIVAL(pdata,0,psbuf->st_nlink); /* number of hard links */ SIVAL(pdata,4,0); pdata += 8; @@ -3937,14 +3605,16 @@ static const struct {unsigned stat_fflag; unsigned smb_fflag;} static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf, uint32 *smb_fflags, uint32 *smb_fmask) { +#ifdef HAVE_STAT_ST_FLAGS int i; for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) { *smb_fmask |= info2_flags_map[i].smb_fflag; - if (psbuf->st_ex_flags & info2_flags_map[i].stat_fflag) { + if (psbuf->st_flags & info2_flags_map[i].stat_fflag) { *smb_fflags |= info2_flags_map[i].smb_fflag; } } +#endif /* HAVE_STAT_ST_FLAGS */ } static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf, @@ -3952,10 +3622,11 @@ static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf, const uint32 smb_fmask, int *stat_fflags) { +#ifdef HAVE_STAT_ST_FLAGS uint32 max_fmask = 0; int i; - *stat_fflags = psbuf->st_ex_flags; + *stat_fflags = psbuf->st_flags; /* For each flags requested in smb_fmask, check the state of the * corresponding flag in smb_fflags and set or clear the matching @@ -3981,6 +3652,9 @@ static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf, } return True; +#else + return False; +#endif /* HAVE_STAT_ST_FLAGS */ } @@ -3998,7 +3672,7 @@ static char *store_file_unix_basic_info2(connection_struct *conn, pdata = store_file_unix_basic(conn, pdata, fsp, psbuf); /* Create (birth) time 64 bit */ - put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, psbuf->st_ex_btime); + put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, get_create_timespec(psbuf, False)); pdata += 8; map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask); @@ -4137,55 +3811,277 @@ static void call_trans2qpipeinfo(connection_struct *conn, return; } -NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, - TALLOC_CTX *mem_ctx, - uint16_t info_level, - files_struct *fsp, - struct smb_filename *smb_fname, - bool delete_pending, - struct timespec write_time_ts, - bool ms_dfs_link, - struct ea_list *ea_list, - int lock_data_count, - char *lock_data, - uint16_t flags2, - unsigned int max_data_bytes, - char **ppdata, - unsigned int *pdata_size) +/**************************************************************************** + Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by + file name or file id). +****************************************************************************/ + +static void call_trans2qfilepathinfo(connection_struct *conn, + struct smb_request *req, + unsigned int tran_call, + char **pparams, int total_params, + char **ppdata, int total_data, + unsigned int max_data_bytes) { + char *params = *pparams; char *pdata = *ppdata; char *dstart, *dend; - unsigned int data_size; - struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts; - time_t create_time, mtime, atime, c_time; - SMB_STRUCT_STAT *psbuf = &smb_fname->st; - char *p; - char *base_name; - char *dos_fname; - int mode; + uint16 info_level; + int mode=0; int nlink; - NTSTATUS status; - uint64_t file_size = 0; - uint64_t pos = 0; - uint64_t allocation_size = 0; - uint64_t file_index = 0; - uint32_t access_mask = 0; + SMB_OFF_T file_size=0; + uint64_t allocation_size=0; + unsigned int data_size = 0; + unsigned int param_size = 2; + SMB_STRUCT_STAT sbuf; + char *dos_fname = NULL; + char *fname = NULL; + char *fullpathname; + char *base_name; + char *p; + SMB_OFF_T pos = 0; + bool delete_pending = False; + int len; + time_t create_time, mtime, atime; + struct timespec create_time_ts, mtime_ts, atime_ts; + struct timespec write_time_ts; + files_struct *fsp = NULL; + struct file_id fileid; + struct ea_list *ea_list = NULL; + char *lock_data = NULL; + bool ms_dfs_link = false; + TALLOC_CTX *ctx = talloc_tos(); + + if (!params) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + ZERO_STRUCT(sbuf); + ZERO_STRUCT(write_time_ts); + + if (tran_call == TRANSACT2_QFILEINFO) { + if (total_params < 4) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (IS_IPC(conn)) { + call_trans2qpipeinfo(conn, req, tran_call, + pparams, total_params, + ppdata, total_data, + max_data_bytes); + return; + } + + fsp = file_fsp(req, SVAL(params,0)); + info_level = SVAL(params,2); + + DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); + + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + + /* Initial check for valid fsp ptr. */ + if (!check_fsp_open(conn, req, fsp)) { + return; + } + + fname = talloc_strdup(talloc_tos(),fsp->fsp_name); + if (!fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + + if(fsp->fake_file_handle) { + /* + * This is actually for the QUOTA_FAKE_FILE --metze + */ + + /* We know this name is ok, it's already passed the checks. */ + + } else if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) { + /* + * This is actually a QFILEINFO on a directory + * handle (returned from an NT SMB). NT5.0 seems + * to do this call. JRA. + */ + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req,ERRDOS,ERRbadpath); + return; + } + } else if (SMB_VFS_STAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req, ERRDOS, ERRbadpath); + return; + } + + fileid = vfs_file_id_from_sbuf(conn, &sbuf); + get_file_infos(fileid, &delete_pending, &write_time_ts); + } else { + /* + * Original code - this is an open file. + */ + if (!check_fsp(conn, req, fsp)) { + return; + } + + if (SMB_VFS_FSTAT(fsp, &sbuf) != 0) { + DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno))); + reply_unixerror(req, ERRDOS, ERRbadfid); + return; + } + pos = fsp->fh->position_information; + fileid = vfs_file_id_from_sbuf(conn, &sbuf); + get_file_infos(fileid, &delete_pending, &write_time_ts); + } + + } else { + NTSTATUS status = NT_STATUS_OK; + + /* qpathinfo */ + if (total_params < 7) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + info_level = SVAL(params,0); + + DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); + + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + + srvstr_get_path(ctx, params, req->flags2, &fname, ¶ms[6], + total_params - 6, + STR_TERMINATE, &status); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + status = resolve_dfspath(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &fname); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + } + reply_nterror(req, status); + return; + } + + status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,nt_errstr(status))); + reply_nterror(req, status); + return; + } + + if ((conn->fs_capabilities & FILE_NAMED_STREAMS) + && is_ntfs_stream_name(fname)) { + char *base; + SMB_STRUCT_STAT bsbuf; + + status = split_ntfs_stream_name(talloc_tos(), fname, + &base, NULL); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("create_file_unixpath: " + "split_ntfs_stream_name failed: %s\n", + nt_errstr(status))); + reply_nterror(req, status); + return; + } + + SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */ + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn,base,&bsbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",base,strerror(errno))); + reply_unixerror(req,ERRDOS,ERRbadpath); + return; + } + } else { + if (SMB_VFS_STAT(conn,base,&bsbuf) != 0) { + DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",base,strerror(errno))); + reply_unixerror(req,ERRDOS,ERRbadpath); + return; + } + } + + fileid = vfs_file_id_from_sbuf(conn, &bsbuf); + get_file_infos(fileid, &delete_pending, NULL); + if (delete_pending) { + reply_nterror(req, NT_STATUS_DELETE_PENDING); + return; + } + } + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req, ERRDOS, ERRbadpath); + return; + } + + } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf) && (info_level != SMB_INFO_IS_NAME_VALID)) { + ms_dfs_link = check_msdfs_link(conn,fname,&sbuf); + + if (!ms_dfs_link) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req, ERRDOS, ERRbadpath); + return; + } + } + + fileid = vfs_file_id_from_sbuf(conn, &sbuf); + get_file_infos(fileid, &delete_pending, &write_time_ts); + if (delete_pending) { + reply_nterror(req, NT_STATUS_DELETE_PENDING); + return; + } + } if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - return NT_STATUS_INVALID_LEVEL; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } - DEBUG(5,("smbd_do_qfilepathinfo: %s (fnum = %d) level=%d max_data=%u\n", - smb_fname_str_dbg(smb_fname), fsp ? fsp->fnum : -1, - info_level, max_data_bytes)); + DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n", + fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data)); + + p = strrchr_m(fname,'/'); + if (!p) + base_name = fname; + else + base_name = p+1; if (ms_dfs_link) { - mode = dos_mode_msdfs(conn, smb_fname); + mode = dos_mode_msdfs(conn,fname,&sbuf); } else { - mode = dos_mode(conn, smb_fname); + mode = dos_mode(conn,fname,&sbuf); } - nlink = psbuf->st_ex_nlink; + nlink = sbuf.st_nlink; if (nlink && (mode&aDIR)) { nlink = 1; @@ -4195,105 +4091,142 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, nlink -= 1; } + fullpathname = fname; + if (!(mode & aDIR)) + file_size = get_file_size_stat(&sbuf); + + /* Pull out any data sent here before we realloc. */ + switch (info_level) { + case SMB_INFO_QUERY_EAS_FROM_LIST: + { + /* Pull any EA list from the data portion. */ + uint32 ea_size; + + if (total_data < 4) { + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; + } + ea_size = IVAL(pdata,0); + + if (total_data > 0 && ea_size != total_data) { + DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \ +total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) )); + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (!lp_ea_support(SNUM(conn))) { + reply_doserror(req, ERRDOS, + ERReasnotsupported); + return; + } + + /* Pull out the list of names. */ + ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4); + if (!ea_list) { + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; + } + break; + } + + case SMB_QUERY_POSIX_LOCK: + { + if (fsp == NULL || fsp->fh->fd == -1) { + reply_nterror(req, NT_STATUS_INVALID_HANDLE); + return; + } + + if (total_data != POSIX_LOCK_DATA_SIZE) { + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; + } + + /* Copy the lock range data. */ + lock_data = (char *)TALLOC_MEMDUP( + ctx, pdata, total_data); + if (!lock_data) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + } + default: + break; + } + + *pparams = (char *)SMB_REALLOC(*pparams,2); + if (*pparams == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + params = *pparams; + SSVAL(params,0,0); data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN; *ppdata = (char *)SMB_REALLOC(*ppdata, data_size); - if (*ppdata == NULL) { - return NT_STATUS_NO_MEMORY; + if (*ppdata == NULL ) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; } pdata = *ppdata; dstart = pdata; dend = dstart + data_size - 1; - if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) { - update_stat_ex_mtime(psbuf, write_time_ts); + create_time_ts = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn))); + mtime_ts = get_mtimespec(&sbuf); + atime_ts = get_atimespec(&sbuf); + + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf); + + if (!fsp) { + /* Do we have this path open ? */ + files_struct *fsp1; + fileid = vfs_file_id_from_sbuf(conn, &sbuf); + fsp1 = file_find_di_first(fileid); + if (fsp1 && fsp1->initial_allocation_size) { + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, &sbuf); + } } - create_time_ts = get_create_timespec(conn, fsp, smb_fname); - mtime_ts = psbuf->st_ex_mtime; - atime_ts = psbuf->st_ex_atime; - ctime_ts = get_change_timespec(conn, fsp, smb_fname); + if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) { + mtime_ts = write_time_ts; + } if (lp_dos_filetime_resolution(SNUM(conn))) { dos_filetime_timespec(&create_time_ts); dos_filetime_timespec(&mtime_ts); dos_filetime_timespec(&atime_ts); - dos_filetime_timespec(&ctime_ts); } create_time = convert_timespec_to_time_t(create_time_ts); mtime = convert_timespec_to_time_t(mtime_ts); atime = convert_timespec_to_time_t(atime_ts); - c_time = convert_timespec_to_time_t(ctime_ts); - - p = strrchr_m(smb_fname->base_name,'/'); - if (!p) - base_name = smb_fname->base_name; - else - base_name = p+1; /* NT expects the name to be in an exact form of the *full* filename. See the trans2 torture test */ if (ISDOT(base_name)) { - dos_fname = talloc_strdup(mem_ctx, "\\"); + dos_fname = talloc_strdup(ctx, "\\"); if (!dos_fname) { - return NT_STATUS_NO_MEMORY; + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; } } else { - dos_fname = talloc_asprintf(mem_ctx, + dos_fname = talloc_asprintf(ctx, "\\%s", - smb_fname->base_name); + fname); if (!dos_fname) { - return NT_STATUS_NO_MEMORY; - } - if (is_ntfs_stream_smb_fname(smb_fname)) { - dos_fname = talloc_asprintf(dos_fname, "%s", - smb_fname->stream_name); - if (!dos_fname) { - return NT_STATUS_NO_MEMORY; - } + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; } - string_replace(dos_fname, '/', '\\'); } - allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf); - - if (!fsp) { - /* Do we have this path open ? */ - files_struct *fsp1; - struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf); - fsp1 = file_find_di_first(fileid); - if (fsp1 && fsp1->initial_allocation_size) { - allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf); - } - } - - if (!(mode & aDIR)) { - file_size = get_file_size_stat(psbuf); - } - - if (fsp) { - pos = fsp->fh->position_information; - } - - if (fsp) { - access_mask = fsp->access_mask; - } else { - /* GENERIC_EXECUTE mapping from Windows */ - access_mask = 0x12019F; - } - - /* This should be an index number - looks like - dev/ino to me :-) - - I think this causes us to fail the IFSKIT - BasicFileInformationTest. -tpot */ - file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */ - file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */ - switch (info_level) { case SMB_INFO_STANDARD: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_STANDARD\n")); data_size = 22; srv_put_dos_date2(pdata,l1_fdateCreation,create_time); srv_put_dos_date2(pdata,l1_fdateLastAccess,atime); @@ -4305,10 +4238,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_INFO_QUERY_EA_SIZE: { - unsigned int ea_size = - estimate_ea_size(conn, fsp, - smb_fname->base_name); - DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n")); + unsigned int ea_size = estimate_ea_size(conn, fsp, fname); + DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n")); data_size = 26; srv_put_dos_date2(pdata,0,create_time); srv_put_dos_date2(pdata,4,atime); @@ -4321,13 +4252,14 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, } case SMB_INFO_IS_NAME_VALID: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n")); - if (fsp) { + DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_IS_NAME_VALID\n")); + if (tran_call == TRANSACT2_QFILEINFO) { /* os/2 needs this ? really ?*/ - return NT_STATUS_DOS(ERRDOS, ERRbadfunc); + reply_doserror(req, ERRDOS, ERRbadfunc); + return; } - /* This is only reached for qpathinfo */ data_size = 0; + param_size = 0; break; case SMB_INFO_QUERY_EAS_FROM_LIST: @@ -4335,12 +4267,9 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, size_t total_ea_len = 0; struct ea_list *ea_file_list = NULL; - DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n")); - ea_file_list = - get_ea_list_from_file(mem_ctx, conn, fsp, - smb_fname->base_name, - &total_ea_len); + ea_file_list = get_ea_list_from_file(ctx, conn, fsp, fname, &total_ea_len); ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len); if (!ea_list || (total_ea_len > data_size)) { @@ -4349,7 +4278,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, break; } - data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list); + data_size = fill_ea_buffer(ctx, pdata, data_size, conn, ea_list); break; } @@ -4358,50 +4287,16 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, /* We have data_size bytes to put EA's into. */ size_t total_ea_len = 0; - DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n")); - ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, - smb_fname->base_name, - &total_ea_len); + ea_list = get_ea_list_from_file(ctx, conn, fsp, fname, &total_ea_len); if (!ea_list || (total_ea_len > data_size)) { data_size = 4; SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */ break; } - data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list); - break; - } - - case 0xFF0F:/*SMB2_INFO_QUERY_ALL_EAS*/ - { - /* This is FileFullEaInformation - 0xF which maps to - * 1015 (decimal) in smbd_do_setfilepathinfo. */ - - /* We have data_size bytes to put EA's into. */ - size_t total_ea_len = 0; - struct ea_list *ea_file_list = NULL; - - DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n")); - - /*TODO: add filtering and index handling */ - - ea_file_list = - get_ea_list_from_file(mem_ctx, conn, fsp, - smb_fname->base_name, - &total_ea_len); - if (!ea_file_list) { - return NT_STATUS_NO_EAS_ON_FILE; - } - - status = fill_ea_chained_buffer(mem_ctx, - pdata, - data_size, - &data_size, - conn, ea_file_list); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + data_size = fill_ea_buffer(ctx, pdata, data_size, conn, ea_list); break; } @@ -4409,31 +4304,31 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_BASIC_INFO: if (info_level == SMB_QUERY_FILE_BASIC_INFO) { - DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n")); data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */ } else { - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n")); data_size = 40; SIVAL(pdata,36,0); } - put_long_date_timespec(conn->ts_res,pdata,create_time_ts); - put_long_date_timespec(conn->ts_res,pdata+8,atime_ts); - put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */ - put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */ + put_long_date_timespec(conn->ts_res, pdata,create_time_ts); + put_long_date_timespec(conn->ts_res, pdata+8,atime_ts); + put_long_date_timespec(conn->ts_res, pdata+16,mtime_ts); /* write time */ + put_long_date_timespec(conn->ts_res, pdata+24,mtime_ts); /* change time */ SIVAL(pdata,32,mode); DEBUG(5,("SMB_QFBI - ")); DEBUG(5,("create: %s ", ctime(&create_time))); DEBUG(5,("access: %s ", ctime(&atime))); DEBUG(5,("write: %s ", ctime(&mtime))); - DEBUG(5,("change: %s ", ctime(&c_time))); + DEBUG(5,("change: %s ", ctime(&mtime))); DEBUG(5,("mode: %x\n", mode)); break; case SMB_FILE_STANDARD_INFORMATION: case SMB_QUERY_FILE_STANDARD_INFO: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n")); data_size = 24; SOFF_T(pdata,0,allocation_size); SOFF_T(pdata,8,file_size); @@ -4446,9 +4341,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_FILE_EA_INFORMATION: case SMB_QUERY_FILE_EA_INFO: { - unsigned int ea_size = - estimate_ea_size(conn, fsp, smb_fname->base_name); - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n")); + unsigned int ea_size = estimate_ea_size(conn, fsp, fname); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_EA_INFORMATION\n")); data_size = 4; SIVAL(pdata,0,ea_size); break; @@ -4458,14 +4352,15 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_ALT_NAME_INFO: case SMB_FILE_ALTERNATE_NAME_INFORMATION: { - int len; char mangled_name[13]; - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n")); if (!name_to_8_3(base_name,mangled_name, True,conn->params)) { - return NT_STATUS_NO_MEMORY; + reply_nterror( + req, + NT_STATUS_NO_MEMORY); } - len = srvstr_push(dstart, flags2, + len = srvstr_push(dstart, req->flags2, pdata+4, mangled_name, PTR_DIFF(dend, pdata+4), STR_UNICODE); @@ -4475,31 +4370,28 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, } case SMB_QUERY_FILE_NAME_INFO: - { - int len; /* this must be *exactly* right for ACLs on mapped drives to work */ - len = srvstr_push(dstart, flags2, + len = srvstr_push(dstart, req->flags2, pdata+4, dos_fname, PTR_DIFF(dend, pdata+4), STR_UNICODE); - DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n")); data_size = 4 + len; SIVAL(pdata,0,len); break; - } case SMB_FILE_ALLOCATION_INFORMATION: case SMB_QUERY_FILE_ALLOCATION_INFO: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n")); data_size = 8; SOFF_T(pdata,0,allocation_size); break; case SMB_FILE_END_OF_FILE_INFORMATION: case SMB_QUERY_FILE_END_OF_FILEINFO: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n")); data_size = 8; SOFF_T(pdata,0,file_size); break; @@ -4507,14 +4399,12 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_ALL_INFO: case SMB_FILE_ALL_INFORMATION: { - int len; - unsigned int ea_size = - estimate_ea_size(conn, fsp, smb_fname->base_name); - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n")); - put_long_date_timespec(conn->ts_res,pdata,create_time_ts); - put_long_date_timespec(conn->ts_res,pdata+8,atime_ts); - put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */ - put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */ + unsigned int ea_size = estimate_ea_size(conn, fsp, fname); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALL_INFORMATION\n")); + put_long_date_timespec(conn->ts_res, pdata,create_time_ts); + put_long_date_timespec(conn->ts_res, pdata+8,atime_ts); + put_long_date_timespec(conn->ts_res, pdata+16,mtime_ts); /* write time */ + put_long_date_timespec(conn->ts_res, pdata+24,mtime_ts); /* change time */ SIVAL(pdata,32,mode); SIVAL(pdata,36,0); /* padding. */ pdata += 40; @@ -4527,44 +4417,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, pdata += 24; SIVAL(pdata,0,ea_size); pdata += 4; /* EA info */ - len = srvstr_push(dstart, flags2, - pdata+4, dos_fname, - PTR_DIFF(dend, pdata+4), - STR_UNICODE); - SIVAL(pdata,0,len); - pdata += 4 + len; - data_size = PTR_DIFF(pdata,(*ppdata)); - break; - } - - case 0xFF12:/*SMB2_FILE_ALL_INFORMATION*/ - { - int len; - unsigned int ea_size = - estimate_ea_size(conn, fsp, smb_fname->base_name); - DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n")); - put_long_date_timespec(conn->ts_res,pdata+0x00,create_time_ts); - put_long_date_timespec(conn->ts_res,pdata+0x08,atime_ts); - put_long_date_timespec(conn->ts_res,pdata+0x10,mtime_ts); /* write time */ - put_long_date_timespec(conn->ts_res,pdata+0x18,ctime_ts); /* change time */ - SIVAL(pdata, 0x20, mode); - SIVAL(pdata, 0x24, 0); /* padding. */ - SBVAL(pdata, 0x28, allocation_size); - SBVAL(pdata, 0x30, file_size); - SIVAL(pdata, 0x38, nlink); - SCVAL(pdata, 0x3C, delete_pending); - SCVAL(pdata, 0x3D, (mode&aDIR)?1:0); - SSVAL(pdata, 0x3E, 0); /* padding */ - SBVAL(pdata, 0x40, file_index); - SIVAL(pdata, 0x48, ea_size); - SIVAL(pdata, 0x4C, access_mask); - SBVAL(pdata, 0x50, pos); - SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */ - SIVAL(pdata, 0x5C, 0); /* No alignment needed. */ - - pdata += 0x60; - - len = srvstr_push(dstart, flags2, + len = srvstr_push(dstart, req->flags2, pdata+4, dos_fname, PTR_DIFF(dend, pdata+4), STR_UNICODE); @@ -4574,15 +4427,26 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, break; } case SMB_FILE_INTERNAL_INFORMATION: + /* This should be an index number - looks like + dev/ino to me :-) + + I think this causes us to fail the IFSKIT + BasicFileInformationTest. -tpot */ - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n")); - SBVAL(pdata, 0, file_index); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n")); + SIVAL(pdata,0,sbuf.st_ino); /* FileIndexLow */ + SIVAL(pdata,4,sbuf.st_dev); /* FileIndexHigh */ data_size = 8; break; case SMB_FILE_ACCESS_INFORMATION: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n")); - SIVAL(pdata, 0, access_mask); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n")); + if (fsp) { + SIVAL(pdata,0,fsp->access_mask); + } else { + /* GENERIC_EXECUTE mapping from Windows */ + SIVAL(pdata,0,0x12019F); + } data_size = 4; break; @@ -4591,32 +4455,32 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, { size_t byte_len; byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False); - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NAME_INFORMATION\n")); SIVAL(pdata,0,byte_len); data_size = 4 + byte_len; break; } case SMB_FILE_DISPOSITION_INFORMATION: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n")); data_size = 1; SCVAL(pdata,0,delete_pending); break; case SMB_FILE_POSITION_INFORMATION: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n")); data_size = 8; SOFF_T(pdata,0,pos); break; case SMB_FILE_MODE_INFORMATION: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_MODE_INFORMATION\n")); SIVAL(pdata,0,mode); data_size = 4; break; case SMB_FILE_ALIGNMENT_INFORMATION: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n")); SIVAL(pdata,0,0); /* No alignment needed. */ data_size = 4; break; @@ -4633,22 +4497,20 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_FILE_STREAM_INFORMATION: { unsigned int num_streams; struct stream_struct *streams; + NTSTATUS status; - DEBUG(10,("smbd_do_qfilepathinfo: " + DEBUG(10,("call_trans2qfilepathinfo: " "SMB_FILE_STREAM_INFORMATION\n")); - if (is_ntfs_stream_smb_fname(smb_fname)) { - return NT_STATUS_INVALID_PARAMETER; - } - status = SMB_VFS_STREAMINFO( - conn, fsp, smb_fname->base_name, talloc_tos(), + conn, fsp, fname, talloc_tos(), &num_streams, &streams); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("could not get stream info: %s\n", nt_errstr(status))); - return status; + reply_nterror(req, status); + return; } status = marshall_stream_info(num_streams, streams, @@ -4658,7 +4520,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("marshall_stream_info failed: %s\n", nt_errstr(status))); - return status; + reply_nterror(req, status); + return; } TALLOC_FREE(streams); @@ -4667,7 +4530,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, } case SMB_QUERY_COMPRESSION_INFO: case SMB_FILE_COMPRESSION_INFORMATION: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n")); SOFF_T(pdata,0,file_size); SIVAL(pdata,8,0); /* ??? */ SIVAL(pdata,12,0); /* ??? */ @@ -4675,11 +4538,11 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, break; case SMB_FILE_NETWORK_OPEN_INFORMATION: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n")); - put_long_date_timespec(conn->ts_res,pdata,create_time_ts); - put_long_date_timespec(conn->ts_res,pdata+8,atime_ts); - put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */ - put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */ + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n")); + put_long_date_timespec(conn->ts_res, pdata,create_time_ts); + put_long_date_timespec(conn->ts_res, pdata+8,atime_ts); + put_long_date_timespec(conn->ts_res, pdata+16,mtime_ts); /* write time */ + put_long_date_timespec(conn->ts_res, pdata+24,mtime_ts); /* change time */ SOFF_T(pdata,32,allocation_size); SOFF_T(pdata,40,file_size); SIVAL(pdata,48,mode); @@ -4688,7 +4551,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, break; case SMB_FILE_ATTRIBUTE_TAG_INFORMATION: - DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n")); SIVAL(pdata,0,mode); SIVAL(pdata,4,0); data_size = 8; @@ -4700,12 +4563,12 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_UNIX_BASIC: - pdata = store_file_unix_basic(conn, pdata, fsp, psbuf); + pdata = store_file_unix_basic(conn, pdata, fsp, &sbuf); data_size = PTR_DIFF(pdata,(*ppdata)); { int i; - DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC ")); + DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC ")); for (i=0; i<100; i++) DEBUG(4,("%d=%x, ",i, (*ppdata)[i])); @@ -4716,12 +4579,12 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_UNIX_INFO2: - pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf); + pdata = store_file_unix_basic_info2(conn, pdata, fsp, &sbuf); data_size = PTR_DIFF(pdata,(*ppdata)); { int i; - DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 ")); + DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 ")); for (i=0; i<100; i++) DEBUG(4,("%d=%x, ",i, (*ppdata)[i])); @@ -4732,29 +4595,33 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_FILE_UNIX_LINK: { - int len; - char *buffer = TALLOC_ARRAY(mem_ctx, char, PATH_MAX+1); + char *buffer = TALLOC_ARRAY(ctx, char, PATH_MAX+1); if (!buffer) { - return NT_STATUS_NO_MEMORY; + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; } - DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n")); + DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n")); #ifdef S_ISLNK - if(!S_ISLNK(psbuf->st_ex_mode)) { - return NT_STATUS_DOS(ERRSRV, ERRbadlink); + if(!S_ISLNK(sbuf.st_mode)) { + reply_unixerror(req, ERRSRV, + ERRbadlink); + return; } #else - return NT_STATUS_DOS(ERRDOS, ERRbadlink); + reply_unixerror(req, ERRDOS, ERRbadlink); + return; #endif - len = SMB_VFS_READLINK(conn, - smb_fname->base_name, - buffer, PATH_MAX); + len = SMB_VFS_READLINK(conn,fullpathname, + buffer, PATH_MAX); if (len == -1) { - return map_nt_error_from_unix(errno); + reply_unixerror(req, ERRDOS, + ERRnoaccess); + return; } buffer[len] = 0; - len = srvstr_push(dstart, flags2, + len = srvstr_push(dstart, req->flags2, pdata, buffer, PTR_DIFF(dend, pdata), STR_TERMINATE); @@ -4775,33 +4642,23 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, if (fsp && !fsp->is_directory && (fsp->fh->fd != -1)) { file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp); } else { - file_acl = - SMB_VFS_SYS_ACL_GET_FILE(conn, - smb_fname->base_name, - SMB_ACL_TYPE_ACCESS); + file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS); } if (file_acl == NULL && no_acl_syscall_error(errno)) { - DEBUG(5,("smbd_do_qfilepathinfo: ACLs " - "not implemented on " - "filesystem containing %s\n", - smb_fname->base_name)); - return NT_STATUS_NOT_IMPLEMENTED; + DEBUG(5,("call_trans2qfilepathinfo: ACLs not implemented on filesystem containing %s\n", + fname )); + reply_nterror( + req, + NT_STATUS_NOT_IMPLEMENTED); + return; } - if (S_ISDIR(psbuf->st_ex_mode)) { + if (S_ISDIR(sbuf.st_mode)) { if (fsp && fsp->is_directory) { - def_acl = - SMB_VFS_SYS_ACL_GET_FILE( - conn, - fsp->fsp_name->base_name, - SMB_ACL_TYPE_DEFAULT); + def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT); } else { - def_acl = - SMB_VFS_SYS_ACL_GET_FILE( - conn, - smb_fname->base_name, - SMB_ACL_TYPE_DEFAULT); + def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT); } def_acl = free_empty_sys_acl(conn, def_acl); } @@ -4810,7 +4667,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, num_def_acls = count_acl_entries(conn, def_acl); if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) { - DEBUG(5,("smbd_do_qfilepathinfo: data_size too small (%u) need %u\n", + DEBUG(5,("call_trans2qfilepathinfo: data_size too small (%u) need %u\n", data_size, (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) )); @@ -4820,29 +4677,37 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, if (def_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); } - return NT_STATUS_BUFFER_TOO_SMALL; + reply_nterror( + req, + NT_STATUS_BUFFER_TOO_SMALL); + return; } SSVAL(pdata,0,SMB_POSIX_ACL_VERSION); SSVAL(pdata,2,num_file_acls); SSVAL(pdata,4,num_def_acls); - if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, psbuf, file_acl)) { + if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, &sbuf, file_acl)) { if (file_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl); } if (def_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); } - return NT_STATUS_INTERNAL_ERROR; + reply_nterror( + req, NT_STATUS_INTERNAL_ERROR); + return; } - if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), psbuf, def_acl)) { + if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), &sbuf, def_acl)) { if (file_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl); } if (def_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); } - return NT_STATUS_INTERNAL_ERROR; + reply_nterror( + req, + NT_STATUS_INTERNAL_ERROR); + return; } if (file_acl) { @@ -4859,18 +4724,16 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case SMB_QUERY_POSIX_LOCK: { + NTSTATUS status = NT_STATUS_INVALID_LEVEL; uint64_t count; uint64_t offset; uint32 lock_pid; enum brl_type lock_type; - /* We need an open file with a real fd for this. */ - if (!fsp || fsp->is_directory || fsp->fh->fd == -1) { - return NT_STATUS_INVALID_LEVEL; - } - - if (lock_data_count != POSIX_LOCK_DATA_SIZE) { - return NT_STATUS_INVALID_PARAMETER; + if (total_data != POSIX_LOCK_DATA_SIZE) { + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; } switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) { @@ -4883,7 +4746,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, case POSIX_LOCK_TYPE_UNLOCK: default: /* There's no point in asking for an unlock... */ - return NT_STATUS_INVALID_PARAMETER; + reply_nterror( + req, + NT_STATUS_INVALID_PARAMETER); + return; } lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET); @@ -4928,394 +4794,15 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE); SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK); } else { - return status; - } - break; - } - - default: - return NT_STATUS_INVALID_LEVEL; - } - - *pdata_size = data_size; - return NT_STATUS_OK; -} - -/**************************************************************************** - Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by - file name or file id). -****************************************************************************/ - -static void call_trans2qfilepathinfo(connection_struct *conn, - struct smb_request *req, - unsigned int tran_call, - char **pparams, int total_params, - char **ppdata, int total_data, - unsigned int max_data_bytes) -{ - char *params = *pparams; - char *pdata = *ppdata; - uint16 info_level; - unsigned int data_size = 0; - unsigned int param_size = 2; - struct smb_filename *smb_fname = NULL; - bool delete_pending = False; - struct timespec write_time_ts; - files_struct *fsp = NULL; - struct file_id fileid; - struct ea_list *ea_list = NULL; - int lock_data_count = 0; - char *lock_data = NULL; - bool ms_dfs_link = false; - NTSTATUS status = NT_STATUS_OK; - - if (!params) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - ZERO_STRUCT(write_time_ts); - - if (tran_call == TRANSACT2_QFILEINFO) { - if (total_params < 4) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (IS_IPC(conn)) { - call_trans2qpipeinfo(conn, req, tran_call, - pparams, total_params, - ppdata, total_data, - max_data_bytes); - return; - } - - fsp = file_fsp(req, SVAL(params,0)); - info_level = SVAL(params,2); - - DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); - - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; - } - - /* Initial check for valid fsp ptr. */ - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - status = copy_smb_filename(talloc_tos(), fsp->fsp_name, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - if(fsp->fake_file_handle) { - /* - * This is actually for the QUOTA_FAKE_FILE --metze - */ - - /* We know this name is ok, it's already passed the checks. */ - - } else if(fsp->is_directory || fsp->fh->fd == -1) { - /* - * This is actually a QFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname)) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_nterror(req, - map_nt_error_from_unix(errno)); - return; - } - } else if (SMB_VFS_STAT(conn, smb_fname)) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_STAT of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_nterror(req, - map_nt_error_from_unix(errno)); - return; - } - - fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); - } else { - /* - * Original code - this is an open file. - */ - if (!check_fsp(conn, req, fsp)) { - return; - } - - if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { - DEBUG(3, ("fstat of fnum %d failed (%s)\n", - fsp->fnum, strerror(errno))); - reply_nterror(req, - map_nt_error_from_unix(errno)); - return; - } - fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); - } - - } else { - char *fname = NULL; - - /* qpathinfo */ - if (total_params < 7) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - info_level = SVAL(params,0); - - DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); - - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; - } - - srvstr_get_path(req, params, req->flags2, &fname, ¶ms[6], - total_params - 6, - STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - status = filename_convert(req, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - return; - } - reply_nterror(req, status); - return; - } - - /* If this is a stream, check if there is a delete_pending. */ - if ((conn->fs_capabilities & FILE_NAMED_STREAMS) - && is_ntfs_stream_smb_fname(smb_fname)) { - struct smb_filename *smb_fname_base = NULL; - - /* Create an smb_filename with stream_name == NULL. */ - status = - create_synthetic_smb_fname(talloc_tos(), - smb_fname->base_name, - NULL, NULL, - &smb_fname_base); - if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; } - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname_base), - strerror(errno))); - TALLOC_FREE(smb_fname_base); - reply_nterror(req, - map_nt_error_from_unix(errno)); - return; - } - } else { - if (SMB_VFS_STAT(conn, smb_fname_base) != 0) { - DEBUG(3,("call_trans2qfilepathinfo: " - "fileinfo of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname_base), - strerror(errno))); - TALLOC_FREE(smb_fname_base); - reply_nterror(req, - map_nt_error_from_unix(errno)); - return; - } - } - - fileid = vfs_file_id_from_sbuf(conn, - &smb_fname_base->st); - TALLOC_FREE(smb_fname_base); - get_file_infos(fileid, &delete_pending, NULL); - if (delete_pending) { - reply_nterror(req, NT_STATUS_DELETE_PENDING); - return; - } - } - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname)) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_LSTAT of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_nterror(req, - map_nt_error_from_unix(errno)); - return; - } - - } else if (!VALID_STAT(smb_fname->st) && - SMB_VFS_STAT(conn, smb_fname) && - (info_level != SMB_INFO_IS_NAME_VALID)) { - ms_dfs_link = check_msdfs_link(conn, - smb_fname->base_name, - &smb_fname->st); - - if (!ms_dfs_link) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_STAT of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_nterror(req, - map_nt_error_from_unix(errno)); - return; - } - } - - fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); - if (delete_pending) { - reply_nterror(req, NT_STATUS_DELETE_PENDING); - return; - } - } - - DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d " - "total_data=%d\n", smb_fname_str_dbg(smb_fname), - fsp ? fsp->fnum : -1, info_level,tran_call,total_data)); - - /* Pull out any data sent here before we realloc. */ - switch (info_level) { - case SMB_INFO_QUERY_EAS_FROM_LIST: - { - /* Pull any EA list from the data portion. */ - uint32 ea_size; - - if (total_data < 4) { - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } - ea_size = IVAL(pdata,0); - - if (total_data > 0 && ea_size != total_data) { - DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \ -total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) )); - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (!lp_ea_support(SNUM(conn))) { - reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); - return; - } - - /* Pull out the list of names. */ - ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4); - if (!ea_list) { - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } break; } - case SMB_QUERY_POSIX_LOCK: - { - if (fsp == NULL || fsp->fh->fd == -1) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); - return; - } - - if (total_data != POSIX_LOCK_DATA_SIZE) { - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } - - /* Copy the lock range data. */ - lock_data = (char *)TALLOC_MEMDUP( - req, pdata, total_data); - if (!lock_data) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - lock_data_count = total_data; - } default: - break; - } - - *pparams = (char *)SMB_REALLOC(*pparams,2); - if (*pparams == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - params = *pparams; - SSVAL(params,0,0); - - /* - * draft-leach-cifs-v1-spec-02.txt - * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path - * says: - * - * The requested information is placed in the Data portion of the - * transaction response. For the information levels greater than 0x100, - * the transaction response has 1 parameter word which should be - * ignored by the client. - * - * However Windows only follows this rule for the IS_NAME_VALID call. - */ - switch (info_level) { - case SMB_INFO_IS_NAME_VALID: - param_size = 0; - break; - } - - if ((info_level & 0xFF00) == 0xFF00) { - /* - * We use levels that start with 0xFF00 - * internally to represent SMB2 specific levels - */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; - } - - status = smbd_do_qfilepathinfo(conn, req, info_level, - fsp, smb_fname, - delete_pending, write_time_ts, - ms_dfs_link, ea_list, - lock_data_count, lock_data, - req->flags2, max_data_bytes, - ppdata, &data_size); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } send_trans2_replies(conn, req, params, param_size, *ppdata, data_size, @@ -5331,42 +4818,70 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd NTSTATUS hardlink_internals(TALLOC_CTX *ctx, connection_struct *conn, - const struct smb_filename *smb_fname_old, - const struct smb_filename *smb_fname_new) + const char *oldname_in, + const char *newname_in) { + SMB_STRUCT_STAT sbuf1, sbuf2; + char *last_component_oldname = NULL; + char *last_component_newname = NULL; + char *oldname = NULL; + char *newname = NULL; NTSTATUS status = NT_STATUS_OK; + ZERO_STRUCT(sbuf1); + ZERO_STRUCT(sbuf2); + + status = unix_convert(ctx, conn, oldname_in, False, &oldname, + &last_component_oldname, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = check_name(conn, oldname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* source must already exist. */ - if (!VALID_STAT(smb_fname_old->st)) { + if (!VALID_STAT(sbuf1)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } + status = unix_convert(ctx, conn, newname_in, False, &newname, + &last_component_newname, &sbuf2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = check_name(conn, newname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* Disallow if newname already exists. */ - if (VALID_STAT(smb_fname_new->st)) { + if (VALID_STAT(sbuf2)) { return NT_STATUS_OBJECT_NAME_COLLISION; } /* No links from a directory. */ - if (S_ISDIR(smb_fname_old->st.st_ex_mode)) { + if (S_ISDIR(sbuf1.st_mode)) { return NT_STATUS_FILE_IS_A_DIRECTORY; } - /* Setting a hardlink to/from a stream isn't currently supported. */ - if (is_ntfs_stream_smb_fname(smb_fname_old) || - is_ntfs_stream_smb_fname(smb_fname_new)) { - return NT_STATUS_INVALID_PARAMETER; + /* Ensure this is within the share. */ + status = check_reduced_name(conn, oldname); + if (!NT_STATUS_IS_OK(status)) { + return status; } - DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", - smb_fname_old->base_name, smb_fname_new->base_name)); + DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname )); - if (SMB_VFS_LINK(conn, smb_fname_old->base_name, - smb_fname_new->base_name) != 0) { + if (SMB_VFS_LINK(conn,oldname,newname) != 0) { status = map_nt_error_from_unix(errno); DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n", - nt_errstr(status), smb_fname_old->base_name, - smb_fname_new->base_name)); + nt_errstr(status), newname, oldname)); } + return status; } @@ -5376,30 +4891,34 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, NTSTATUS smb_set_file_time(connection_struct *conn, files_struct *fsp, - const struct smb_filename *smb_fname, + const char *fname, + const SMB_STRUCT_STAT *psbuf, struct smb_file_time *ft, bool setting_write_time) { - struct smb_filename smb_fname_base; + struct smb_file_time ft_stat; uint32 action = FILE_NOTIFY_CHANGE_LAST_ACCESS |FILE_NOTIFY_CHANGE_LAST_WRITE |FILE_NOTIFY_CHANGE_CREATION; - if (!VALID_STAT(smb_fname->st)) { + if (!VALID_STAT(*psbuf)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } /* get some defaults (no modifications) if any info is zero or -1. */ if (null_timespec(ft->create_time)) { + ft->create_time = get_create_timespec(psbuf, lp_fake_dir_create_times(SNUM(conn))); action &= ~FILE_NOTIFY_CHANGE_CREATION; } if (null_timespec(ft->atime)) { + ft->atime= get_atimespec(psbuf); action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS; } if (null_timespec(ft->mtime)) { + ft->mtime = get_mtimespec(psbuf); action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; } @@ -5412,7 +4931,6 @@ NTSTATUS smb_set_file_time(connection_struct *conn, * what we can store on this filesystem. */ round_timespec(conn->ts_res, &ft->create_time); - round_timespec(conn->ts_res, &ft->ctime); round_timespec(conn->ts_res, &ft->atime); round_timespec(conn->ts_res, &ft->mtime); @@ -5420,8 +4938,6 @@ NTSTATUS smb_set_file_time(connection_struct *conn, time_to_asc(convert_timespec_to_time_t(ft->atime)))); DEBUG(5,("smb_set_filetime: modtime: %s\n ", time_to_asc(convert_timespec_to_time_t(ft->mtime)))); - DEBUG(5,("smb_set_filetime: ctime: %s\n ", - time_to_asc(convert_timespec_to_time_t(ft->ctime)))); DEBUG(5,("smb_set_file_time: createtime: %s\n ", time_to_asc(convert_timespec_to_time_t(ft->create_time)))); @@ -5447,24 +4963,35 @@ NTSTATUS smb_set_file_time(connection_struct *conn, set_sticky_write_time_fsp(fsp, ft->mtime); } } else { - set_sticky_write_time_path( - vfs_file_id_from_sbuf(conn, &smb_fname->st), - ft->mtime); + set_sticky_write_time_path(conn, fname, + vfs_file_id_from_sbuf(conn, psbuf), + ft->mtime); } } - DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n")); + ft_stat.create_time = get_create_timespec(psbuf, + lp_fake_dir_create_times(SNUM(conn))); + ft_stat.atime= get_atimespec(psbuf); + ft_stat.mtime = get_mtimespec(psbuf); - /* Always call ntimes on the base, even if a stream was passed in. */ - smb_fname_base = *smb_fname; - smb_fname_base.stream_name = NULL; + round_timespec(conn->ts_res, &ft_stat.create_time); + round_timespec(conn->ts_res, &ft_stat.atime); + round_timespec(conn->ts_res, &ft_stat.mtime); - if(file_ntimes(conn, &smb_fname_base, ft)!=0) { - return map_nt_error_from_unix(errno); + if (fsp && fsp->base_fsp) { + fname = fsp->base_fsp->fsp_name; } - notify_fname(conn, NOTIFY_ACTION_MODIFIED, action, - smb_fname->base_name); + if (timespec_compare(&ft_stat.create_time, &ft->create_time) || + timespec_compare(&ft_stat.atime, &ft->atime) || + timespec_compare(&ft_stat.mtime, &ft->mtime)) { + DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n")); + if(file_ntimes(conn, fname, ft)!=0) { + return map_nt_error_from_unix(errno); + } + } + notify_fname(conn, NOTIFY_ACTION_MODIFIED, action, fname); + return NT_STATUS_OK; } @@ -5473,26 +5000,25 @@ NTSTATUS smb_set_file_time(connection_struct *conn, ****************************************************************************/ static NTSTATUS smb_set_file_dosmode(connection_struct *conn, - const struct smb_filename *smb_fname, - uint32 dosmode) + files_struct *fsp, + const char *fname, + SMB_STRUCT_STAT *psbuf, + uint32 dosmode) { - struct smb_filename *smb_fname_base = NULL; - NTSTATUS status; - - if (!VALID_STAT(smb_fname->st)) { + if (!VALID_STAT(*psbuf)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } - /* Always operate on the base_name, even if a stream was passed in. */ - status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name, - NULL, &smb_fname->st, - &smb_fname_base); - if (!NT_STATUS_IS_OK(status)) { - return status; + if (fsp) { + if (fsp->base_fsp) { + fname = fsp->base_fsp->fsp_name; + } else { + fname = fsp->fsp_name; + } } - + if (dosmode) { - if (S_ISDIR(smb_fname_base->st.st_ex_mode)) { + if (S_ISDIR(psbuf->st_mode)) { dosmode |= aDIR; } else { dosmode &= ~aDIR; @@ -5502,25 +5028,18 @@ static NTSTATUS smb_set_file_dosmode(connection_struct *conn, DEBUG(6,("smb_set_file_dosmode: dosmode: 0x%x\n", (unsigned int)dosmode)); /* check the mode isn't different, before changing it */ - if ((dosmode != 0) && (dosmode != dos_mode(conn, smb_fname_base))) { - DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode " - "0x%x\n", smb_fname_str_dbg(smb_fname_base), - (unsigned int)dosmode)); - - if(file_set_dosmode(conn, smb_fname_base, dosmode, NULL, - false)) { - DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of " - "%s failed (%s)\n", - smb_fname_str_dbg(smb_fname_base), - strerror(errno))); - status = map_nt_error_from_unix(errno); - goto out; + if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, psbuf))) { + + DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode 0x%x\n", + fname, (unsigned int)dosmode )); + + if(file_set_dosmode(conn, fname, dosmode, psbuf, NULL, false)) { + DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of %s failed (%s)\n", + fname, strerror(errno))); + return map_nt_error_from_unix(errno); } } - status = NT_STATUS_OK; - out: - TALLOC_FREE(smb_fname_base); - return status; + return NT_STATUS_OK; } /**************************************************************************** @@ -5529,14 +5048,12 @@ static NTSTATUS smb_set_file_dosmode(connection_struct *conn, static NTSTATUS smb_set_file_size(connection_struct *conn, struct smb_request *req, - files_struct *fsp, - const struct smb_filename *smb_fname, - const SMB_STRUCT_STAT *psbuf, - SMB_OFF_T size, - bool fail_after_createfile) + files_struct *fsp, + const char *fname, + SMB_STRUCT_STAT *psbuf, + SMB_OFF_T size) { NTSTATUS status = NT_STATUS_OK; - struct smb_filename *smb_fname_tmp = NULL; files_struct *new_fsp = NULL; if (!VALID_STAT(*psbuf)) { @@ -5550,7 +5067,7 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, } DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n", - smb_fname_str_dbg(smb_fname), (double)size)); + fname, (double)size )); if (fsp && fsp->fh->fd != -1) { /* Handle based call. */ @@ -5561,18 +5078,12 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, return NT_STATUS_OK; } - status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - smb_fname_tmp->st = *psbuf; - status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname_tmp, /* fname */ + fname, /* fname */ + 0, /* create_file_flags */ FILE_WRITE_ATTRIBUTES, /* access_mask */ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ FILE_SHARE_DELETE), @@ -5584,21 +5095,14 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, NULL, /* sd */ NULL, /* ea_list */ &new_fsp, /* result */ - NULL); /* pinfo */ - - TALLOC_FREE(smb_fname_tmp); + NULL, /* pinfo */ + psbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { /* NB. We check for open_was_deferred in the caller. */ return status; } - /* See RAW-SFILEINFO-END-OF-FILE */ - if (fail_after_createfile) { - close_file(req, new_fsp,NORMAL_CLOSE); - return NT_STATUS_INVALID_LEVEL; - } - if (vfs_set_filelen(new_fsp, size) == -1) { status = map_nt_error_from_unix(errno); close_file(req, new_fsp,NORMAL_CLOSE); @@ -5618,7 +5122,7 @@ static NTSTATUS smb_info_set_ea(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const struct smb_filename *smb_fname) + const char *fname) { struct ea_list *ea_list = NULL; TALLOC_CTX *ctx = NULL; @@ -5648,59 +5152,12 @@ static NTSTATUS smb_info_set_ea(connection_struct *conn, if (!ea_list) { return NT_STATUS_INVALID_PARAMETER; } - status = set_ea(conn, fsp, smb_fname, ea_list); + status = set_ea(conn, fsp, fname, ea_list); return status; } /**************************************************************************** - Deal with SMB_FILE_FULL_EA_INFORMATION set. -****************************************************************************/ - -static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn, - const char *pdata, - int total_data, - files_struct *fsp) -{ - struct ea_list *ea_list = NULL; - NTSTATUS status; - - if (!fsp) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!lp_ea_support(SNUM(conn))) { - DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but " - "EA's not supported.\n", - (unsigned int)total_data)); - return NT_STATUS_EAS_NOT_SUPPORTED; - } - - if (total_data < 10) { - DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u " - "too small.\n", - (unsigned int)total_data)); - return NT_STATUS_INVALID_PARAMETER; - } - - ea_list = read_nttrans_ea_list(talloc_tos(), - pdata, - total_data); - - if (!ea_list) { - return NT_STATUS_INVALID_PARAMETER; - } - status = set_ea(conn, fsp, fsp->fsp_name, ea_list); - - DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n", - smb_fname_str_dbg(fsp->fsp_name), - nt_errstr(status) )); - - return status; -} - - -/**************************************************************************** Deal with SMB_SET_FILE_DISPOSITION_INFO. ****************************************************************************/ @@ -5708,7 +5165,8 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - struct smb_filename *smb_fname) + const char *fname, + SMB_STRUCT_STAT *psbuf) { NTSTATUS status = NT_STATUS_OK; bool delete_on_close; @@ -5723,19 +5181,18 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn, } delete_on_close = (CVAL(pdata,0) ? True : False); - dosmode = dos_mode(conn, smb_fname); + dosmode = dos_mode(conn, fname, psbuf); DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, " "delete_on_close = %u\n", - smb_fname_str_dbg(smb_fname), + fsp->fsp_name, (unsigned int)dosmode, (unsigned int)delete_on_close )); - if (delete_on_close) { - status = can_set_delete_on_close(fsp, dosmode); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + status = can_set_delete_on_close(fsp, delete_on_close, dosmode); + + if (!NT_STATUS_IS_OK(status)) { + return status; } /* The set is across all open files on this dev/inode pair. */ @@ -5776,9 +5233,8 @@ static NTSTATUS smb_file_position_information(connection_struct *conn, } #endif /* LARGE_SMB_OFF_T */ - DEBUG(10,("smb_file_position_information: Set file position " - "information for file %s to %.0f\n", fsp_str_dbg(fsp), - (double)position_information)); + DEBUG(10,("smb_file_position_information: Set file position information for file %s to %.0f\n", + fsp->fsp_name, (double)position_information )); fsp->fh->position_information = position_information; return NT_STATUS_OK; } @@ -5811,10 +5267,10 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, struct smb_request *req, const char *pdata, int total_data, - const struct smb_filename *smb_fname) + const char *fname) { char *link_target = NULL; - const char *newname = smb_fname->base_name; + const char *newname = fname; TALLOC_CTX *ctx = talloc_tos(); /* Set a symbolic link. */ @@ -5852,10 +5308,9 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, struct smb_request *req, const char *pdata, int total_data, - const struct smb_filename *smb_fname_new) + const char *fname) { char *oldname = NULL; - struct smb_filename *smb_fname_old = NULL; TALLOC_CTX *ctx = talloc_tos(); NTSTATUS status = NT_STATUS_OK; @@ -5870,21 +5325,18 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, return status; } - DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n", - smb_fname_str_dbg(smb_fname_new), oldname)); - - status = filename_convert(ctx, - conn, + status = resolve_dfspath(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, oldname, - 0, - NULL, - &smb_fname_old); + &oldname); if (!NT_STATUS_IS_OK(status)) { return status; } - return hardlink_internals(ctx, conn, smb_fname_old, smb_fname_new); + DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n", + fname, oldname)); + + return hardlink_internals(ctx, conn, oldname, fname); } /**************************************************************************** @@ -5896,14 +5348,16 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - struct smb_filename *smb_fname_src) + const char *fname) { bool overwrite; uint32 root_fid; uint32 len; char *newname = NULL; - struct smb_filename *smb_fname_dst = NULL; + char *base_name = NULL; bool dest_has_wcard = False; + SMB_STRUCT_STAT sbuf; + char *newname_last_component = NULL; NTSTATUS status = NT_STATUS_OK; char *p; TALLOC_CTX *ctx = talloc_tos(); @@ -5912,6 +5366,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } + ZERO_STRUCT(sbuf); + overwrite = (CVAL(pdata,0) ? True : False); root_fid = IVAL(pdata,4); len = IVAL(pdata,8); @@ -5949,44 +5405,20 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, if (newname[0] != ':') { return NT_STATUS_NOT_SUPPORTED; } - - /* Create an smb_fname to call rename_internals_fsp() with. */ - status = create_synthetic_smb_fname(talloc_tos(), - fsp->base_fsp->fsp_name->base_name, newname, NULL, - &smb_fname_dst); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - /* - * Set the original last component, since - * rename_internals_fsp() requires it. - */ - smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst, - newname); - if (smb_fname_dst->original_lcomp == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; + base_name = talloc_asprintf(ctx, "%s%s", + fsp->base_fsp->fsp_name, + newname); + if (!base_name) { + return NT_STATUS_NO_MEMORY; } - } else { - /* - * Build up an smb_fname_dst based on the filename passed in. - * We basically just strip off the last component, and put on - * the newname instead. - */ - char *base_name = NULL; - /* newname must *not* be a stream name. */ - if (newname[0] == ':') { + if (is_ntfs_stream_name(newname)) { return NT_STATUS_NOT_SUPPORTED; } - /* - * Strip off the last component (filename) of the path passed - * in. - */ - base_name = talloc_strdup(ctx, smb_fname_src->base_name); + /* Create the base directory. */ + base_name = talloc_strdup(ctx, fname); if (!base_name) { return NT_STATUS_NO_MEMORY; } @@ -6007,50 +5439,35 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_NO_MEMORY; } - status = unix_convert(ctx, conn, base_name, &smb_fname_dst, - (UCF_SAVE_LCOMP | - (dest_has_wcard ? - UCF_ALWAYS_ALLOW_WCARD_LCOMP : - 0))); + status = unix_convert(ctx, conn, newname, False, + &newname, + &newname_last_component, + &sbuf); /* If an error we expect this to be * NT_STATUS_OBJECT_PATH_NOT_FOUND */ - if (!NT_STATUS_IS_OK(status)) { - if(!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND, - status)) { - goto out; - } - /* Create an smb_fname to call rename_internals_fsp() */ - status = create_synthetic_smb_fname(ctx, - base_name, NULL, - NULL, - &smb_fname_dst); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } + if (!NT_STATUS_IS_OK(status) + && !NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND, + status)) { + return status; } } if (fsp) { - DEBUG(10,("smb_file_rename_information: " - "SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", - fsp->fnum, fsp_str_dbg(fsp), - smb_fname_str_dbg(smb_fname_dst))); - status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0, + DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", + fsp->fnum, fsp->fsp_name, base_name )); + status = rename_internals_fsp(conn, fsp, base_name, + newname_last_component, 0, overwrite); } else { - DEBUG(10,("smb_file_rename_information: " - "SMB_FILE_RENAME_INFORMATION %s -> %s\n", - smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst))); - status = rename_internals(ctx, conn, req, smb_fname_src, - smb_fname_dst, 0, overwrite, false, - dest_has_wcard, - FILE_WRITE_ATTRIBUTES); - } - out: - TALLOC_FREE(smb_fname_dst); + DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n", + fname, base_name )); + status = rename_internals(ctx, conn, req, fname, base_name, 0, + overwrite, False, dest_has_wcard, + FILE_WRITE_ATTRIBUTES); + } + return status; } @@ -6063,7 +5480,8 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const struct smb_filename *smb_fname) + const char *fname, + SMB_STRUCT_STAT *psbuf) { uint16 posix_acl_version; uint16 num_file_acls; @@ -6098,20 +5516,18 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, } DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n", - smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp), + fname ? fname : fsp->fsp_name, (unsigned int)num_file_acls, (unsigned int)num_def_acls)); - if (valid_file_acls && !set_unix_posix_acl(conn, fsp, - smb_fname->base_name, num_file_acls, - pdata + SMB_POSIX_ACL_HEADER_SIZE)) { + if (valid_file_acls && !set_unix_posix_acl(conn, fsp, fname, num_file_acls, + pdata + SMB_POSIX_ACL_HEADER_SIZE)) { return map_nt_error_from_unix(errno); } - if (valid_def_acls && !set_unix_posix_default_acl(conn, - smb_fname->base_name, &smb_fname->st, num_def_acls, - pdata + SMB_POSIX_ACL_HEADER_SIZE + - (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) { + if (valid_def_acls && !set_unix_posix_default_acl(conn, fname, psbuf, num_def_acls, + pdata + SMB_POSIX_ACL_HEADER_SIZE + + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) { return map_nt_error_from_unix(errno); } return NT_STATUS_OK; @@ -6187,7 +5603,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u," "lock_pid = %u, count = %.0f, offset = %.0f\n", - fsp_str_dbg(fsp), + fsp->fsp_name, (unsigned int)lock_type, (unsigned int)lock_pid, (double)count, @@ -6243,85 +5659,111 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, } /**************************************************************************** - Deal with SMB_SET_FILE_BASIC_INFO. + Deal with SMB_INFO_STANDARD. ****************************************************************************/ -static NTSTATUS smb_set_file_basic_info(connection_struct *conn, +static NTSTATUS smb_set_info_standard(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const struct smb_filename *smb_fname) + const char *fname, + const SMB_STRUCT_STAT *psbuf) { - /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */ struct smb_file_time ft; - uint32 dosmode = 0; - NTSTATUS status = NT_STATUS_OK; - ZERO_STRUCT(ft); - if (total_data < 36) { + if (total_data < 12) { return NT_STATUS_INVALID_PARAMETER; } - /* Set the attributes */ - dosmode = IVAL(pdata,32); - status = smb_set_file_dosmode(conn, smb_fname, dosmode); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - /* create time */ - ft.create_time = interpret_long_date(pdata); + ft.create_time = convert_time_t_to_timespec(srv_make_unix_date2(pdata)); /* access time */ - ft.atime = interpret_long_date(pdata+8); - - /* write time. */ - ft.mtime = interpret_long_date(pdata+16); + ft.atime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+4)); - /* change time. */ - ft.ctime = interpret_long_date(pdata+24); + /* write time */ + ft.mtime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+8)); - DEBUG(10, ("smb_set_file_basic_info: file %s\n", - smb_fname_str_dbg(smb_fname))); + DEBUG(10,("smb_set_info_standard: file %s\n", + fname ? fname : fsp->fsp_name )); - return smb_set_file_time(conn, fsp, smb_fname, &ft, - true); + return smb_set_file_time(conn, + fsp, + fname, + psbuf, + &ft, + true); } /**************************************************************************** - Deal with SMB_INFO_STANDARD. + Deal with SMB_SET_FILE_BASIC_INFO. ****************************************************************************/ -static NTSTATUS smb_set_info_standard(connection_struct *conn, +static NTSTATUS smb_set_file_basic_info(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const struct smb_filename *smb_fname) + const char *fname, + SMB_STRUCT_STAT *psbuf) { + /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */ + struct timespec write_time; + struct timespec changed_time; struct smb_file_time ft; + uint32 dosmode = 0; + NTSTATUS status = NT_STATUS_OK; + bool setting_write_time = true; ZERO_STRUCT(ft); - if (total_data < 12) { + if (total_data < 36) { return NT_STATUS_INVALID_PARAMETER; } - /* create time */ - ft.create_time = convert_time_t_to_timespec(srv_make_unix_date2(pdata)); + /* Set the attributes */ + dosmode = IVAL(pdata,32); + status = smb_set_file_dosmode(conn, fsp, fname, psbuf, dosmode); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* access time */ - ft.atime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+4)); - /* write time */ - ft.mtime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+8)); + ft.atime = interpret_long_date(pdata+8); - DEBUG(10,("smb_set_info_standard: file %s\n", - smb_fname_str_dbg(smb_fname))); + write_time = interpret_long_date(pdata+16); + changed_time = interpret_long_date(pdata+24); + + /* mtime */ + ft.mtime = timespec_min(&write_time, &changed_time); + + /* create time */ + ft.create_time = interpret_long_date(pdata); + + if ((timespec_compare(&write_time, &ft.mtime) == 1) && + !null_timespec(write_time)) { + ft.mtime = write_time; + } + + /* Prefer a defined time to an undefined one. */ + if (null_timespec(ft.mtime)) { + if (null_timespec(write_time)) { + ft.mtime = changed_time; + setting_write_time = false; + } else { + ft.mtime = write_time; + } + } + + DEBUG(10,("smb_set_file_basic_info: file %s\n", + fname ? fname : fsp->fsp_name )); - return smb_set_file_time(conn, - fsp, - smb_fname, + return smb_set_file_time(conn, + fsp, + fname, + psbuf, &ft, - true); + setting_write_time); } /**************************************************************************** @@ -6333,13 +5775,14 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - struct smb_filename *smb_fname) + const char *fname, + SMB_STRUCT_STAT *psbuf) { uint64_t allocation_size = 0; NTSTATUS status = NT_STATUS_OK; files_struct *new_fsp = NULL; - if (!VALID_STAT(smb_fname->st)) { + if (!VALID_STAT(*psbuf)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } @@ -6357,22 +5800,20 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, } #endif /* LARGE_SMB_OFF_T */ - DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for " - "file %s to %.0f\n", smb_fname_str_dbg(smb_fname), - (double)allocation_size)); + DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for file %s to %.0f\n", + fname, (double)allocation_size )); if (allocation_size) { allocation_size = smb_roundup(conn, allocation_size); } - DEBUG(10,("smb_set_file_allocation_info: file %s : setting new " - "allocation size to %.0f\n", smb_fname_str_dbg(smb_fname), - (double)allocation_size)); + DEBUG(10,("smb_set_file_allocation_info: file %s : setting new allocation size to %.0f\n", + fname, (double)allocation_size )); if (fsp && fsp->fh->fd != -1) { /* Open file handle. */ /* Only change if needed. */ - if (allocation_size != get_file_size_stat(&smb_fname->st)) { + if (allocation_size != get_file_size_stat(psbuf)) { if (vfs_allocate_file_space(fsp, allocation_size) == -1) { return map_nt_error_from_unix(errno); } @@ -6387,11 +5828,13 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, } /* Pathname or stat or directory file. */ + status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + 0, /* create_file_flags */ FILE_WRITE_DATA, /* access_mask */ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ FILE_SHARE_DELETE), @@ -6403,7 +5846,8 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, NULL, /* sd */ NULL, /* ea_list */ &new_fsp, /* result */ - NULL); /* pinfo */ + NULL, /* pinfo */ + psbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { /* NB. We check for open_was_deferred in the caller. */ @@ -6411,7 +5855,7 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, } /* Only change if needed. */ - if (allocation_size != get_file_size_stat(&smb_fname->st)) { + if (allocation_size != get_file_size_stat(psbuf)) { if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) { status = map_nt_error_from_unix(errno); close_file(req, new_fsp, NORMAL_CLOSE); @@ -6439,8 +5883,8 @@ static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const struct smb_filename *smb_fname, - bool fail_after_createfile) + const char *fname, + SMB_STRUCT_STAT *psbuf) { SMB_OFF_T size; @@ -6458,15 +5902,13 @@ static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn, } #endif /* LARGE_SMB_OFF_T */ DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for " - "file %s to %.0f\n", smb_fname_str_dbg(smb_fname), - (double)size)); + "file %s to %.0f\n", fname, (double)size )); return smb_set_file_size(conn, req, fsp, - smb_fname, - &smb_fname->st, - size, - fail_after_createfile); + fname, + psbuf, + size); } /**************************************************************************** @@ -6476,7 +5918,8 @@ static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn, static NTSTATUS smb_unix_mknod(connection_struct *conn, const char *pdata, int total_data, - const struct smb_filename *smb_fname) + const char *fname, + SMB_STRUCT_STAT *psbuf) { uint32 file_type = IVAL(pdata,56); #if defined(HAVE_MAKEDEV) @@ -6492,8 +5935,7 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode, - PERM_NEW_FILE, &unixmode); + status = unix_perms_from_wire(conn, psbuf, raw_unixmode, PERM_NEW_FILE, &unixmode); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6527,12 +5969,11 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev " - "%.0f mode 0%o for file %s\n", (double)dev, - (unsigned int)unixmode, smb_fname_str_dbg(smb_fname))); + DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \ +0%o for file %s\n", (double)dev, (unsigned int)unixmode, fname )); /* Ok - do the mknod. */ - if (SMB_VFS_MKNOD(conn, smb_fname->base_name, unixmode, dev) != 0) { + if (SMB_VFS_MKNOD(conn, fname, unixmode, dev) != 0) { return map_nt_error_from_unix(errno); } @@ -6542,15 +5983,18 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, if (lp_inherit_perms(SNUM(conn))) { char *parent; - if (!parent_dirname(talloc_tos(), smb_fname->base_name, - &parent, NULL)) { + if (!parent_dirname(talloc_tos(), fname, &parent, NULL)) { return NT_STATUS_NO_MEMORY; } - inherit_access_posix_acl(conn, parent, smb_fname->base_name, - unixmode); + inherit_access_posix_acl(conn, parent, fname, unixmode); TALLOC_FREE(parent); } + if (SMB_VFS_STAT(conn, fname, psbuf) != 0) { + status = map_nt_error_from_unix(errno); + SMB_VFS_UNLINK(conn,fname); + return status; + } return NT_STATUS_OK; } @@ -6563,7 +6007,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const struct smb_filename *smb_fname) + const char *fname, + SMB_STRUCT_STAT *psbuf) { struct smb_file_time ft; uint32 raw_unixmode; @@ -6577,7 +6022,6 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, files_struct *all_fsps = NULL; bool modify_mtime = true; struct file_id id; - SMB_STRUCT_STAT sbuf; ZERO_STRUCT(ft); @@ -6604,8 +6048,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, set_grp = (gid_t)IVAL(pdata,48); raw_unixmode = IVAL(pdata,84); - if (VALID_STAT(smb_fname->st)) { - if (S_ISDIR(smb_fname->st.st_ex_mode)) { + if (VALID_STAT(*psbuf)) { + if (S_ISDIR(psbuf->st_mode)) { ptype = PERM_EXISTING_DIR; } else { ptype = PERM_EXISTING_FILE; @@ -6614,22 +6058,16 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, ptype = PERM_NEW_FILE; } - status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode, - ptype, &unixmode); + status = unix_perms_from_wire(conn, psbuf, raw_unixmode, ptype, &unixmode); if (!NT_STATUS_IS_OK(status)) { return status; } - DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = " - "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", - smb_fname_str_dbg(smb_fname), (double)size, - (unsigned int)set_owner, (unsigned int)set_grp, - (int)raw_unixmode)); + DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = %s \ +size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", + fname, (double)size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode)); - sbuf = smb_fname->st; - - if (!VALID_STAT(sbuf)) { - struct smb_filename *smb_fname_tmp = NULL; + if (!VALID_STAT(*psbuf)) { /* * The only valid use of this is to create character and block * devices, and named pipes. This is deprecated (IMHO) and @@ -6639,32 +6077,17 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, status = smb_unix_mknod(conn, pdata, total_data, - smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = copy_smb_filename(talloc_tos(), smb_fname, - &smb_fname_tmp); + fname, + psbuf); if (!NT_STATUS_IS_OK(status)) { return status; } - if (SMB_VFS_STAT(conn, smb_fname_tmp) != 0) { - status = map_nt_error_from_unix(errno); - TALLOC_FREE(smb_fname_tmp); - SMB_VFS_UNLINK(conn, smb_fname); - return status; - } - - sbuf = smb_fname_tmp->st; - TALLOC_FREE(smb_fname_tmp); - /* Ensure we don't try and change anything else. */ raw_unixmode = SMB_MODE_NO_CHANGE; - size = get_file_size_stat(&sbuf); - ft.atime = sbuf.st_ex_atime; - ft.mtime = sbuf.st_ex_mtime; + size = get_file_size_stat(psbuf); + ft.atime = get_atimespec(psbuf); + ft.mtime = get_mtimespec(psbuf); /* * We continue here as we might want to change the * owner uid/gid. @@ -6678,7 +6101,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, * */ if (!size) { - size = get_file_size_stat(&sbuf); + size = get_file_size_stat(psbuf); } #endif @@ -6687,11 +6110,9 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, */ if (raw_unixmode != SMB_MODE_NO_CHANGE) { - DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC " - "setting mode 0%o for file %s\n", - (unsigned int)unixmode, - smb_fname_str_dbg(smb_fname))); - if (SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode) != 0) { + DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n", + (unsigned int)unixmode, fname )); + if (SMB_VFS_CHMOD(conn, fname, unixmode) != 0) { return map_nt_error_from_unix(errno); } } @@ -6700,27 +6121,22 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, * Deal with the UNIX specific uid set. */ - if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && - (sbuf.st_ex_uid != set_owner)) { + if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (psbuf->st_uid != set_owner)) { int ret; - DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC " - "changing owner %u for path %s\n", - (unsigned int)set_owner, - smb_fname_str_dbg(smb_fname))); + DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC changing owner %u for path %s\n", + (unsigned int)set_owner, fname )); - if (S_ISLNK(sbuf.st_ex_mode)) { - ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, - set_owner, (gid_t)-1); + if (S_ISLNK(psbuf->st_mode)) { + ret = SMB_VFS_LCHOWN(conn, fname, set_owner, (gid_t)-1); } else { - ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, - set_owner, (gid_t)-1); + ret = SMB_VFS_CHOWN(conn, fname, set_owner, (gid_t)-1); } if (ret != 0) { status = map_nt_error_from_unix(errno); if (delete_on_fail) { - SMB_VFS_UNLINK(conn, smb_fname); + SMB_VFS_UNLINK(conn,fname); } return status; } @@ -6730,17 +6146,13 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, * Deal with the UNIX specific gid set. */ - if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && - (sbuf.st_ex_gid != set_grp)) { - DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC " - "changing group %u for file %s\n", - (unsigned int)set_owner, - smb_fname_str_dbg(smb_fname))); - if (SMB_VFS_CHOWN(conn, smb_fname->base_name, (uid_t)-1, - set_grp) != 0) { + if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (psbuf->st_gid != set_grp)) { + DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n", + (unsigned int)set_owner, fname )); + if (SMB_VFS_CHOWN(conn, fname, (uid_t)-1, set_grp) != 0) { status = map_nt_error_from_unix(errno); if (delete_on_fail) { - SMB_VFS_UNLINK(conn, smb_fname); + SMB_VFS_UNLINK(conn,fname); } return status; } @@ -6749,22 +6161,16 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, /* Deal with any size changes. */ status = smb_set_file_size(conn, req, - fsp, - smb_fname, - &sbuf, - size, - false); + fsp, + fname, + psbuf, + size); if (!NT_STATUS_IS_OK(status)) { return status; } /* Deal with any time changes. */ - if (null_timespec(ft.mtime) && null_timespec(ft.atime)) { - /* No change, don't cancel anything. */ - return status; - } - - id = vfs_file_id_from_sbuf(conn, &sbuf); + id = vfs_file_id_from_sbuf(conn, psbuf); for(all_fsps = file_find_di_first(id); all_fsps; all_fsps = file_find_di_next(all_fsps)) { /* @@ -6787,12 +6193,13 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, status = smb_set_file_time(conn, fsp, - smb_fname, + fname, + psbuf, &ft, false); if (modify_mtime) { notify_fname(conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name); + FILE_NOTIFY_CHANGE_LAST_WRITE, fname); } return status; } @@ -6806,7 +6213,8 @@ static NTSTATUS smb_set_file_unix_info2(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const struct smb_filename *smb_fname) + const char *fname, + SMB_STRUCT_STAT *psbuf) { NTSTATUS status; uint32 smb_fflags; @@ -6820,7 +6228,7 @@ static NTSTATUS smb_set_file_unix_info2(connection_struct *conn, * and UNIX_INFO2. */ status = smb_set_file_unix_basic(conn, req, pdata, total_data, - fsp, smb_fname); + fsp, fname, psbuf); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6834,8 +6242,8 @@ static NTSTATUS smb_set_file_unix_info2(connection_struct *conn, if (smb_fmask != 0) { int stat_fflags = 0; - if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags, - smb_fmask, &stat_fflags)) { + if (!map_info2_flags_to_sbuf(psbuf, smb_fflags, smb_fmask, + &stat_fflags)) { /* Client asked to alter a flag we don't understand. */ return NT_STATUS_INVALID_PARAMETER; } @@ -6844,8 +6252,7 @@ static NTSTATUS smb_set_file_unix_info2(connection_struct *conn, /* XXX: we should be using SMB_VFS_FCHFLAGS here. */ return NT_STATUS_NOT_SUPPORTED; } else { - if (SMB_VFS_CHFLAGS(conn, smb_fname->base_name, - stat_fflags) != 0) { + if (SMB_VFS_CHFLAGS(conn, fname, stat_fflags) != 0) { return map_nt_error_from_unix(errno); } } @@ -6867,7 +6274,8 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, struct smb_request *req, char **ppdata, int total_data, - struct smb_filename *smb_fname, + const char *fname, + SMB_STRUCT_STAT *psbuf, int *pdata_return_size) { NTSTATUS status = NT_STATUS_OK; @@ -6886,8 +6294,7 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, raw_unixmode = IVAL(pdata,8); /* Next 4 bytes are not yet defined. */ - status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode, - PERM_NEW_DIR, &unixmode); + status = unix_perms_from_wire(conn, psbuf, raw_unixmode, PERM_NEW_DIR, &unixmode); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6895,13 +6302,14 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS; DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n", - smb_fname_str_dbg(smb_fname), (unsigned int)unixmode)); + fname, (unsigned int)unixmode )); - status = SMB_VFS_CREATE_FILE( + status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + 0, /* create_file_flags */ FILE_READ_ATTRIBUTES, /* access_mask */ FILE_SHARE_NONE, /* share_access */ FILE_CREATE, /* create_disposition*/ @@ -6912,7 +6320,8 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + psbuf); /* psbuf */ if (NT_STATUS_IS_OK(status)) { close_file(req, fsp, NORMAL_CLOSE); @@ -6944,14 +6353,12 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, case SMB_QUERY_FILE_UNIX_BASIC: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC); SSVAL(pdata,10,0); /* Padding. */ - store_file_unix_basic(conn, pdata + 12, fsp, - &smb_fname->st); + store_file_unix_basic(conn, pdata + 12, fsp, psbuf); break; case SMB_QUERY_FILE_UNIX_INFO2: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2); SSVAL(pdata,10,0); /* Padding. */ - store_file_unix_basic_info2(conn, pdata + 12, fsp, - &smb_fname->st); + store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf); break; default: SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED); @@ -6970,7 +6377,8 @@ static NTSTATUS smb_posix_open(connection_struct *conn, struct smb_request *req, char **ppdata, int total_data, - struct smb_filename *smb_fname, + const char *fname, + SMB_STRUCT_STAT *psbuf, int *pdata_return_size) { bool extended_oplock_granted = False; @@ -7005,7 +6413,8 @@ static NTSTATUS smb_posix_open(connection_struct *conn, return smb_posix_mkdir(conn, req, ppdata, total_data, - smb_fname, + fname, + psbuf, pdata_return_size); } @@ -7044,10 +6453,11 @@ static NTSTATUS smb_posix_open(connection_struct *conn, raw_unixmode = IVAL(pdata,8); /* Next 4 bytes are not yet defined. */ - status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode, - (VALID_STAT(smb_fname->st) ? - PERM_EXISTING_FILE : PERM_NEW_FILE), - &unixmode); + status = unix_perms_from_wire(conn, + psbuf, + raw_unixmode, + VALID_STAT(*psbuf) ? PERM_EXISTING_FILE : PERM_NEW_FILE, + &unixmode); if (!NT_STATUS_IS_OK(status)) { return status; @@ -7066,7 +6476,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn, } DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n", - smb_fname_str_dbg(smb_fname), + fname, (unsigned int)wire_open_mode, (unsigned int)unixmode )); @@ -7074,7 +6484,8 @@ static NTSTATUS smb_posix_open(connection_struct *conn, conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + 0, /* create_file_flags */ access_mask, /* access_mask */ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ FILE_SHARE_DELETE), @@ -7086,7 +6497,8 @@ static NTSTATUS smb_posix_open(connection_struct *conn, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + psbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { return status; @@ -7140,14 +6552,12 @@ static NTSTATUS smb_posix_open(connection_struct *conn, case SMB_QUERY_FILE_UNIX_BASIC: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC); SSVAL(pdata,10,0); /* padding. */ - store_file_unix_basic(conn, pdata + 12, fsp, - &smb_fname->st); + store_file_unix_basic(conn, pdata + 12, fsp, psbuf); break; case SMB_QUERY_FILE_UNIX_INFO2: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2); SSVAL(pdata,10,0); /* padding. */ - store_file_unix_basic_info2(conn, pdata + 12, fsp, - &smb_fname->st); + store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf); break; default: SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED); @@ -7165,7 +6575,8 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, struct smb_request *req, const char *pdata, int total_data, - struct smb_filename *smb_fname) + const char *fname, + SMB_STRUCT_STAT *psbuf) { NTSTATUS status = NT_STATUS_OK; files_struct *fsp = NULL; @@ -7182,20 +6593,20 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, flags = SVAL(pdata,0); - if (!VALID_STAT(smb_fname->st)) { + if (!VALID_STAT(*psbuf)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) && - !VALID_STAT_OF_DIR(smb_fname->st)) { + !VALID_STAT_OF_DIR(*psbuf)) { return NT_STATUS_NOT_A_DIRECTORY; } DEBUG(10,("smb_posix_unlink: %s %s\n", (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file", - smb_fname_str_dbg(smb_fname))); + fname)); - if (VALID_STAT_OF_DIR(smb_fname->st)) { + if (VALID_STAT_OF_DIR(*psbuf)) { create_options |= FILE_DIRECTORY_FILE; } @@ -7203,7 +6614,8 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - smb_fname, /* fname */ + fname, /* fname */ + 0, /* create_file_flags */ DELETE_ACCESS, /* access_mask */ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ FILE_SHARE_DELETE), @@ -7215,7 +6627,8 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &info); /* pinfo */ + &info, /* pinfo */ + psbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { return status; @@ -7230,7 +6643,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, NULL); if (lck == NULL) { DEBUG(0, ("smb_posix_unlink: Could not get share mode " - "lock for file %s\n", fsp_str_dbg(fsp))); + "lock for file %s\n", fsp->fsp_name)); close_file(req, fsp, NORMAL_CLOSE); return NT_STATUS_INVALID_PARAMETER; } @@ -7260,7 +6673,8 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, &del, 1, fsp, - smb_fname); + fname, + psbuf); if (!NT_STATUS_IS_OK(status)) { close_file(req, fsp, NORMAL_CLOSE); @@ -7271,36 +6685,190 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, return close_file(req, fsp, NORMAL_CLOSE); } -NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, - struct smb_request *req, - TALLOC_CTX *mem_ctx, - uint16_t info_level, - files_struct *fsp, - struct smb_filename *smb_fname, - char **ppdata, int total_data, - int *ret_data_size) +/**************************************************************************** + Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname). +****************************************************************************/ + +static void call_trans2setfilepathinfo(connection_struct *conn, + struct smb_request *req, + unsigned int tran_call, + char **pparams, int total_params, + char **ppdata, int total_data, + unsigned int max_data_bytes) { + char *params = *pparams; char *pdata = *ppdata; + uint16 info_level; + SMB_STRUCT_STAT sbuf; + char *fname = NULL; + files_struct *fsp = NULL; NTSTATUS status = NT_STATUS_OK; int data_return_size = 0; + TALLOC_CTX *ctx = talloc_tos(); + + if (!params) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + ZERO_STRUCT(sbuf); + + if (tran_call == TRANSACT2_SETFILEINFO) { + if (total_params < 4) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + fsp = file_fsp(req, SVAL(params,0)); + /* Basic check for non-null fsp. */ + if (!check_fsp_open(conn, req, fsp)) { + return; + } + info_level = SVAL(params,2); + + fname = talloc_strdup(talloc_tos(),fsp->fsp_name); + if (!fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + + if(fsp->is_directory || fsp->fh->fd == -1) { + /* + * This is actually a SETFILEINFO on a directory + * handle (returned from an NT SMB). NT5.0 seems + * to do this call. JRA. + */ + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req,ERRDOS,ERRbadpath); + return; + } + } else { + if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) { + DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req,ERRDOS,ERRbadpath); + return; + } + } + } else if (fsp->print_file) { + /* + * Doing a DELETE_ON_CLOSE should cancel a print job. + */ + if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) { + fsp->fh->private_options |= FILE_DELETE_ON_CLOSE; + + DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name )); + + SSVAL(params,0,0); + send_trans2_replies(conn, req, params, 2, + *ppdata, 0, + max_data_bytes); + return; + } else { + reply_unixerror(req, ERRDOS, ERRbadpath); + return; + } + } else { + /* + * Original code - this is an open file. + */ + if (!check_fsp(conn, req, fsp)) { + return; + } + + if (SMB_VFS_FSTAT(fsp, &sbuf) != 0) { + DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); + reply_unixerror(req, ERRDOS, ERRbadfid); + return; + } + } + } else { + /* set path info */ + if (total_params < 7) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + info_level = SVAL(params,0); + srvstr_get_path(ctx, params, req->flags2, &fname, ¶ms[6], + total_params - 6, STR_TERMINATE, + &status); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + status = resolve_dfspath(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &fname); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + return; + } + reply_nterror(req, status); + return; + } + + status = unix_convert(ctx, conn, fname, False, + &fname, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* + * For CIFS UNIX extensions the target name may not exist. + */ + + /* Always do lstat for UNIX calls. */ + SMB_VFS_LSTAT(conn,fname,&sbuf); - *ret_data_size = 0; + } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req, ERRDOS, ERRbadpath); + return; + } + } if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - return NT_STATUS_INVALID_LEVEL; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } if (!CAN_WRITE(conn)) { /* Allow POSIX opens. The open path will deny * any non-readonly opens. */ if (info_level != SMB_POSIX_PATH_OPEN) { - return NT_STATUS_DOS(ERRSRV, ERRaccess); + reply_doserror(req, ERRSRV, ERRaccess); + return; } } - DEBUG(3,("smbd_do_setfilepathinfo: %s (fnum %d) info_level=%d " - "totdata=%d\n", smb_fname_str_dbg(smb_fname), - fsp ? fsp->fnum : -1, info_level, total_data)); + DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n", + tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data)); + + /* Realloc the parameter size */ + *pparams = (char *)SMB_REALLOC(*pparams,2); + if (*pparams == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + params = *pparams; + + SSVAL(params,0,0); switch (info_level) { @@ -7310,7 +6878,8 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, pdata, total_data, fsp, - smb_fname); + fname, + &sbuf); break; } @@ -7320,7 +6889,7 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, pdata, total_data, fsp, - smb_fname); + fname); break; } @@ -7331,7 +6900,8 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, pdata, total_data, fsp, - smb_fname); + fname, + &sbuf); break; } @@ -7342,29 +6912,20 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, pdata, total_data, fsp, - smb_fname); + fname, + &sbuf); break; } case SMB_FILE_END_OF_FILE_INFORMATION: case SMB_SET_FILE_END_OF_FILE_INFO: { - /* - * XP/Win7 both fail after the createfile with - * SMB_SET_FILE_END_OF_FILE_INFO but not - * SMB_FILE_END_OF_FILE_INFORMATION (pass-through). - * The level is known here, so pass it down - * appropriately. - */ - bool should_fail = - (info_level == SMB_SET_FILE_END_OF_FILE_INFO); - status = smb_set_file_end_of_file_info(conn, req, pdata, total_data, fsp, - smb_fname, - should_fail); + fname, + &sbuf); break; } @@ -7384,7 +6945,8 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, pdata, total_data, fsp, - smb_fname); + fname, + &sbuf); break; } @@ -7397,15 +6959,6 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, break; } - case SMB_FILE_FULL_EA_INFORMATION: - { - status = smb_set_file_full_ea_info(conn, - pdata, - total_data, - fsp); - break; - } - /* From tridge Samba4 : * MODE_INFORMATION in setfileinfo (I have no * idea what "mode information" on a file is - it takes a value of 0, @@ -7430,7 +6983,8 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, pdata, total_data, fsp, - smb_fname); + fname, + &sbuf); break; } @@ -7440,30 +6994,33 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, pdata, total_data, fsp, - smb_fname); + fname, + &sbuf); break; } case SMB_SET_FILE_UNIX_LINK: { - if (fsp) { + if (tran_call != TRANSACT2_SETPATHINFO) { /* We must have a pathname for this. */ - return NT_STATUS_INVALID_LEVEL; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } status = smb_set_file_unix_link(conn, req, pdata, - total_data, smb_fname); + total_data, fname); break; } case SMB_SET_FILE_UNIX_HLINK: { - if (fsp) { + if (tran_call != TRANSACT2_SETPATHINFO) { /* We must have a pathname for this. */ - return NT_STATUS_INVALID_LEVEL; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } status = smb_set_file_unix_hlink(conn, req, pdata, total_data, - smb_fname); + fname); break; } @@ -7471,7 +7028,7 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, { status = smb_file_rename_information(conn, req, pdata, total_data, - fsp, smb_fname); + fsp, fname); break; } @@ -7482,15 +7039,17 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, pdata, total_data, fsp, - smb_fname); + fname, + &sbuf); break; } #endif case SMB_SET_POSIX_LOCK: { - if (!fsp) { - return NT_STATUS_INVALID_LEVEL; + if (tran_call != TRANSACT2_SETFILEINFO) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } status = smb_set_posix_lock(conn, req, pdata, total_data, fsp); @@ -7499,227 +7058,43 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, case SMB_POSIX_PATH_OPEN: { - if (fsp) { + if (tran_call != TRANSACT2_SETPATHINFO) { /* We must have a pathname for this. */ - return NT_STATUS_INVALID_LEVEL; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } status = smb_posix_open(conn, req, ppdata, total_data, - smb_fname, + fname, + &sbuf, &data_return_size); break; } case SMB_POSIX_PATH_UNLINK: { - if (fsp) { + if (tran_call != TRANSACT2_SETPATHINFO) { /* We must have a pathname for this. */ - return NT_STATUS_INVALID_LEVEL; + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; } status = smb_posix_unlink(conn, req, pdata, total_data, - smb_fname); + fname, + &sbuf); break; } default: - return NT_STATUS_INVALID_LEVEL; - } - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - *ret_data_size = data_return_size; - return NT_STATUS_OK; -} - -/**************************************************************************** - Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname). -****************************************************************************/ - -static void call_trans2setfilepathinfo(connection_struct *conn, - struct smb_request *req, - unsigned int tran_call, - char **pparams, int total_params, - char **ppdata, int total_data, - unsigned int max_data_bytes) -{ - char *params = *pparams; - char *pdata = *ppdata; - uint16 info_level; - struct smb_filename *smb_fname = NULL; - files_struct *fsp = NULL; - NTSTATUS status = NT_STATUS_OK; - int data_return_size = 0; - - if (!params) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (tran_call == TRANSACT2_SETFILEINFO) { - if (total_params < 4) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - fsp = file_fsp(req, SVAL(params,0)); - /* Basic check for non-null fsp. */ - if (!check_fsp_open(conn, req, fsp)) { - return; - } - info_level = SVAL(params,2); - - status = copy_smb_filename(talloc_tos(), fsp->fsp_name, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - if(fsp->is_directory || fsp->fh->fd == -1) { - /* - * This is actually a SETFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname)) { - DEBUG(3,("call_trans2setfilepathinfo: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_nterror(req, map_nt_error_from_unix(errno)); - return; - } - } else { - if (SMB_VFS_STAT(conn, smb_fname) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: " - "fileinfo of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_nterror(req, map_nt_error_from_unix(errno)); - return; - } - } - } else if (fsp->print_file) { - /* - * Doing a DELETE_ON_CLOSE should cancel a print job. - */ - if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) { - fsp->fh->private_options |= FILE_DELETE_ON_CLOSE; - - DEBUG(3,("call_trans2setfilepathinfo: " - "Cancelling print job (%s)\n", - fsp_str_dbg(fsp))); - - SSVAL(params,0,0); - send_trans2_replies(conn, req, params, 2, - *ppdata, 0, - max_data_bytes); - return; - } else { - reply_nterror(req, - NT_STATUS_OBJECT_PATH_NOT_FOUND); - return; - } - } else { - /* - * Original code - this is an open file. - */ - if (!check_fsp(conn, req, fsp)) { - return; - } - - if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fstat " - "of fnum %d failed (%s)\n", fsp->fnum, - strerror(errno))); - reply_nterror(req, map_nt_error_from_unix(errno)); - return; - } - } - } else { - char *fname = NULL; - - /* set path info */ - if (total_params < 7) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - info_level = SVAL(params,0); - srvstr_get_path(req, params, req->flags2, &fname, ¶ms[6], - total_params - 6, STR_TERMINATE, - &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - status = filename_convert(req, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - return; - } - reply_nterror(req, status); - return; - } - - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* - * For CIFS UNIX extensions the target name may not exist. - */ - - /* Always do lstat for UNIX calls. */ - SMB_VFS_LSTAT(conn, smb_fname); - - } else if (!VALID_STAT(smb_fname->st) && - SMB_VFS_STAT(conn, smb_fname)) { - DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of " - "%s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_nterror(req, map_nt_error_from_unix(errno)); + reply_nterror(req, NT_STATUS_INVALID_LEVEL); return; - } - } - - DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d " - "totdata=%d\n", tran_call, smb_fname_str_dbg(smb_fname), - fsp ? fsp->fnum : -1, info_level,total_data)); - - /* Realloc the parameter size */ - *pparams = (char *)SMB_REALLOC(*pparams,2); - if (*pparams == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; } - params = *pparams; - - SSVAL(params,0,0); - status = smbd_do_setfilepathinfo(conn, req, req, - info_level, - fsp, - smb_fname, - ppdata, total_data, - &data_return_size); + if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ @@ -7743,9 +7118,10 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } + SSVAL(params,0,0); send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size, max_data_bytes); - + return; } @@ -7758,16 +7134,16 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, char **ppdata, int total_data, unsigned int max_data_bytes) { - struct smb_filename *smb_dname = NULL; char *params = *pparams; char *pdata = *ppdata; char *directory = NULL; + SMB_STRUCT_STAT sbuf; NTSTATUS status = NT_STATUS_OK; struct ea_list *ea_list = NULL; TALLOC_CTX *ctx = talloc_tos(); if (!CAN_WRITE(conn)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRSRV, ERRaccess); return; } @@ -7786,29 +7162,38 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); - status = filename_convert(ctx, + status = resolve_dfspath(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, - 0, - NULL, - &smb_dname); - + &directory); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - return; + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); } reply_nterror(req, status); return; - } + } + + status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(5,("call_trans2mkdir error (%s)\n", nt_errstr(status))); + reply_nterror(req, status); + return; + } /* Any data in this call is an EA list. */ if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) { reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); - goto out; + return; } /* @@ -7820,21 +7205,21 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, if (total_data != 4) { if (total_data < 10) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } if (IVAL(pdata,0) > total_data) { DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n", IVAL(pdata,0), (unsigned int)total_data)); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } ea_list = read_ea_list(talloc_tos(), pdata + 4, total_data - 4); if (!ea_list) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - goto out; + return; } } /* If total_data == 4 Windows doesn't care what values @@ -7842,19 +7227,19 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, * The System i QNTC IBM SMB client puts bad values here, * so ignore them. */ - status = create_directory(conn, req, smb_dname); + status = create_directory(conn, req, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + return; } - + /* Try and set any given EA. */ if (ea_list) { - status = set_ea(conn, NULL, smb_dname, ea_list); + status = set_ea(conn, NULL, directory, ea_list); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - goto out; + return; } } @@ -7862,16 +7247,14 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, *pparams = (char *)SMB_REALLOC(*pparams,2); if(*pparams == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; + return; } params = *pparams; SSVAL(params,0,0); send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes); - - out: - TALLOC_FREE(smb_dname); + return; } @@ -7924,7 +7307,7 @@ static void call_trans2findnotifyfirst(connection_struct *conn, fnf_handle = 257; send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes); - + return; } @@ -7955,7 +7338,7 @@ static void call_trans2findnotifynext(connection_struct *conn, SSVAL(params,2,0); /* No EA errors */ send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes); - + return; } @@ -7986,7 +7369,7 @@ static void call_trans2getdfsreferral(connection_struct *conn, max_referral_level = SVAL(params,0); if(!lp_host_msdfs()) { - reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + reply_doserror(req, ERRDOS, ERRbadfunc); return; } @@ -8028,7 +7411,7 @@ static void call_trans2ioctl(connection_struct *conn, /* check for an invalid fid before proceeding */ if (!fsp) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); + reply_doserror(req, ERRDOS, ERRbadfid); return; } @@ -8057,7 +7440,7 @@ static void call_trans2ioctl(connection_struct *conn, } DEBUG(2,("Unknown TRANS2_IOCTL\n")); - reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + reply_doserror(req, ERRSRV, ERRerror); } /**************************************************************************** @@ -8067,7 +7450,6 @@ static void call_trans2ioctl(connection_struct *conn, void reply_findclose(struct smb_request *req) { int dptr_num; - struct smbd_server_connection *sconn = smbd_server_conn; START_PROFILE(SMBfindclose); @@ -8081,7 +7463,7 @@ void reply_findclose(struct smb_request *req) DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num)); - dptr_close(sconn, &dptr_num); + dptr_close(&dptr_num); reply_outbuf(req, 0, 0); @@ -8106,7 +7488,7 @@ void reply_findnclose(struct smb_request *req) END_PROFILE(SMBfindnclose); return; } - + dptr_num = SVAL(req->vwv+0, 0); DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num)); @@ -8126,7 +7508,7 @@ void reply_findnclose(struct smb_request *req) static void handle_trans2(connection_struct *conn, struct smb_request *req, struct trans_state *state) { - if (get_Protocol() >= PROTOCOL_NT1) { + if (Protocol >= PROTOCOL_NT1) { req->flags2 |= 0x40; /* IS_LONG_NAME */ SSVAL(req->inbuf,smb_flg2,req->flags2); } @@ -8283,7 +7665,7 @@ static void handle_trans2(connection_struct *conn, struct smb_request *req, default: /* Error in request */ DEBUG(2,("Unknown request %d in trans2 call\n", state->call)); - reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + reply_doserror(req, ERRSRV,ERRerror); } } @@ -8335,7 +7717,7 @@ void reply_trans2(struct smb_request *req) case TRANSACT2_SETFSINFO: break; default: - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + reply_doserror(req, ERRSRV, ERRaccess); END_PROFILE(SMBtrans2); return; } @@ -8526,7 +7908,7 @@ void reply_transs2(struct smb_request *req) state->received_param += pcnt; state->received_data += dcnt; - + if ((state->received_data > state->total_data) || (state->received_param > state->total_param)) goto bad_param; diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 2ec50cd4d8..72837ff967 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -224,8 +224,7 @@ void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid) bool change_to_user(connection_struct *conn, uint16 vuid) { const struct auth_serversupplied_info *server_info = NULL; - struct smbd_server_connection *sconn = smbd_server_conn; - user_struct *vuser = get_valid_user_struct(sconn, vuid); + user_struct *vuser = get_valid_user_struct(vuid); int snum; gid_t gid; uid_t uid; diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 0dd5bb98f7..fd7f91f361 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -5,7 +5,6 @@ Copyright (C) Tim Potter 1999 Copyright (C) Alexander Bokovoy 2002 Copyright (C) James Peach 2006 - Copyright (C) Volker Lendecke 2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,8 +32,8 @@ static_decl_vfs; struct vfs_init_function_entry { char *name; + const vfs_op_tuple *vfs_op_tuples; struct vfs_init_function_entry *prev, *next; - const struct vfs_fn_pointers *fns; }; /**************************************************************************** @@ -46,7 +45,7 @@ static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name) struct vfs_init_function_entry *entry = backends; DEBUG(10, ("vfs_find_backend_entry called for %s\n", name)); - + while(entry) { if (strcmp(entry->name, name)==0) return entry; entry = entry->next; @@ -55,8 +54,7 @@ static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name) return NULL; } -NTSTATUS smb_register_vfs(int version, const char *name, - const struct vfs_fn_pointers *fns) +NTSTATUS smb_register_vfs(int version, const char *name, const vfs_op_tuple *vfs_op_tuples) { struct vfs_init_function_entry *entry = backends; @@ -69,7 +67,7 @@ NTSTATUS smb_register_vfs(int version, const char *name, return NT_STATUS_OBJECT_TYPE_MISMATCH; } - if (!name || !name[0]) { + if (!name || !name[0] || !vfs_op_tuples) { DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n")); return NT_STATUS_INVALID_PARAMETER; } @@ -81,7 +79,7 @@ NTSTATUS smb_register_vfs(int version, const char *name, entry = SMB_XMALLOC_P(struct vfs_init_function_entry); entry->name = smb_xstrdup(name); - entry->fns = fns; + entry->vfs_op_tuples = vfs_op_tuples; DLIST_ADD(backends, entry); DEBUG(5, ("Successfully added vfs backend '%s'\n", name)); @@ -102,14 +100,23 @@ static void vfs_init_default(connection_struct *conn) initialise custom vfs hooks ****************************************************************************/ +static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which, + struct vfs_handle_struct * handle, void * op) +{ + ((struct vfs_handle_struct **)&vfs->handles)[which] = handle; + ((void **)(void *)&vfs->ops)[which] = op; +} + bool vfs_init_custom(connection_struct *conn, const char *vfs_object) { + const vfs_op_tuple *ops; char *module_path = NULL; char *module_name = NULL; char *module_param = NULL, *p; + int i; vfs_handle_struct *handle; const struct vfs_init_function_entry *entry; - + if (!conn||!vfs_object||!vfs_object[0]) { DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n")); return False; @@ -154,41 +161,47 @@ bool vfs_init_custom(connection_struct *conn, const char *vfs_object) } /* First, try to load the module with the new module system */ - entry = vfs_find_backend_entry(module_name); - if (!entry) { - NTSTATUS status; - - DEBUG(5, ("vfs module [%s] not loaded - trying to load...\n", - vfs_object)); - - status = smb_probe_module("vfs", module_path); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("error probing vfs module '%s': %s\n", - module_path, nt_errstr(status))); + if((entry = vfs_find_backend_entry(module_name)) || + (NT_STATUS_IS_OK(smb_probe_module("vfs", module_path)) && + (entry = vfs_find_backend_entry(module_name)))) { + + DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object)); + + if ((ops = entry->vfs_op_tuples) == NULL) { + DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object)); goto fail; - } - - entry = vfs_find_backend_entry(module_name); - if (!entry) { - DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object)); - goto fail; - } + } + } else { + DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object)); + goto fail; } - DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object)); - handle = TALLOC_ZERO_P(conn, vfs_handle_struct); if (!handle) { DEBUG(0,("TALLOC_ZERO() failed!\n")); goto fail; } + memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops)); handle->conn = conn; - handle->fns = entry->fns; if (module_param) { handle->param = talloc_strdup(conn, module_param); } DLIST_ADD(conn->vfs_handles, handle); + for(i=0; ops[i].op != NULL; i++) { + DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer)); + if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) { + /* If this operation was already made opaque by different module, it + * will be overridden here. + */ + DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object)); + vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op); + } + /* Change current VFS disposition*/ + DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object)); + vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op); + } + SAFE_FREE(module_path); SAFE_FREE(module_name); return True; @@ -291,7 +304,7 @@ bool smbd_vfs_init(connection_struct *conn) const char **vfs_objects; unsigned int i = 0; int j = 0; - + /* Normal share - initialise with disk access functions */ vfs_init_default(conn); vfs_objects = lp_vfs_objects(SNUM(conn)); @@ -299,7 +312,7 @@ bool smbd_vfs_init(connection_struct *conn) /* Override VFS functions if 'vfs object' was not specified*/ if (!vfs_objects || !vfs_objects[0]) return True; - + for (i=0; vfs_objects[i] ;) { i++; } @@ -314,18 +327,61 @@ bool smbd_vfs_init(connection_struct *conn) } /******************************************************************* + Check if directory exists. +********************************************************************/ + +bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st) +{ + SMB_STRUCT_STAT st2; + bool ret; + + if (!st) + st = &st2; + + if (SMB_VFS_STAT(conn,dname,st) != 0) + return(False); + + ret = S_ISDIR(st->st_mode); + if(!ret) + errno = ENOTDIR; + + return ret; +} + +/******************************************************************* + Check if an object exists in the vfs. +********************************************************************/ + +bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf) +{ + SMB_STRUCT_STAT st; + + if (!sbuf) + sbuf = &st; + + ZERO_STRUCTP(sbuf); + + if (SMB_VFS_STAT(conn,fname,sbuf) == -1) + return(False); + return True; +} + +/******************************************************************* Check if a file exists in the vfs. ********************************************************************/ -NTSTATUS vfs_file_exist(connection_struct *conn, struct smb_filename *smb_fname) +bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf) { - /* Only return OK if stat was successful and S_ISREG */ - if ((SMB_VFS_STAT(conn, smb_fname) != -1) && - S_ISREG(smb_fname->st.st_ex_mode)) { - return NT_STATUS_OK; - } + SMB_STRUCT_STAT st; + + if (!sbuf) + sbuf = &st; - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + ZERO_STRUCTP(sbuf); + + if (SMB_VFS_STAT(conn,fname,sbuf) == -1) + return False; + return(S_ISREG(sbuf->st_mode)); } /**************************************************************************** @@ -462,12 +518,10 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len) * Actually try and commit the space on disk.... */ - DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", - fsp_str_dbg(fsp), (double)len)); + DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len )); if (((SMB_OFF_T)len) < 0) { - DEBUG(0,("vfs_allocate_file_space: %s negative len " - "requested.\n", fsp_str_dbg(fsp))); + DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name )); errno = EINVAL; return -1; } @@ -476,15 +530,14 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len) if (ret == -1) return ret; - if (len == (uint64_t)st.st_ex_size) + if (len == (uint64_t)st.st_size) return 0; - if (len < (uint64_t)st.st_ex_size) { + if (len < (uint64_t)st.st_size) { /* Shrink - use ftruncate. */ - DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current " - "size %.0f\n", fsp_str_dbg(fsp), - (double)st.st_ex_size)); + DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n", + fsp->fsp_name, (double)st.st_size )); contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK); @@ -506,18 +559,15 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len) if (!lp_strict_allocate(SNUM(fsp->conn))) return 0; - len -= st.st_ex_size; + len -= st.st_size; len /= 1024; /* Len is now number of 1k blocks needed. */ - space_avail = get_dfree_info(conn, fsp->fsp_name->base_name, false, - &bsize, &dfree, &dsize); + space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize); if (space_avail == (uint64_t)-1) { return -1; } - DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, " - "needed blocks = %.0f, space avail = %.0f\n", - fsp_str_dbg(fsp), (double)st.st_ex_size, (double)len, - (double)space_avail)); + DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n", + fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail )); if (len > space_avail) { errno = ENOSPC; @@ -539,15 +589,14 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len) contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN); - DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", - fsp_str_dbg(fsp), (double)len)); + DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len)); flush_write_cache(fsp, SIZECHANGE_FLUSH); if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) { set_filelen_write_cache(fsp, len); notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, - fsp->fsp_name->base_name); + fsp->fsp_name); } contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN); @@ -578,14 +627,12 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) return ret; } - if (len <= st.st_ex_size) { + if (len <= st.st_size) { return 0; } - DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to " - "len %.0f (%.0f bytes)\n", fsp_str_dbg(fsp), - (double)st.st_ex_size, (double)len, - (double)(len - st.st_ex_size))); + DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n", + fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size))); contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE); @@ -600,8 +647,8 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) } } - offset = st.st_ex_size; - num_to_write = len - st.st_ex_size; + offset = st.st_size; + num_to_write = len - st.st_size; total = 0; while (total < num_to_write) { @@ -609,9 +656,8 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total); if (pwrite_ret == -1) { - DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file " - "%s failed with error %s\n", - fsp_str_dbg(fsp), strerror(errno))); + DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n", + fsp->fsp_name, strerror(errno) )); ret = -1; goto out; } @@ -659,13 +705,10 @@ SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n) A vfs_readdir wrapper which just returns the file name. ********************************************************************/ -const char *vfs_readdirname(connection_struct *conn, void *p, - SMB_STRUCT_STAT *sbuf, char **talloced) +char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf) { SMB_STRUCT_DIRENT *ptr= NULL; - const char *dname; - char *translated; - NTSTATUS status; + char *dname; if (!p) return(NULL); @@ -676,7 +719,6 @@ const char *vfs_readdirname(connection_struct *conn, void *p, dname = ptr->d_name; - #ifdef NEXT2 if (telldir(p) < 0) return(NULL); @@ -687,17 +729,7 @@ const char *vfs_readdirname(connection_struct *conn, void *p, dname = dname - 2; #endif - status = SMB_VFS_TRANSLATE_NAME(conn, dname, vfs_translate_to_windows, - talloc_tos(), &translated); - if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { - *talloced = NULL; - return dname; - } - *talloced = translated; - if (!NT_STATUS_IS_OK(status)) { - return NULL; - } - return translated; + return(dname); } /******************************************************************* @@ -737,12 +769,10 @@ int vfs_ChDir(connection_struct *conn, const char *path) char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) { char s[PATH_MAX+1]; - char *result = NULL; + SMB_STRUCT_STAT st, st2; + char *result; DATA_BLOB cache_value; struct file_id key; - struct smb_filename *smb_fname_dot = NULL; - struct smb_filename *smb_fname_full = NULL; - NTSTATUS status; *s = 0; @@ -750,14 +780,9 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) goto nocache; } - status = create_synthetic_smb_fname(ctx, ".", NULL, NULL, - &smb_fname_dot); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - goto out; - } + SET_STAT_INVALID(st); - if (SMB_VFS_STAT(conn, smb_fname_dot) == -1) { + if (SMB_VFS_STAT(conn, ".",&st) == -1) { /* * Known to fail for root: the directory may be NFS-mounted * and exported with root_squash (so has no root access). @@ -767,7 +792,7 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) goto nocache; } - key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st); + key = vfs_file_id_from_sbuf(conn, &st); if (!memcache_lookup(smbd_memcache(), GETWD_CACHE, data_blob_const(&key, sizeof(key)), @@ -778,25 +803,17 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) SMB_ASSERT((cache_value.length > 0) && (cache_value.data[cache_value.length-1] == '\0')); - status = create_synthetic_smb_fname(ctx, (char *)cache_value.data, - NULL, NULL, &smb_fname_full); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - goto out; - } - - if ((SMB_VFS_STAT(conn, smb_fname_full) == 0) && - (smb_fname_dot->st.st_ex_dev == smb_fname_full->st.st_ex_dev) && - (smb_fname_dot->st.st_ex_ino == smb_fname_full->st.st_ex_ino) && - (S_ISDIR(smb_fname_dot->st.st_ex_mode))) { + if ((SMB_VFS_STAT(conn, (char *)cache_value.data, &st2) == 0) + && (st.st_dev == st2.st_dev) && (st.st_ino == st2.st_ino) + && (S_ISDIR(st.st_mode))) { /* * Ok, we're done */ - result = talloc_strdup(ctx, smb_fname_full->base_name); + result = talloc_strdup(ctx, (char *)cache_value.data); if (result == NULL) { errno = ENOMEM; } - goto out; + return result; } nocache: @@ -810,11 +827,11 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) if (!SMB_VFS_GETWD(conn,s)) { DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n", strerror(errno))); - goto out; + return NULL; } - if (lp_getwd_cache() && VALID_STAT(smb_fname_dot->st)) { - key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st); + if (lp_getwd_cache() && VALID_STAT(st)) { + key = vfs_file_id_from_sbuf(conn, &st); memcache_add(smbd_memcache(), GETWD_CACHE, data_blob_const(&key, sizeof(key)), @@ -825,10 +842,6 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) if (result == NULL) { errno = ENOMEM; } - - out: - TALLOC_FREE(smb_fname_dot); - TALLOC_FREE(smb_fname_full); return result; } @@ -846,9 +859,10 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) bool free_resolved_name = False; #endif char *resolved_name = NULL; + size_t con_path_len = strlen(conn->connectpath); char *p = NULL; - DEBUG(3,("check_reduced_name [%s] [%s]\n", fname, conn->connectpath)); + DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath)); #ifdef REALPATH_TAKES_NULL resolved_name = SMB_VFS_REALPATH(conn,fname,NULL); @@ -859,10 +873,8 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) if (!resolved_name) { switch (errno) { case ENOTDIR: - DEBUG(3,("check_reduced_name: Component not a " - "directory in getting realpath for " - "%s\n", fname)); - return NT_STATUS_OBJECT_PATH_NOT_FOUND; + DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname)); + return map_nt_error_from_unix(errno); case ENOENT: { TALLOC_CTX *ctx = talloc_tos(); @@ -893,18 +905,8 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf); #endif if (!resolved_name) { - NTSTATUS status = map_nt_error_from_unix(errno); - - if (errno == ENOENT || errno == ENOTDIR) { - status = NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - DEBUG(3,("check_reduce_named: " - "couldn't get realpath for " - "%s (%s)\n", - fname, - nt_errstr(status))); - return status; + DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname)); + return map_nt_error_from_unix(errno); } tmp_fname = talloc_asprintf(ctx, "%s/%s", @@ -917,8 +919,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) SAFE_FREE(resolved_name); resolved_name = SMB_STRDUP(tmp_fname); if (!resolved_name) { - DEBUG(0, ("check_reduced_name: malloc " - "fail for %s\n", tmp_fname)); + DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname)); return NT_STATUS_NO_MEMORY; } #else @@ -928,18 +929,15 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) break; } default: - DEBUG(1,("check_reduced_name: couldn't get " - "realpath for %s\n", fname)); + DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname)); return map_nt_error_from_unix(errno); } } - DEBUG(10,("check_reduced_name realpath [%s] -> [%s]\n", fname, - resolved_name)); + DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name)); if (*resolved_name != '/') { - DEBUG(0,("check_reduced_name: realpath doesn't return " - "absolute paths !\n")); + DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n")); if (free_resolved_name) { SAFE_FREE(resolved_name); } @@ -947,29 +945,12 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) } /* Check for widelinks allowed. */ - if (!lp_widelinks(SNUM(conn))) { - const char *conn_rootdir; - - conn_rootdir = SMB_VFS_CONNECTPATH(conn, fname); - if (conn_rootdir == NULL) { - DEBUG(2, ("check_reduced_name: Could not get " - "conn_rootdir\n")); - if (free_resolved_name) { - SAFE_FREE(resolved_name); - } - return NT_STATUS_ACCESS_DENIED; - } - - if (strncmp(conn_rootdir, resolved_name, - strlen(conn_rootdir)) != 0) { - DEBUG(2, ("check_reduced_name: Bad access " - "attempt: %s is a symlink outside the " - "share path\n", fname)); - if (free_resolved_name) { - SAFE_FREE(resolved_name); - } - return NT_STATUS_ACCESS_DENIED; - } + if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) { + DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path\n", fname)); + if (free_resolved_name) { + SAFE_FREE(resolved_name); + } + return NT_STATUS_ACCESS_DENIED; } /* Check if we are allowing users to follow symlinks */ @@ -978,967 +959,21 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) #ifdef S_ISLNK if (!lp_symlinks(SNUM(conn))) { - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - - status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - if (free_resolved_name) { - SAFE_FREE(resolved_name); - } - return status; - } - - if ( (SMB_VFS_LSTAT(conn, smb_fname) != -1) && - (S_ISLNK(smb_fname->st.st_ex_mode)) ) { + SMB_STRUCT_STAT statbuf; + if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) && + (S_ISLNK(statbuf.st_mode)) ) { if (free_resolved_name) { SAFE_FREE(resolved_name); } - DEBUG(3,("check_reduced_name: denied: file path name " - "%s is a symlink\n",resolved_name)); - TALLOC_FREE(smb_fname); + DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name)); return NT_STATUS_ACCESS_DENIED; } - TALLOC_FREE(smb_fname); } #endif - DEBUG(3,("check_reduced_name: %s reduced to %s\n", fname, - resolved_name)); + DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name)); if (free_resolved_name) { SAFE_FREE(resolved_name); } return NT_STATUS_OK; } - -/** - * XXX: This is temporary and there should be no callers of this once - * smb_filename is plumbed through all path based operations. - */ -int vfs_stat_smb_fname(struct connection_struct *conn, const char *fname, - SMB_STRUCT_STAT *psbuf) -{ - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - int ret; - - status = create_synthetic_smb_fname_split(talloc_tos(), fname, NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - if (lp_posix_pathnames()) { - ret = SMB_VFS_LSTAT(conn, smb_fname); - } else { - ret = SMB_VFS_STAT(conn, smb_fname); - } - - if (ret != -1) { - *psbuf = smb_fname->st; - } - - TALLOC_FREE(smb_fname); - return ret; -} - -/** - * XXX: This is temporary and there should be no callers of this once - * smb_filename is plumbed through all path based operations. - */ -int vfs_lstat_smb_fname(struct connection_struct *conn, const char *fname, - SMB_STRUCT_STAT *psbuf) -{ - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - int ret; - - status = create_synthetic_smb_fname_split(talloc_tos(), fname, NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - ret = SMB_VFS_LSTAT(conn, smb_fname); - if (ret != -1) { - *psbuf = smb_fname->st; - } - - TALLOC_FREE(smb_fname); - return ret; -} - -/** - * Ensure LSTAT is called for POSIX paths. - */ - -NTSTATUS vfs_stat_fsp(files_struct *fsp) -{ - int ret; - - if(fsp->is_directory || fsp->fh->fd == -1) { - if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name); - } else { - ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name); - } - if (ret == -1) { - return map_nt_error_from_unix(errno); - } - } else { - if(SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) { - return map_nt_error_from_unix(errno); - } - } - return NT_STATUS_OK; -} - -/* - generate a file_id from a stat structure - */ -struct file_id vfs_file_id_from_sbuf(connection_struct *conn, const SMB_STRUCT_STAT *sbuf) -{ - return SMB_VFS_FILE_ID_CREATE(conn, sbuf); -} - -int smb_vfs_call_connect(struct vfs_handle_struct *handle, - const char *service, const char *user) -{ - VFS_FIND(connect_fn); - return handle->fns->connect_fn(handle, service, user); -} - -void smb_vfs_call_disconnect(struct vfs_handle_struct *handle) -{ - VFS_FIND(disconnect); - handle->fns->disconnect(handle); -} - -uint64_t smb_vfs_call_disk_free(struct vfs_handle_struct *handle, - const char *path, bool small_query, - uint64_t *bsize, uint64_t *dfree, - uint64_t *dsize) -{ - VFS_FIND(disk_free); - return handle->fns->disk_free(handle, path, small_query, bsize, dfree, - dsize); -} - -int smb_vfs_call_get_quota(struct vfs_handle_struct *handle, - enum SMB_QUOTA_TYPE qtype, unid_t id, - SMB_DISK_QUOTA *qt) -{ - VFS_FIND(get_quota); - return handle->fns->get_quota(handle, qtype, id, qt); -} - -int smb_vfs_call_set_quota(struct vfs_handle_struct *handle, - enum SMB_QUOTA_TYPE qtype, unid_t id, - SMB_DISK_QUOTA *qt) -{ - VFS_FIND(set_quota); - return handle->fns->set_quota(handle, qtype, id, qt); -} - -int smb_vfs_call_get_shadow_copy_data(struct vfs_handle_struct *handle, - struct files_struct *fsp, - SHADOW_COPY_DATA *shadow_copy_data, - bool labels) -{ - VFS_FIND(get_shadow_copy_data); - return handle->fns->get_shadow_copy_data(handle, fsp, shadow_copy_data, - labels); -} -int smb_vfs_call_statvfs(struct vfs_handle_struct *handle, const char *path, - struct vfs_statvfs_struct *statbuf) -{ - VFS_FIND(statvfs); - return handle->fns->statvfs(handle, path, statbuf); -} - -uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle, - enum timestamp_set_resolution *p_ts_res) -{ - VFS_FIND(fs_capabilities); - return handle->fns->fs_capabilities(handle, p_ts_res); -} - -SMB_STRUCT_DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle, - const char *fname, const char *mask, - uint32 attributes) -{ - VFS_FIND(opendir); - return handle->fns->opendir(handle, fname, mask, attributes); -} - -SMB_STRUCT_DIRENT *smb_vfs_call_readdir(struct vfs_handle_struct *handle, - SMB_STRUCT_DIR *dirp, - SMB_STRUCT_STAT *sbuf) -{ - VFS_FIND(readdir); - return handle->fns->readdir(handle, dirp, sbuf); -} - -void smb_vfs_call_seekdir(struct vfs_handle_struct *handle, - SMB_STRUCT_DIR *dirp, long offset) -{ - VFS_FIND(seekdir); - handle->fns->seekdir(handle, dirp, offset); -} - -long smb_vfs_call_telldir(struct vfs_handle_struct *handle, - SMB_STRUCT_DIR *dirp) -{ - VFS_FIND(telldir); - return handle->fns->telldir(handle, dirp); -} - -void smb_vfs_call_rewind_dir(struct vfs_handle_struct *handle, - SMB_STRUCT_DIR *dirp) -{ - VFS_FIND(rewind_dir); - handle->fns->rewind_dir(handle, dirp); -} - -int smb_vfs_call_mkdir(struct vfs_handle_struct *handle, const char *path, - mode_t mode) -{ - VFS_FIND(mkdir); - return handle->fns->mkdir(handle, path, mode); -} - -int smb_vfs_call_rmdir(struct vfs_handle_struct *handle, const char *path) -{ - VFS_FIND(rmdir); - return handle->fns->rmdir(handle, path); -} - -int smb_vfs_call_closedir(struct vfs_handle_struct *handle, - SMB_STRUCT_DIR *dir) -{ - VFS_FIND(closedir); - return handle->fns->closedir(handle, dir); -} - -void smb_vfs_call_init_search_op(struct vfs_handle_struct *handle, - SMB_STRUCT_DIR *dirp) -{ - VFS_FIND(init_search_op); - handle->fns->init_search_op(handle, dirp); -} - -int smb_vfs_call_open(struct vfs_handle_struct *handle, - struct smb_filename *smb_fname, struct files_struct *fsp, - int flags, mode_t mode) -{ - VFS_FIND(open); - return handle->fns->open(handle, smb_fname, fsp, flags, mode); -} - -NTSTATUS smb_vfs_call_create_file(struct vfs_handle_struct *handle, - struct smb_request *req, - uint16_t root_dir_fid, - struct smb_filename *smb_fname, - uint32_t access_mask, - uint32_t share_access, - uint32_t create_disposition, - uint32_t create_options, - uint32_t file_attributes, - uint32_t oplock_request, - uint64_t allocation_size, - struct security_descriptor *sd, - struct ea_list *ea_list, - files_struct **result, - int *pinfo) -{ - VFS_FIND(create_file); - return handle->fns->create_file( - handle, req, root_dir_fid, smb_fname, access_mask, - share_access, create_disposition, create_options, - file_attributes, oplock_request, allocation_size, sd, ea_list, - result, pinfo); -} - -int smb_vfs_call_close_fn(struct vfs_handle_struct *handle, - struct files_struct *fsp) -{ - VFS_FIND(close_fn); - return handle->fns->close_fn(handle, fsp); -} - -ssize_t smb_vfs_call_vfs_read(struct vfs_handle_struct *handle, - struct files_struct *fsp, void *data, size_t n) -{ - VFS_FIND(vfs_read); - return handle->fns->vfs_read(handle, fsp, data, n); -} - -ssize_t smb_vfs_call_pread(struct vfs_handle_struct *handle, - struct files_struct *fsp, void *data, size_t n, - SMB_OFF_T offset) -{ - VFS_FIND(pread); - return handle->fns->pread(handle, fsp, data, n, offset); -} - -ssize_t smb_vfs_call_write(struct vfs_handle_struct *handle, - struct files_struct *fsp, const void *data, - size_t n) -{ - VFS_FIND(write); - return handle->fns->write(handle, fsp, data, n); -} - -ssize_t smb_vfs_call_pwrite(struct vfs_handle_struct *handle, - struct files_struct *fsp, const void *data, - size_t n, SMB_OFF_T offset) -{ - VFS_FIND(pwrite); - return handle->fns->pwrite(handle, fsp, data, n, offset); -} - -SMB_OFF_T smb_vfs_call_lseek(struct vfs_handle_struct *handle, - struct files_struct *fsp, SMB_OFF_T offset, - int whence) -{ - VFS_FIND(lseek); - return handle->fns->lseek(handle, fsp, offset, whence); -} - -ssize_t smb_vfs_call_sendfile(struct vfs_handle_struct *handle, int tofd, - files_struct *fromfsp, const DATA_BLOB *header, - SMB_OFF_T offset, size_t count) -{ - VFS_FIND(sendfile); - return handle->fns->sendfile(handle, tofd, fromfsp, header, offset, - count); -} - -ssize_t smb_vfs_call_recvfile(struct vfs_handle_struct *handle, int fromfd, - files_struct *tofsp, SMB_OFF_T offset, - size_t count) -{ - VFS_FIND(recvfile); - return handle->fns->recvfile(handle, fromfd, tofsp, offset, count); -} - -int smb_vfs_call_rename(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname_src, - const struct smb_filename *smb_fname_dst) -{ - VFS_FIND(rename); - return handle->fns->rename(handle, smb_fname_src, smb_fname_dst); -} - -int smb_vfs_call_fsync(struct vfs_handle_struct *handle, - struct files_struct *fsp) -{ - VFS_FIND(fsync); - return handle->fns->fsync(handle, fsp); -} - -int smb_vfs_call_stat(struct vfs_handle_struct *handle, - struct smb_filename *smb_fname) -{ - VFS_FIND(stat); - return handle->fns->stat(handle, smb_fname); -} - -int smb_vfs_call_fstat(struct vfs_handle_struct *handle, - struct files_struct *fsp, SMB_STRUCT_STAT *sbuf) -{ - VFS_FIND(fstat); - return handle->fns->fstat(handle, fsp, sbuf); -} - -int smb_vfs_call_lstat(struct vfs_handle_struct *handle, - struct smb_filename *smb_filename) -{ - VFS_FIND(lstat); - return handle->fns->lstat(handle, smb_filename); -} - -uint64_t smb_vfs_call_get_alloc_size(struct vfs_handle_struct *handle, - struct files_struct *fsp, - const SMB_STRUCT_STAT *sbuf) -{ - VFS_FIND(get_alloc_size); - return handle->fns->get_alloc_size(handle, fsp, sbuf); -} - -int smb_vfs_call_unlink(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname) -{ - VFS_FIND(unlink); - return handle->fns->unlink(handle, smb_fname); -} - -int smb_vfs_call_chmod(struct vfs_handle_struct *handle, const char *path, - mode_t mode) -{ - VFS_FIND(chmod); - return handle->fns->chmod(handle, path, mode); -} - -int smb_vfs_call_fchmod(struct vfs_handle_struct *handle, - struct files_struct *fsp, mode_t mode) -{ - VFS_FIND(fchmod); - return handle->fns->fchmod(handle, fsp, mode); -} - -int smb_vfs_call_chown(struct vfs_handle_struct *handle, const char *path, - uid_t uid, gid_t gid) -{ - VFS_FIND(chown); - return handle->fns->chown(handle, path, uid, gid); -} - -int smb_vfs_call_fchown(struct vfs_handle_struct *handle, - struct files_struct *fsp, uid_t uid, gid_t gid) -{ - VFS_FIND(fchown); - return handle->fns->fchown(handle, fsp, uid, gid); -} - -int smb_vfs_call_lchown(struct vfs_handle_struct *handle, const char *path, - uid_t uid, gid_t gid) -{ - VFS_FIND(lchown); - return handle->fns->lchown(handle, path, uid, gid); -} - -int smb_vfs_call_chdir(struct vfs_handle_struct *handle, const char *path) -{ - VFS_FIND(chdir); - return handle->fns->chdir(handle, path); -} - -char *smb_vfs_call_getwd(struct vfs_handle_struct *handle, char *buf) -{ - VFS_FIND(getwd); - return handle->fns->getwd(handle, buf); -} - -int smb_vfs_call_ntimes(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname, - struct smb_file_time *ft) -{ - VFS_FIND(ntimes); - return handle->fns->ntimes(handle, smb_fname, ft); -} - -int smb_vfs_call_ftruncate(struct vfs_handle_struct *handle, - struct files_struct *fsp, SMB_OFF_T offset) -{ - VFS_FIND(ftruncate); - return handle->fns->ftruncate(handle, fsp, offset); -} - -int smb_vfs_call_kernel_flock(struct vfs_handle_struct *handle, - struct files_struct *fsp, uint32 share_mode, - uint32_t access_mask) -{ - VFS_FIND(kernel_flock); - return handle->fns->kernel_flock(handle, fsp, share_mode, - access_mask); -} - -int smb_vfs_call_linux_setlease(struct vfs_handle_struct *handle, - struct files_struct *fsp, int leasetype) -{ - VFS_FIND(linux_setlease); - return handle->fns->linux_setlease(handle, fsp, leasetype); -} - -int smb_vfs_call_symlink(struct vfs_handle_struct *handle, const char *oldpath, - const char *newpath) -{ - VFS_FIND(symlink); - return handle->fns->symlink(handle, oldpath, newpath); -} - -int smb_vfs_call_vfs_readlink(struct vfs_handle_struct *handle, - const char *path, char *buf, size_t bufsiz) -{ - VFS_FIND(vfs_readlink); - return handle->fns->vfs_readlink(handle, path, buf, bufsiz); -} - -int smb_vfs_call_link(struct vfs_handle_struct *handle, const char *oldpath, - const char *newpath) -{ - VFS_FIND(link); - return handle->fns->link(handle, oldpath, newpath); -} - -int smb_vfs_call_mknod(struct vfs_handle_struct *handle, const char *path, - mode_t mode, SMB_DEV_T dev) -{ - VFS_FIND(mknod); - return handle->fns->mknod(handle, path, mode, dev); -} - -char *smb_vfs_call_realpath(struct vfs_handle_struct *handle, - const char *path, char *resolved_path) -{ - VFS_FIND(realpath); - return handle->fns->realpath(handle, path, resolved_path); -} - -NTSTATUS smb_vfs_call_notify_watch(struct vfs_handle_struct *handle, - struct sys_notify_context *ctx, - struct notify_entry *e, - void (*callback)(struct sys_notify_context *ctx, - void *private_data, - struct notify_event *ev), - void *private_data, void *handle_p) -{ - VFS_FIND(notify_watch); - return handle->fns->notify_watch(handle, ctx, e, callback, - private_data, handle_p); -} - -int smb_vfs_call_chflags(struct vfs_handle_struct *handle, const char *path, - unsigned int flags) -{ - VFS_FIND(chflags); - return handle->fns->chflags(handle, path, flags); -} - -struct file_id smb_vfs_call_file_id_create(struct vfs_handle_struct *handle, - const SMB_STRUCT_STAT *sbuf) -{ - VFS_FIND(file_id_create); - return handle->fns->file_id_create(handle, sbuf); -} - -NTSTATUS smb_vfs_call_streaminfo(struct vfs_handle_struct *handle, - struct files_struct *fsp, - const char *fname, - TALLOC_CTX *mem_ctx, - unsigned int *num_streams, - struct stream_struct **streams) -{ - VFS_FIND(streaminfo); - return handle->fns->streaminfo(handle, fsp, fname, mem_ctx, - num_streams, streams); -} - -int smb_vfs_call_get_real_filename(struct vfs_handle_struct *handle, - const char *path, const char *name, - TALLOC_CTX *mem_ctx, char **found_name) -{ - VFS_FIND(get_real_filename); - return handle->fns->get_real_filename(handle, path, name, mem_ctx, - found_name); -} - -const char *smb_vfs_call_connectpath(struct vfs_handle_struct *handle, - const char *filename) -{ - VFS_FIND(connectpath); - return handle->fns->connectpath(handle, filename); -} - -bool smb_vfs_call_strict_lock(struct vfs_handle_struct *handle, - struct files_struct *fsp, - struct lock_struct *plock) -{ - VFS_FIND(strict_lock); - return handle->fns->strict_lock(handle, fsp, plock); -} - -void smb_vfs_call_strict_unlock(struct vfs_handle_struct *handle, - struct files_struct *fsp, - struct lock_struct *plock) -{ - VFS_FIND(strict_unlock); - handle->fns->strict_unlock(handle, fsp, plock); -} - -NTSTATUS smb_vfs_call_translate_name(struct vfs_handle_struct *handle, - const char *name, - enum vfs_translate_direction direction, - TALLOC_CTX *mem_ctx, - char **mapped_name) -{ - VFS_FIND(translate_name); - return handle->fns->translate_name(handle, name, direction, mem_ctx, - mapped_name); -} - -NTSTATUS smb_vfs_call_fget_nt_acl(struct vfs_handle_struct *handle, - struct files_struct *fsp, - uint32 security_info, - struct security_descriptor **ppdesc) -{ - VFS_FIND(fget_nt_acl); - return handle->fns->fget_nt_acl(handle, fsp, security_info, - ppdesc); -} - -NTSTATUS smb_vfs_call_get_nt_acl(struct vfs_handle_struct *handle, - const char *name, - uint32 security_info, - struct security_descriptor **ppdesc) -{ - VFS_FIND(get_nt_acl); - return handle->fns->get_nt_acl(handle, name, security_info, ppdesc); -} - -NTSTATUS smb_vfs_call_fset_nt_acl(struct vfs_handle_struct *handle, - struct files_struct *fsp, - uint32 security_info_sent, - const struct security_descriptor *psd) -{ - VFS_FIND(fset_nt_acl); - return handle->fns->fset_nt_acl(handle, fsp, security_info_sent, psd); -} - -int smb_vfs_call_chmod_acl(struct vfs_handle_struct *handle, const char *name, - mode_t mode) -{ - VFS_FIND(chmod_acl); - return handle->fns->chmod_acl(handle, name, mode); -} - -int smb_vfs_call_fchmod_acl(struct vfs_handle_struct *handle, - struct files_struct *fsp, mode_t mode) -{ - VFS_FIND(fchmod_acl); - return handle->fns->fchmod_acl(handle, fsp, mode); -} - -int smb_vfs_call_sys_acl_get_entry(struct vfs_handle_struct *handle, - SMB_ACL_T theacl, int entry_id, - SMB_ACL_ENTRY_T *entry_p) -{ - VFS_FIND(sys_acl_get_entry); - return handle->fns->sys_acl_get_entry(handle, theacl, entry_id, - entry_p); -} - -int smb_vfs_call_sys_acl_get_tag_type(struct vfs_handle_struct *handle, - SMB_ACL_ENTRY_T entry_d, - SMB_ACL_TAG_T *tag_type_p) -{ - VFS_FIND(sys_acl_get_tag_type); - return handle->fns->sys_acl_get_tag_type(handle, entry_d, tag_type_p); -} - -int smb_vfs_call_sys_acl_get_permset(struct vfs_handle_struct *handle, - SMB_ACL_ENTRY_T entry_d, - SMB_ACL_PERMSET_T *permset_p) -{ - VFS_FIND(sys_acl_get_permset); - return handle->fns->sys_acl_get_permset(handle, entry_d, permset_p); -} - -void * smb_vfs_call_sys_acl_get_qualifier(struct vfs_handle_struct *handle, - SMB_ACL_ENTRY_T entry_d) -{ - VFS_FIND(sys_acl_get_qualifier); - return handle->fns->sys_acl_get_qualifier(handle, entry_d); -} - -SMB_ACL_T smb_vfs_call_sys_acl_get_file(struct vfs_handle_struct *handle, - const char *path_p, - SMB_ACL_TYPE_T type) -{ - VFS_FIND(sys_acl_get_file); - return handle->fns->sys_acl_get_file(handle, path_p, type); -} - -SMB_ACL_T smb_vfs_call_sys_acl_get_fd(struct vfs_handle_struct *handle, - struct files_struct *fsp) -{ - VFS_FIND(sys_acl_get_fd); - return handle->fns->sys_acl_get_fd(handle, fsp); -} - -int smb_vfs_call_sys_acl_clear_perms(struct vfs_handle_struct *handle, - SMB_ACL_PERMSET_T permset) -{ - VFS_FIND(sys_acl_clear_perms); - return handle->fns->sys_acl_clear_perms(handle, permset); -} - -int smb_vfs_call_sys_acl_add_perm(struct vfs_handle_struct *handle, - SMB_ACL_PERMSET_T permset, - SMB_ACL_PERM_T perm) -{ - VFS_FIND(sys_acl_add_perm); - return handle->fns->sys_acl_add_perm(handle, permset, perm); -} - -char * smb_vfs_call_sys_acl_to_text(struct vfs_handle_struct *handle, - SMB_ACL_T theacl, ssize_t *plen) -{ - VFS_FIND(sys_acl_to_text); - return handle->fns->sys_acl_to_text(handle, theacl, plen); -} - -SMB_ACL_T smb_vfs_call_sys_acl_init(struct vfs_handle_struct *handle, - int count) -{ - VFS_FIND(sys_acl_init); - return handle->fns->sys_acl_init(handle, count); -} - -int smb_vfs_call_sys_acl_create_entry(struct vfs_handle_struct *handle, - SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) -{ - VFS_FIND(sys_acl_create_entry); - return handle->fns->sys_acl_create_entry(handle, pacl, pentry); -} - -int smb_vfs_call_sys_acl_set_tag_type(struct vfs_handle_struct *handle, - SMB_ACL_ENTRY_T entry, - SMB_ACL_TAG_T tagtype) -{ - VFS_FIND(sys_acl_set_tag_type); - return handle->fns->sys_acl_set_tag_type(handle, entry, tagtype); -} - -int smb_vfs_call_sys_acl_set_qualifier(struct vfs_handle_struct *handle, - SMB_ACL_ENTRY_T entry, void *qual) -{ - VFS_FIND(sys_acl_set_qualifier); - return handle->fns->sys_acl_set_qualifier(handle, entry, qual); -} - -int smb_vfs_call_sys_acl_set_permset(struct vfs_handle_struct *handle, - SMB_ACL_ENTRY_T entry, - SMB_ACL_PERMSET_T permset) -{ - VFS_FIND(sys_acl_set_permset); - return handle->fns->sys_acl_set_permset(handle, entry, permset); -} - -int smb_vfs_call_sys_acl_valid(struct vfs_handle_struct *handle, - SMB_ACL_T theacl) -{ - VFS_FIND(sys_acl_valid); - return handle->fns->sys_acl_valid(handle, theacl); -} - -int smb_vfs_call_sys_acl_set_file(struct vfs_handle_struct *handle, - const char *name, SMB_ACL_TYPE_T acltype, - SMB_ACL_T theacl) -{ - VFS_FIND(sys_acl_set_file); - return handle->fns->sys_acl_set_file(handle, name, acltype, theacl); -} - -int smb_vfs_call_sys_acl_set_fd(struct vfs_handle_struct *handle, - struct files_struct *fsp, SMB_ACL_T theacl) -{ - VFS_FIND(sys_acl_set_fd); - return handle->fns->sys_acl_set_fd(handle, fsp, theacl); -} - -int smb_vfs_call_sys_acl_delete_def_file(struct vfs_handle_struct *handle, - const char *path) -{ - VFS_FIND(sys_acl_delete_def_file); - return handle->fns->sys_acl_delete_def_file(handle, path); -} - -int smb_vfs_call_sys_acl_get_perm(struct vfs_handle_struct *handle, - SMB_ACL_PERMSET_T permset, - SMB_ACL_PERM_T perm) -{ - VFS_FIND(sys_acl_get_perm); - return handle->fns->sys_acl_get_perm(handle, permset, perm); -} - -int smb_vfs_call_sys_acl_free_text(struct vfs_handle_struct *handle, - char *text) -{ - VFS_FIND(sys_acl_free_text); - return handle->fns->sys_acl_free_text(handle, text); -} - -int smb_vfs_call_sys_acl_free_acl(struct vfs_handle_struct *handle, - SMB_ACL_T posix_acl) -{ - VFS_FIND(sys_acl_free_acl); - return handle->fns->sys_acl_free_acl(handle, posix_acl); -} - -int smb_vfs_call_sys_acl_free_qualifier(struct vfs_handle_struct *handle, - void *qualifier, SMB_ACL_TAG_T tagtype) -{ - VFS_FIND(sys_acl_free_qualifier); - return handle->fns->sys_acl_free_qualifier(handle, qualifier, tagtype); -} - -ssize_t smb_vfs_call_getxattr(struct vfs_handle_struct *handle, - const char *path, const char *name, void *value, - size_t size) -{ - VFS_FIND(getxattr); - return handle->fns->getxattr(handle, path, name, value, size); -} - -ssize_t smb_vfs_call_lgetxattr(struct vfs_handle_struct *handle, - const char *path, const char *name, void *value, - size_t size) -{ - VFS_FIND(lgetxattr); - return handle->fns->lgetxattr(handle, path, name, value, size); -} - -ssize_t smb_vfs_call_fgetxattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, const char *name, - void *value, size_t size) -{ - VFS_FIND(fgetxattr); - return handle->fns->fgetxattr(handle, fsp, name, value, size); -} - -ssize_t smb_vfs_call_listxattr(struct vfs_handle_struct *handle, - const char *path, char *list, size_t size) -{ - VFS_FIND(listxattr); - return handle->fns->listxattr(handle, path, list, size); -} - -ssize_t smb_vfs_call_llistxattr(struct vfs_handle_struct *handle, - const char *path, char *list, size_t size) -{ - VFS_FIND(llistxattr); - return handle->fns->llistxattr(handle, path, list, size); -} - -ssize_t smb_vfs_call_flistxattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, char *list, - size_t size) -{ - VFS_FIND(flistxattr); - return handle->fns->flistxattr(handle, fsp, list, size); -} - -int smb_vfs_call_removexattr(struct vfs_handle_struct *handle, - const char *path, const char *name) -{ - VFS_FIND(removexattr); - return handle->fns->removexattr(handle, path, name); -} - -int smb_vfs_call_lremovexattr(struct vfs_handle_struct *handle, - const char *path, const char *name) -{ - VFS_FIND(lremovexattr); - return handle->fns->lremovexattr(handle, path, name); -} - -int smb_vfs_call_fremovexattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, const char *name) -{ - VFS_FIND(fremovexattr); - return handle->fns->fremovexattr(handle, fsp, name); -} - -int smb_vfs_call_setxattr(struct vfs_handle_struct *handle, const char *path, - const char *name, const void *value, size_t size, - int flags) -{ - VFS_FIND(setxattr); - return handle->fns->setxattr(handle, path, name, value, size, flags); -} - -int smb_vfs_call_lsetxattr(struct vfs_handle_struct *handle, const char *path, - const char *name, const void *value, size_t size, - int flags) -{ - VFS_FIND(lsetxattr); - return handle->fns->lsetxattr(handle, path, name, value, size, flags); -} - -int smb_vfs_call_fsetxattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, const char *name, - const void *value, size_t size, int flags) -{ - VFS_FIND(fsetxattr); - return handle->fns->fsetxattr(handle, fsp, name, value, size, flags); -} - -int smb_vfs_call_aio_read(struct vfs_handle_struct *handle, - struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb) -{ - VFS_FIND(aio_read); - return handle->fns->aio_read(handle, fsp, aiocb); -} - -int smb_vfs_call_aio_write(struct vfs_handle_struct *handle, - struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb) -{ - VFS_FIND(aio_write); - return handle->fns->aio_write(handle, fsp, aiocb); -} - -ssize_t smb_vfs_call_aio_return_fn(struct vfs_handle_struct *handle, - struct files_struct *fsp, - SMB_STRUCT_AIOCB *aiocb) -{ - VFS_FIND(aio_return_fn); - return handle->fns->aio_return_fn(handle, fsp, aiocb); -} - -int smb_vfs_call_aio_cancel(struct vfs_handle_struct *handle, - struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb) -{ - VFS_FIND(aio_cancel); - return handle->fns->aio_cancel(handle, fsp, aiocb); -} - -int smb_vfs_call_aio_error_fn(struct vfs_handle_struct *handle, - struct files_struct *fsp, - SMB_STRUCT_AIOCB *aiocb) -{ - VFS_FIND(aio_error_fn); - return handle->fns->aio_error_fn(handle, fsp, aiocb); -} - -int smb_vfs_call_aio_fsync(struct vfs_handle_struct *handle, - struct files_struct *fsp, int op, - SMB_STRUCT_AIOCB *aiocb) -{ - VFS_FIND(aio_fsync); - return handle->fns->aio_fsync(handle, fsp, op, aiocb); -} - -int smb_vfs_call_aio_suspend(struct vfs_handle_struct *handle, - struct files_struct *fsp, - const SMB_STRUCT_AIOCB * const aiocb[], int n, - const struct timespec *timeout) -{ - VFS_FIND(aio_suspend); - return handle->fns->aio_suspend(handle, fsp, aiocb, n, timeout); -} - -bool smb_vfs_call_aio_force(struct vfs_handle_struct *handle, - struct files_struct *fsp) -{ - VFS_FIND(aio_force); - return handle->fns->aio_force(handle, fsp); -} - -bool smb_vfs_call_is_offline(struct vfs_handle_struct *handle, - const char *path, SMB_STRUCT_STAT *sbuf) -{ - VFS_FIND(is_offline); - return handle->fns->is_offline(handle, path, sbuf); -} - -int smb_vfs_call_set_offline(struct vfs_handle_struct *handle, - const char *path) -{ - VFS_FIND(set_offline); - return handle->fns->set_offline(handle, path); -} |