diff options
author | bubulle <bubulle@alioth.debian.org> | 2008-11-01 11:09:46 +0000 |
---|---|---|
committer | bubulle <bubulle@alioth.debian.org> | 2008-11-01 11:09:46 +0000 |
commit | a2b71a0141763c20552bb45eeb4cb78c4b513118 (patch) | |
tree | 85b64d98387145ea4e00c1b529e1820542a979a3 /source/smbd | |
parent | 2203bd59918d6d70515f9dad601cb5c0ef098092 (diff) | |
download | samba-a2b71a0141763c20552bb45eeb4cb78c4b513118.tar.gz |
Revert the merge of 3.3.0~pre2 in upstream branch
git-svn-id: svn://svn.debian.org/svn/pkg-samba/branches/samba/upstream@2200 fc4039ab-9d04-0410-8cac-899223bdd6b0
Diffstat (limited to 'source/smbd')
35 files changed, 1208 insertions, 1048 deletions
diff --git a/source/smbd/change_trust_pw.c b/source/smbd/change_trust_pw.c index 72a72a78b5..4773eeff86 100644 --- a/source/smbd/change_trust_pw.c +++ b/source/smbd/change_trust_pw.c @@ -73,9 +73,8 @@ NTSTATUS change_trust_account_password( const char *domain, const char *remote_m /* Shouldn't we open this with schannel ? JRA. */ - nt_status = cli_rpc_pipe_open_noauth( - cli, &ndr_table_netlogon.syntax_id, &netlogon_pipe); - if (!NT_STATUS_IS_OK(nt_status)) { + netlogon_pipe = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, &nt_status); + if (!netlogon_pipe) { DEBUG(0,("modify_trust_password: unable to open the domain client session to machine %s. Error was : %s.\n", dc_name, nt_errstr(nt_status))); cli_shutdown(cli); @@ -83,8 +82,7 @@ NTSTATUS change_trust_account_password( const char *domain, const char *remote_m goto failed; } - nt_status = trust_pw_find_change_and_store_it( - netlogon_pipe, netlogon_pipe, domain); + nt_status = trust_pw_find_change_and_store_it(netlogon_pipe, netlogon_pipe->mem_ctx, domain); cli_shutdown(cli); cli = NULL; diff --git a/source/smbd/close.c b/source/smbd/close.c index 818b4c70a8..3d3c4cf09e 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -581,7 +581,7 @@ static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_ } DEBUG(2,("%s closed file %s (numopen=%d) %s\n", - conn->server_info->unix_name,fsp->fsp_name, + conn->user,fsp->fsp_name, conn->num_files_open, nt_errstr(status) )); @@ -703,6 +703,20 @@ static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_ty } /**************************************************************************** + Close a 'stat file' opened internally. +****************************************************************************/ + +static NTSTATUS close_stat(files_struct *fsp) +{ + /* + * Do the code common to files and directories. + */ + close_filestruct(fsp); + file_free(fsp); + return NT_STATUS_OK; +} + +/**************************************************************************** Close a files_struct. ****************************************************************************/ @@ -713,6 +727,8 @@ NTSTATUS close_file(files_struct *fsp, enum file_close_type close_type) if(fsp->is_directory) { status = close_directory(fsp, close_type); + } else if (fsp->is_stat) { + status = close_stat(fsp); } else if (fsp->fake_file_handle != NULL) { status = close_fake_file(fsp); } else { diff --git a/source/smbd/conn.c b/source/smbd/conn.c index 7f34d2b8e2..c5a2df4773 100644 --- a/source/smbd/conn.c +++ b/source/smbd/conn.c @@ -91,6 +91,7 @@ thinking the server is still available. ****************************************************************************/ connection_struct *conn_new(void) { + TALLOC_CTX *mem_ctx; connection_struct *conn; int i; int find_offset = 1; @@ -138,18 +139,25 @@ find_again: return NULL; } - if (!(conn=TALLOC_ZERO_P(NULL, connection_struct)) || - !(conn->params = TALLOC_P(conn, struct share_params))) { + if ((mem_ctx=talloc_init("connection_struct"))==NULL) { + DEBUG(0,("talloc_init(connection_struct) failed!\n")); + return NULL; + } + + if (!(conn=TALLOC_ZERO_P(mem_ctx, connection_struct)) || + !(conn->params = TALLOC_P(mem_ctx, struct share_params))) { DEBUG(0,("TALLOC_ZERO() failed!\n")); - TALLOC_FREE(conn); + TALLOC_FREE(mem_ctx); return NULL; } + conn->mem_ctx = mem_ctx; conn->cnum = i; bitmap_set(bmap, i); num_open++; + string_set(&conn->user,""); string_set(&conn->dirpath,""); string_set(&conn->connectpath,""); string_set(&conn->origpath,""); @@ -161,19 +169,16 @@ find_again: /**************************************************************************** Close all conn structures. -return true if any were closed ****************************************************************************/ -bool conn_close_all(void) + +void conn_close_all(void) { connection_struct *conn, *next; - bool ret = false; for (conn=Connections;conn;conn=next) { next=conn->next; set_current_service(conn, 0, True); close_cnum(conn, conn->vuid); - ret = true; } - return ret; } /**************************************************************************** @@ -228,15 +233,24 @@ bool conn_idle_all(time_t t) Clear a vuid out of the validity cache, and as the 'owner' of a connection. ****************************************************************************/ -void conn_clear_vuid_caches(uint16_t vuid) +void conn_clear_vuid_cache(uint16 vuid) { connection_struct *conn; + unsigned int i; for (conn=Connections;conn;conn=conn->next) { if (conn->vuid == vuid) { conn->vuid = UID_FIELD_INVALID; } - conn_clear_vuid_cache(conn, vuid); + + for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) { + if (conn->vuid_cache.array[i].vuid == vuid) { + struct vuid_cache_entry *ent = &conn->vuid_cache.array[i]; + ent->vuid = UID_FIELD_INVALID; + ent->read_only = False; + ent->admin_user = False; + } + } } } @@ -247,13 +261,14 @@ void conn_clear_vuid_caches(uint16_t vuid) void conn_free_internal(connection_struct *conn) { vfs_handle_struct *handle = NULL, *thandle = NULL; + TALLOC_CTX *mem_ctx = NULL; struct trans_state *state = NULL; /* Free vfs_connection_struct */ handle = conn->vfs_handles; while(handle) { - thandle = handle->next; DLIST_REMOVE(conn->vfs_handles, handle); + thandle = handle->next; if (handle->free_data) handle->free_data(&handle->data); handle = thandle; @@ -271,12 +286,14 @@ void conn_free_internal(connection_struct *conn) free_namearray(conn->veto_oplock_list); free_namearray(conn->aio_write_behind_list); + string_free(&conn->user); string_free(&conn->dirpath); string_free(&conn->connectpath); string_free(&conn->origpath); + mem_ctx = conn->mem_ctx; ZERO_STRUCTP(conn); - talloc_destroy(conn); + talloc_destroy(mem_ctx); } /**************************************************************************** diff --git a/source/smbd/connection.c b/source/smbd/connection.c index 8dd5964f5f..d7063c9989 100644 --- a/source/smbd/connection.c +++ b/source/smbd/connection.c @@ -152,8 +152,8 @@ bool claim_connection(connection_struct *conn, const char *name, crec.pid = procid_self(); crec.cnum = conn?conn->cnum:-1; if (conn) { - crec.uid = conn->server_info->utok.uid; - crec.gid = conn->server_info->utok.gid; + crec.uid = conn->uid; + crec.gid = conn->gid; strlcpy(crec.servicename, lp_servicename(SNUM(conn)), sizeof(crec.servicename)); } diff --git a/source/smbd/dfree.c b/source/smbd/dfree.c index 1ddcd48d40..9e7f18a130 100644 --- a/source/smbd/dfree.c +++ b/source/smbd/dfree.c @@ -206,7 +206,7 @@ SMB_BIG_UINT get_dfree_info(connection_struct *conn, /* No cached info or time to refresh. */ if (!dfc) { - dfc = TALLOC_P(conn, struct dfree_cached_info); + dfc = TALLOC_P(conn->mem_ctx, struct dfree_cached_info); if (!dfc) { return dfree_ret; } diff --git a/source/smbd/dir.c b/source/smbd/dir.c index c2735c032a..604db984af 100644 --- a/source/smbd/dir.c +++ b/source/smbd/dir.c @@ -24,6 +24,8 @@ This module implements directory related functions for Samba. */ +extern struct current_user current_user; + /* "Special" directory offsets. */ #define END_OF_DIRECTORY_OFFSET ((long)-1) #define START_OF_DIRECTORY_OFFSET ((long)0) @@ -921,8 +923,13 @@ bool get_dir_entry(TALLOC_CTX *ctx, use it for anything security sensitive. ********************************************************************/ -static bool user_can_read_file(connection_struct *conn, char *name) +static bool user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst) { + SEC_DESC *psd = NULL; + files_struct *fsp; + NTSTATUS status; + uint32 access_granted; + /* * If user is a member of the Admin group * we never hide files from them. @@ -932,7 +939,38 @@ static bool user_can_read_file(connection_struct *conn, char *name) return True; } - return can_access_file_acl(conn, name, FILE_READ_DATA); + SMB_ASSERT(VALID_STAT(*pst)); + + /* Pseudo-open the file (note - no fd's created). */ + + if(S_ISDIR(pst->st_mode)) { + status = open_directory(conn, NULL, name, pst, + READ_CONTROL_ACCESS, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, /* no create options. */ + FILE_ATTRIBUTE_DIRECTORY, + NULL, &fsp); + } else { + status = open_file_stat(conn, NULL, name, pst, &fsp); + } + + if (!NT_STATUS_IS_OK(status)) { + return False; + } + + /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ + status = SMB_VFS_FGET_NT_ACL(fsp, + (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd); + close_file(fsp, NORMAL_CLOSE); + + /* No access if SD get failed. */ + if (!NT_STATUS_IS_OK(status)) { + return False; + } + + return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA, + &access_granted, &status); } /******************************************************************* @@ -944,6 +982,12 @@ static bool user_can_read_file(connection_struct *conn, char *name) static bool user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst) { + SEC_DESC *psd = NULL; + files_struct *fsp; + int info; + NTSTATUS status; + uint32 access_granted; + /* * If user is a member of the Admin group * we never hide files from them. @@ -959,9 +1003,33 @@ static bool user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_ if(S_ISDIR(pst->st_mode)) { return True; + } else { + status = open_file_ntcreate(conn, NULL, name, pst, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + INTERNAL_OPEN_ONLY, + &info, &fsp); + } + + if (!NT_STATUS_IS_OK(status)) { + return False; + } + + /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ + status = SMB_VFS_FGET_NT_ACL(fsp, + (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd); + close_file(fsp, NORMAL_CLOSE); + + /* No access if SD get failed. */ + if (!NT_STATUS_IS_OK(status)) { + return False; } - return can_write_to_file(conn, name, pst); + return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA, + &access_granted, &status); } /******************************************************************* @@ -1035,7 +1103,7 @@ bool is_visible_file(connection_struct *conn, const char *dir_path, const char * } /* Honour _hide unreadable_ option */ - if (hide_unreadable && !user_can_read_file(conn, entry)) { + if (hide_unreadable && !user_can_read_file(conn, entry, pst)) { DEBUG(10,("is_visible_file: file %s is unreadable.\n", entry )); SAFE_FREE(entry); return False; diff --git a/source/smbd/fake_file.c b/source/smbd/fake_file.c index 8dd9abee1a..31fe030f46 100644 --- a/source/smbd/fake_file.c +++ b/source/smbd/fake_file.c @@ -19,52 +19,54 @@ #include "includes.h" -struct fake_file_type { - const char *name; - enum FAKE_FILE_TYPE type; - void *(*init_pd)(TALLOC_CTX *mem_ctx); -}; +extern struct current_user current_user; -static struct fake_file_type fake_files[] = { +static FAKE_FILE fake_files[] = { #ifdef WITH_QUOTAS - {FAKE_FILE_NAME_QUOTA_UNIX, FAKE_FILE_TYPE_QUOTA, init_quota_handle}, + {FAKE_FILE_NAME_QUOTA_UNIX, FAKE_FILE_TYPE_QUOTA, init_quota_handle, destroy_quota_handle}, #endif /* WITH_QUOTAS */ - {NULL, FAKE_FILE_TYPE_NONE, NULL} + {NULL, FAKE_FILE_TYPE_NONE, NULL, NULL } }; /**************************************************************************** Create a fake file handle ****************************************************************************/ -static struct fake_file_handle *init_fake_file_handle(enum FAKE_FILE_TYPE type) +static struct _FAKE_FILE_HANDLE *init_fake_file_handle(enum FAKE_FILE_TYPE type) { - struct fake_file_handle *fh = NULL; + TALLOC_CTX *mem_ctx = NULL; + FAKE_FILE_HANDLE *fh = NULL; int i; - for (i=0; fake_files[i].name!=NULL; i++) { + for (i=0;fake_files[i].name!=NULL;i++) { if (fake_files[i].type==type) { - break; - } - } + DEBUG(5,("init_fake_file_handle: for [%s]\n",fake_files[i].name)); - if (fake_files[i].name == NULL) { - return NULL; - } + if ((mem_ctx=talloc_init("fake_file_handle"))==NULL) { + DEBUG(0,("talloc_init(fake_file_handle) failed.\n")); + return NULL; + } - DEBUG(5,("init_fake_file_handle: for [%s]\n",fake_files[i].name)); + if ((fh =TALLOC_ZERO_P(mem_ctx, FAKE_FILE_HANDLE))==NULL) { + DEBUG(0,("TALLOC_ZERO() failed.\n")); + talloc_destroy(mem_ctx); + return NULL; + } - fh = talloc(NULL, struct fake_file_handle); - if (fh == NULL) { - DEBUG(0,("TALLOC_ZERO() failed.\n")); - return NULL; - } + fh->type = type; + fh->mem_ctx = mem_ctx; - fh->type = type; + if (fake_files[i].init_pd) { + fh->pd = fake_files[i].init_pd(fh->mem_ctx); + } - if (fake_files[i].init_pd) { - fh->private_data = fake_files[i].init_pd(fh); + fh->free_pd = fake_files[i].free_pd; + + return fh; + } } - return fh; + + return NULL; } /**************************************************************************** @@ -99,7 +101,6 @@ enum FAKE_FILE_TYPE is_fake_file(const char *fname) ****************************************************************************/ NTSTATUS open_fake_file(connection_struct *conn, - uint16_t current_vuid, enum FAKE_FILE_TYPE fake_file_type, const char *fname, uint32 access_mask, @@ -109,11 +110,10 @@ NTSTATUS open_fake_file(connection_struct *conn, NTSTATUS status; /* access check */ - if (conn->server_info->utok.uid != 0) { + if (current_user.ut.uid != 0) { DEBUG(3, ("open_fake_file_shared: access_denied to " "service[%s] file[%s] user[%s]\n", - lp_servicename(SNUM(conn)), fname, - conn->server_info->unix_name)); + lp_servicename(SNUM(conn)),fname,conn->user)); return NT_STATUS_ACCESS_DENIED; } @@ -128,7 +128,7 @@ NTSTATUS open_fake_file(connection_struct *conn, fsp->conn = conn; fsp->fh->fd = -1; - fsp->vuid = current_vuid; + fsp->vuid = current_user.vuid; fsp->fh->pos = -1; fsp->can_lock = False; /* Should this be true ? - No, JRA */ fsp->access_mask = access_mask; @@ -146,12 +146,18 @@ NTSTATUS open_fake_file(connection_struct *conn, return NT_STATUS_OK; } -void destroy_fake_file_handle(struct fake_file_handle **fh) +void destroy_fake_file_handle(FAKE_FILE_HANDLE **fh) { - if (!fh) { + if (!fh||!(*fh)) { return; } - TALLOC_FREE(*fh); + + if ((*fh)->free_pd) { + (*fh)->free_pd(&(*fh)->pd); + } + + talloc_destroy((*fh)->mem_ctx); + (*fh) = NULL; } NTSTATUS close_fake_file(files_struct *fsp) diff --git a/source/smbd/file_access.c b/source/smbd/file_access.c index 84c993d06b..964d1af258 100644 --- a/source/smbd/file_access.c +++ b/source/smbd/file_access.c @@ -20,14 +20,13 @@ #include "includes.h" +extern struct current_user current_user; + #undef DBGC_CLASS #define DBGC_CLASS DBGC_ACLS -/** - * Security descriptor / NT Token level access check function. - */ -bool can_access_file_acl(struct connection_struct *conn, - const char * fname, +static bool can_access_file_acl(struct connection_struct *conn, + const char * fname, SMB_STRUCT_STAT *psbuf, uint32_t access_mask) { bool result; @@ -45,7 +44,7 @@ bool can_access_file_acl(struct connection_struct *conn, return false; } - result = se_access_check(secdesc, conn->server_info->ptok, + result = se_access_check(secdesc, current_user.nt_user_token, access_mask, &access_granted, &status); TALLOC_FREE(secdesc); return result; @@ -82,11 +81,16 @@ bool can_delete_file_in_directory(connection_struct *conn, const char *fname) if (!S_ISDIR(sbuf.st_mode)) { return False; } - if (conn->server_info->utok.uid == 0 || conn->admin_user) { + if (current_user.ut.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ return True; } + /* Check primary owner write access. */ + if (current_user.ut.uid == sbuf.st_uid) { + return (sbuf.st_mode & S_IWUSR) ? True : False; + } + #ifdef S_ISVTX /* sticky bit means delete only by owner or root. */ if (sbuf.st_mode & S_ISVTX) { @@ -104,7 +108,7 @@ bool can_delete_file_in_directory(connection_struct *conn, const char *fname) * for bug #3348. Don't assume owning sticky bit * directory means write access allowed. */ - if (conn->server_info->utok.uid != sbuf_file.st_uid) { + if (current_user.ut.uid != sbuf_file.st_uid) { return False; } } @@ -112,21 +116,7 @@ bool can_delete_file_in_directory(connection_struct *conn, const char *fname) /* now for ACL checks */ - /* - * There's two ways to get the permission to delete a file: First by - * having the DELETE bit on the file itself and second if that does - * not help, by the DELETE_CHILD bit on the containing directory. - * - * Here we check the other way round because with just posix - * permissions looking at the file itself will never grant DELETE, so - * by looking at the directory first we save one get_acl call. - */ - - if (can_access_file_acl(conn, dname, FILE_DELETE_CHILD)) { - return true; - } - - return can_access_file_acl(conn, fname, DELETE_ACCESS); + return can_access_file_acl(conn, dname, &sbuf, FILE_WRITE_DATA); } /**************************************************************************** @@ -135,7 +125,7 @@ bool can_delete_file_in_directory(connection_struct *conn, const char *fname) Note this doesn't take into account share write permissions. ****************************************************************************/ -bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask) +bool can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask) { if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) { return False; @@ -144,10 +134,10 @@ bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT /* some fast paths first */ - DEBUG(10,("can_access_file_data: requesting 0x%x on file %s\n", + DEBUG(10,("can_access_file: requesting 0x%x on file %s\n", (unsigned int)access_mask, fname )); - if (conn->server_info->utok.uid == 0 || conn->admin_user) { + if (current_user.ut.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ return True; } @@ -160,7 +150,7 @@ bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT } /* Check primary owner access. */ - if (conn->server_info->utok.uid == psbuf->st_uid) { + if (current_user.ut.uid == psbuf->st_uid) { switch (access_mask) { case FILE_READ_DATA: return (psbuf->st_mode & S_IRUSR) ? True : False; @@ -180,7 +170,7 @@ bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT /* now for ACL checks */ - return can_access_file_acl(conn, fname, access_mask); + return can_access_file_acl(conn, fname, psbuf, access_mask); } /**************************************************************************** @@ -190,33 +180,6 @@ bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT bool can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) { - return can_access_file_data(conn, fname, psbuf, FILE_WRITE_DATA); + return can_access_file(conn, fname, psbuf, FILE_WRITE_DATA); } -/**************************************************************************** - Check for an existing default Windows ACL on a directory. -****************************************************************************/ - -bool directory_has_default_acl(connection_struct *conn, const char *fname) -{ - /* returns talloced off tos. */ - struct security_descriptor *secdesc = NULL; - unsigned int i; - NTSTATUS status = SMB_VFS_GET_NT_ACL(conn, fname, - DACL_SECURITY_INFORMATION, &secdesc); - - if (!NT_STATUS_IS_OK(status) || secdesc == NULL) { - return false; - } - - for (i = 0; i < secdesc->dacl->num_aces; i++) { - struct security_ace *psa = &secdesc->dacl->aces[i]; - if (psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT| - SEC_ACE_FLAG_CONTAINER_INHERIT)) { - TALLOC_FREE(secdesc); - return true; - } - } - TALLOC_FREE(secdesc); - return false; -} diff --git a/source/smbd/filename.c b/source/smbd/filename.c index 562f1e8d94..41a0b9296a 100644 --- a/source/smbd/filename.c +++ b/source/smbd/filename.c @@ -101,7 +101,8 @@ get any fatal errors that should immediately terminate the calling SMB processing whilst resolving. If the saved_last_component != 0, then the unmodified last component -of the pathname is returned there. If saved_last_component == 0 then nothing +of the pathname is returned there. This is used in an exceptional +case in reply_mv (so far). If saved_last_component == 0 then nothing is returned there. If last_component_wcard is true then a MS wildcard was detected and diff --git a/source/smbd/files.c b/source/smbd/files.c index 8d06e20f81..d6e91c67be 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -122,12 +122,10 @@ NTSTATUS file_new(connection_struct *conn, files_struct **result) chain_fsp = fsp; - /* A new fsp invalidates the positive and - negative fsp_fi_cache as the new fsp is pushed - at the start of the list and we search from - a cache hit to the *end* of the list. */ - - ZERO_STRUCT(fsp_fi_cache); + /* A new fsp invalidates a negative fsp_fi_cache. */ + if (fsp_fi_cache.fsp == NULL) { + ZERO_STRUCT(fsp_fi_cache); + } *result = fsp; return NT_STATUS_OK; @@ -328,7 +326,8 @@ files_struct *file_find_di_first(struct file_id id) fsp_fi_cache.id = id; for (fsp=Files;fsp;fsp=fsp->next) { - if (file_id_equal(&fsp->file_id, &id)) { + if ( fsp->fh->fd != -1 && + file_id_equal(&fsp->file_id, &id)) { /* Setup positive cache. */ fsp_fi_cache.fsp = fsp; return fsp; @@ -349,7 +348,8 @@ files_struct *file_find_di_next(files_struct *start_fsp) files_struct *fsp; for (fsp = start_fsp->next;fsp;fsp=fsp->next) { - if (file_id_equal(&fsp->file_id, &start_fsp->file_id)) { + if ( fsp->fh->fd != -1 && + file_id_equal(&fsp->file_id, &start_fsp->file_id)) { return fsp; } } @@ -539,6 +539,7 @@ NTSTATUS dup_file_fsp(files_struct *fsp, dup_fsp->print_file = fsp->print_file; dup_fsp->modified = fsp->modified; dup_fsp->is_directory = fsp->is_directory; + dup_fsp->is_stat = fsp->is_stat; dup_fsp->aio_write_behind = fsp->aio_write_behind; string_set(&dup_fsp->fsp_name,fsp->fsp_name); diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c index f4c45999ba..6961a5caf1 100644 --- a/source/smbd/ipc.c +++ b/source/smbd/ipc.c @@ -81,7 +81,8 @@ static void copy_trans_params_and_data(char *outbuf, int align, Send a trans reply. ****************************************************************************/ -void send_trans_reply(connection_struct *conn, const uint8_t *inbuf, +void send_trans_reply(connection_struct *conn, + struct smb_request *req, char *rparam, int rparam_len, char *rdata, int rdata_len, bool buffer_too_large) @@ -90,7 +91,6 @@ void send_trans_reply(connection_struct *conn, const uint8_t *inbuf, int tot_data_sent = 0; int tot_param_sent = 0; int align; - char *outbuf; int ldata = rdata ? rdata_len : 0; int lparam = rparam ? rparam_len : 0; @@ -103,48 +103,47 @@ void send_trans_reply(connection_struct *conn, const uint8_t *inbuf, align = ((this_lparam)%4); - if (!create_outbuf(talloc_tos(), (char *)inbuf, &outbuf, - 10, 1+align+this_ldata+this_lparam)) { - smb_panic("could not allocate outbuf"); - } + reply_outbuf(req, 10, 1+align+this_ldata+this_lparam); - copy_trans_params_and_data(outbuf, align, + copy_trans_params_and_data((char *)req->outbuf, align, rparam, tot_param_sent, this_lparam, rdata, tot_data_sent, this_ldata); - SSVAL(outbuf,smb_vwv0,lparam); - SSVAL(outbuf,smb_vwv1,ldata); - SSVAL(outbuf,smb_vwv3,this_lparam); - SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf)); - SSVAL(outbuf,smb_vwv5,0); - SSVAL(outbuf,smb_vwv6,this_ldata); - SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align, - outbuf)); - SSVAL(outbuf,smb_vwv8,0); - SSVAL(outbuf,smb_vwv9,0); + SSVAL(req->outbuf,smb_vwv0,lparam); + SSVAL(req->outbuf,smb_vwv1,ldata); + SSVAL(req->outbuf,smb_vwv3,this_lparam); + SSVAL(req->outbuf,smb_vwv4,smb_offset(smb_buf(req->outbuf)+1, + req->outbuf)); + SSVAL(req->outbuf,smb_vwv5,0); + SSVAL(req->outbuf,smb_vwv6,this_ldata); + SSVAL(req->outbuf,smb_vwv7,smb_offset(smb_buf(req->outbuf)+1+ + this_lparam+align, + req->outbuf)); + SSVAL(req->outbuf,smb_vwv8,0); + SSVAL(req->outbuf,smb_vwv9,0); if (buffer_too_large) { - error_packet_set((char *)outbuf, ERRDOS, ERRmoredata, - STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__); + error_packet_set((char *)req->outbuf, + ERRDOS, ERRmoredata, + STATUS_BUFFER_OVERFLOW, + __LINE__, __FILE__); } - show_msg(outbuf); - if (!srv_send_smb(smbd_server_fd(), (char *)outbuf, - IS_CONN_ENCRYPTED(conn))) { + show_msg((char *)req->outbuf); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + IS_CONN_ENCRYPTED(conn))) exit_server_cleanly("send_trans_reply: srv_send_smb failed."); - } - TALLOC_FREE(outbuf); + TALLOC_FREE(req->outbuf); tot_data_sent = this_ldata; tot_param_sent = this_lparam; while (tot_data_sent < ldata || tot_param_sent < lparam) { - this_lparam = MIN(lparam-tot_param_sent, - max_send - 500); /* hack */ - this_ldata = MIN(ldata -tot_data_sent, - max_send - (500+this_lparam)); + this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */ + this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam)); if(this_lparam < 0) this_lparam = 0; @@ -154,39 +153,39 @@ void send_trans_reply(connection_struct *conn, const uint8_t *inbuf, align = (this_lparam%4); - if (!create_outbuf(talloc_tos(), (char *)inbuf, &outbuf, - 10, 1+align+this_ldata+this_lparam)) { - smb_panic("could not allocate outbuf"); - } + reply_outbuf(req, 10, 1+this_ldata+this_lparam+align); - copy_trans_params_and_data(outbuf, align, + copy_trans_params_and_data((char *)req->outbuf, align, rparam, tot_param_sent, this_lparam, rdata, tot_data_sent, this_ldata); - SSVAL(outbuf,smb_vwv3,this_lparam); - SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf)); - SSVAL(outbuf,smb_vwv5,tot_param_sent); - SSVAL(outbuf,smb_vwv6,this_ldata); - SSVAL(outbuf,smb_vwv7, - smb_offset(smb_buf(outbuf)+1+this_lparam+align, outbuf)); - SSVAL(outbuf,smb_vwv8,tot_data_sent); - SSVAL(outbuf,smb_vwv9,0); + SSVAL(req->outbuf,smb_vwv3,this_lparam); + SSVAL(req->outbuf,smb_vwv4,smb_offset(smb_buf(req->outbuf)+1, + req->outbuf)); + SSVAL(req->outbuf,smb_vwv5,tot_param_sent); + SSVAL(req->outbuf,smb_vwv6,this_ldata); + SSVAL(req->outbuf,smb_vwv7,smb_offset(smb_buf(req->outbuf)+1+ + this_lparam+align, + req->outbuf)); + SSVAL(req->outbuf,smb_vwv8,tot_data_sent); + SSVAL(req->outbuf,smb_vwv9,0); if (buffer_too_large) { - error_packet_set(outbuf, ERRDOS, ERRmoredata, + error_packet_set((char *)req->outbuf, + ERRDOS, ERRmoredata, STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__); } - show_msg(outbuf); - if (!srv_send_smb(smbd_server_fd(), outbuf, - IS_CONN_ENCRYPTED(conn))) - exit_server_cleanly("send_trans_reply: srv_send_smb " - "failed."); + show_msg((char *)req->outbuf); + if (!srv_send_smb(smbd_server_fd(), + (char *)req->outbuf, + IS_CONN_ENCRYPTED(conn))) + exit_server_cleanly("send_trans_reply: srv_send_smb failed."); tot_data_sent += this_ldata; tot_param_sent += this_lparam; - TALLOC_FREE(outbuf); + TALLOC_FREE(req->outbuf); } } @@ -213,8 +212,7 @@ static void api_rpc_trans_reply(connection_struct *conn, struct smb_request *req return; } - send_trans_reply(conn, req->inbuf, NULL, 0, rdata, data_len, - is_data_outstanding); + send_trans_reply(conn, req, NULL, 0, rdata, data_len, is_data_outstanding); SAFE_FREE(rdata); return; } @@ -238,7 +236,7 @@ static void api_WNPHS(connection_struct *conn, struct smb_request *req, smb_np_s if (wait_rpc_pipe_hnd_state(p, priority)) { /* now send the reply */ - send_trans_reply(conn, req->inbuf, NULL, 0, NULL, 0, False); + send_trans_reply(conn, req, NULL, 0, NULL, 0, False); return; } api_no_reply(conn,req); @@ -264,7 +262,7 @@ static void api_SNPHS(connection_struct *conn, struct smb_request *req, smb_np_s if (set_rpc_pipe_hnd_state(p, id)) { /* now send the reply */ - send_trans_reply(conn, req->inbuf, NULL, 0, NULL, 0, False); + send_trans_reply(conn, req, NULL, 0, NULL, 0, False); return; } api_no_reply(conn,req); @@ -286,7 +284,7 @@ static void api_no_reply(connection_struct *conn, struct smb_request *req) DEBUG(3,("Unsupported API fd command\n")); /* now send the reply */ - send_trans_reply(conn, req->inbuf, rparam, 4, NULL, 0, False); + send_trans_reply(conn, req, rparam, 4, NULL, 0, False); return; } @@ -328,8 +326,7 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid, /* Win9x does this call with a unicode pipe name, not a pnum. */ /* Just return success for now... */ DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n")); - send_trans_reply(conn, req->inbuf, NULL, 0, NULL, 0, - False); + send_trans_reply(conn, req, NULL, 0, NULL, 0, False); return; } @@ -528,7 +525,7 @@ void reply_trans(struct smb_request *req) return; } - if ((state = TALLOC_P(conn, struct trans_state)) == NULL) { + if ((state = TALLOC_P(conn->mem_ctx, struct trans_state)) == NULL) { DEBUG(0, ("talloc failed\n")); reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBtrans); diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c index fe1d766b9d..6fa4f9698d 100644 --- a/source/smbd/lanman.c +++ b/source/smbd/lanman.c @@ -27,6 +27,9 @@ #include "includes.h" +extern struct current_user current_user; +extern userdom_struct current_user_info; + #ifdef CHECK_TYPES #undef CHECK_TYPES #endif @@ -98,11 +101,11 @@ static int CopyExpanded(connection_struct *conn, } buf = talloc_sub_advanced(ctx, lp_servicename(SNUM(conn)), - conn->server_info->unix_name, + conn->user, conn->connectpath, - conn->server_info->utok.gid, - conn->server_info->sanitized_username, - pdb_get_domain(conn->server_info->sam_account), + conn->gid, + get_current_username(), + current_user_info.domain, buf); if (!buf) { *p_space_remaining = 0; @@ -149,11 +152,11 @@ static int StrlenExpanded(connection_struct *conn, int snum, char *s) } buf = talloc_sub_advanced(ctx, lp_servicename(SNUM(conn)), - conn->server_info->unix_name, + conn->user, conn->connectpath, - conn->server_info->utok.gid, - conn->server_info->sanitized_username, - pdb_get_domain(conn->server_info->sam_account), + conn->gid, + get_current_username(), + current_user_info.domain, buf); if (!buf) { return 0; @@ -179,11 +182,11 @@ static char *Expand(connection_struct *conn, int snum, char *s) } return talloc_sub_advanced(ctx, lp_servicename(SNUM(conn)), - conn->server_info->unix_name, + conn->user, conn->connectpath, - conn->server_info->utok.gid, - conn->server_info->sanitized_username, - pdb_get_domain(conn->server_info->sam_account), + conn->gid, + get_current_username(), + current_user_info.domain, buf); } @@ -1893,7 +1896,6 @@ static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid, unsigned int offset; int snum; int res = ERRunsup; - size_t converted_size; if (!str1 || !str2 || !p) { return False; @@ -1954,13 +1956,7 @@ static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid, return False; } - if (!pull_ascii_talloc(talloc_tos(), &pathname, - offset ? (data+offset) : "", &converted_size)) - { - DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s", - strerror(errno))); - } - + pull_ascii_talloc(talloc_tos(), &pathname, offset? (data+offset) : ""); if (!pathname) { return false; } @@ -2680,15 +2676,15 @@ static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, switch (function) { case 81: /* delete */ - if (print_job_delete(conn->server_info, snum, jobid, &werr)) + if (print_job_delete(¤t_user, snum, jobid, &werr)) errcode = NERR_Success; break; case 82: /* pause */ - if (print_job_pause(conn->server_info, snum, jobid, &werr)) + if (print_job_pause(¤t_user, snum, jobid, &werr)) errcode = NERR_Success; break; case 83: /* resume */ - if (print_job_resume(conn->server_info, snum, jobid, &werr)) + if (print_job_resume(¤t_user, snum, jobid, &werr)) errcode = NERR_Success; break; } @@ -2749,19 +2745,13 @@ static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, switch (function) { case 74: /* Pause queue */ - if (print_queue_pause(conn->server_info, snum, &werr)) { - errcode = NERR_Success; - } + if (print_queue_pause(¤t_user, snum, &werr)) errcode = NERR_Success; break; case 75: /* Resume queue */ - if (print_queue_resume(conn->server_info, snum, &werr)) { - errcode = NERR_Success; - } + if (print_queue_resume(¤t_user, snum, &werr)) errcode = NERR_Success; break; case 103: /* Purge */ - if (print_queue_purge(conn->server_info, snum, &werr)) { - errcode = NERR_Success; - } + if (print_queue_purge(¤t_user, snum, &werr)) errcode = NERR_Success; break; } @@ -3008,15 +2998,14 @@ static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, SIVAL(p,6,0); } else { SIVAL(p,6,PTR_DIFF(p2,*rdata)); - comment = talloc_sub_advanced( - ctx, - lp_servicename(SNUM(conn)), - conn->server_info->unix_name, - conn->connectpath, - conn->server_info->utok.gid, - conn->server_info->sanitized_username, - pdb_get_domain(conn->server_info->sam_account), - comment); + comment = talloc_sub_advanced(ctx, + lp_servicename(SNUM(conn)), + conn->user, + conn->connectpath, + conn->gid, + get_current_username(), + current_user_info.domain, + comment); if (comment) { return false; } @@ -3115,7 +3104,7 @@ static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, p += 4; SIVAL(p,0,PTR_DIFF(p2,*rdata)); - strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2)); + strlcpy(p2,current_user_info.smb_name,PTR_DIFF(endp,p2)); p2 = skip_string(*rdata,*rdata_len,p2); if (!p2) { return False; @@ -3349,9 +3338,8 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid, Don't depend on vuser being non-null !!. JRA */ 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, - vuser->server_info->unix_name)); + DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid, + vuser->user.unix_name)); } if (!str1 || !str2 || !UserName || !p) { @@ -3424,9 +3412,7 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid, /* EEK! the cifsrap.txt doesn't have this in!!!! */ SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */ - strlcpy(p2,((vuser != NULL) - ? pdb_get_fullname(vuser->server_info->sam_account) - : UserName),PTR_DIFF(endp,p2)); + strlcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName),PTR_DIFF(endp,p2)); p2 = skip_string(*rdata,*rdata_len,p2); if (!p2) { return False; @@ -3434,17 +3420,12 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid, } if (uLevel == 11) { - const char *homedir = ""; - if (vuser != NULL) { - homedir = pdb_get_homedir( - vuser->server_info->sam_account); - } /* modelled after NTAS 3.51 reply */ SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */ SIVALS(p,usri11_password_age,-1); /* password age */ SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */ - strlcpy(p2, homedir, PTR_DIFF(endp,p2)); + strlcpy(p2, vuser && vuser->homedir ? vuser->homedir : "",PTR_DIFF(endp,p2)); p2 = skip_string(*rdata,*rdata_len,p2); if (!p2) { return False; @@ -3495,9 +3476,7 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid, SSVAL(p,42, conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */ - strlcpy(p2, vuser ? pdb_get_homedir( - vuser->server_info->sam_account) : "", - PTR_DIFF(endp,p2)); + strlcpy(p2, vuser && vuser->homedir ? vuser->homedir : "",PTR_DIFF(endp,p2)); p2 = skip_string(*rdata,*rdata_len,p2); if (!p2) { return False; @@ -3506,9 +3485,7 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid, *p2++ = 0; SSVAL(p,52,0); /* flags */ SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */ - strlcpy(p2, vuser ? pdb_get_logon_script( - vuser->server_info->sam_account) : "", - PTR_DIFF(endp,p2)); + strlcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "",PTR_DIFF(endp,p2)); p2 = skip_string(*rdata,*rdata_len,p2); if (!p2) { return False; @@ -3516,9 +3493,7 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid, if (uLevel == 2) { SIVAL(p,60,0); /* auth_flags */ SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */ - strlcpy(p2,((vuser != NULL) - ? pdb_get_fullname(vuser->server_info->sam_account) - : UserName),PTR_DIFF(endp,p2)); + strlcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName),PTR_DIFF(endp,p2)); p2 = skip_string(*rdata,*rdata_len,p2); if (!p2) { return False; @@ -3605,9 +3580,8 @@ static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, } if(vuser != NULL) { - DEBUG(3,(" Username of UID %d is %s\n", - (int)vuser->server_info->utok.uid, - vuser->server_info->unix_name)); + DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid, + vuser->user.unix_name)); } uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); @@ -3664,8 +3638,7 @@ static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, } PACKS(&desc,"z",lp_workgroup());/* domain */ - PACKS(&desc,"z", vuser ? pdb_get_logon_script( - vuser->server_info->sam_account) : ""); /* script path */ + PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */ PACKI(&desc,"D",0x00000000); /* reserved */ } @@ -4587,7 +4560,7 @@ void api_reply(connection_struct *conn, uint16 vuid, if (api_commands[i].auth_user && lp_restrict_anonymous()) { user_struct *user = get_valid_user_struct(vuid); - if (!user || user->server_info->guest) { + if (!user || user->guest) { reply_nterror(req, NT_STATUS_ACCESS_DENIED); return; } @@ -4632,7 +4605,7 @@ void api_reply(connection_struct *conn, uint16 vuid, /* If api_Unsupported returns false we can't return anything. */ if (reply) { - send_trans_reply(conn, req->inbuf, rparam, rparam_len, + send_trans_reply(conn, req, rparam, rparam_len, rdata, rdata_len, False); } diff --git a/source/smbd/mangle_hash.c b/source/smbd/mangle_hash.c index 69ecf77834..1dc9c67dcc 100644 --- a/source/smbd/mangle_hash.c +++ b/source/smbd/mangle_hash.c @@ -294,7 +294,8 @@ static bool is_8_3(const char *fname, bool check_case, bool allow_wildcards, if (strlen(f) > 12) return False; - if (!push_ucs2_allocate(&ucs2name, f, &size)) { + size = push_ucs2_allocate(&ucs2name, f); + if (size == (size_t)-1) { DEBUG(0,("is_8_3: internal error push_ucs2_allocate() failed!\n")); goto done; } @@ -603,11 +604,9 @@ static bool must_mangle(const char *name, { smb_ucs2_t *name_ucs2 = NULL; NTSTATUS status; - size_t converted_size; - magic_char = lp_magicchar(p); - if (!push_ucs2_allocate(&name_ucs2, name, &converted_size)) { + if (push_ucs2_allocate(&name_ucs2, name) == (size_t)-1) { DEBUG(0, ("push_ucs2_allocate failed!\n")); return False; } @@ -638,14 +637,12 @@ static bool hash_name_to_8_3(const char *in, const struct share_params *p) { smb_ucs2_t *in_ucs2 = NULL; - size_t converted_size; - magic_char = lp_magicchar(p); DEBUG(5,("hash_name_to_8_3( %s, cache83 = %s)\n", in, cache83 ? "True" : "False")); - if (!push_ucs2_allocate(&in_ucs2, in, &converted_size)) { + if (push_ucs2_allocate(&in_ucs2, in) == (size_t)-1) { DEBUG(0, ("push_ucs2_allocate failed!\n")); return False; } diff --git a/source/smbd/message.c b/source/smbd/message.c index 62df5c37eb..a870f03df9 100644 --- a/source/smbd/message.c +++ b/source/smbd/message.c @@ -45,7 +45,7 @@ static void msg_deliver(struct msg_state *state) int i; int fd; char *msg; - size_t len; + int len; ssize_t sz; fstring alpha_buf; char *s; @@ -72,17 +72,18 @@ static void msg_deliver(struct msg_state *state) * Incoming message is in DOS codepage format. Convert to UNIX. */ - if (!convert_string_talloc(talloc_tos(), CH_DOS, CH_UNIX, state->msg, - talloc_get_size(state->msg), (void *)&msg, - &len, true)) { + len = convert_string_talloc( + talloc_tos(), CH_DOS, CH_UNIX, state->msg, + talloc_get_size(state->msg), (void *)&msg, true); + + if (len == -1) { DEBUG(3, ("Conversion failed, delivering message in DOS " "codepage format\n")); msg = state->msg; } for (i = 0; i < len; i++) { - if ((msg[i] == '\r') && - (i < (len-1)) && (msg[i+1] == '\n')) { + if ((msg[i] == '\r') && (i < (len-1)) && (msg[i+1] == '\n')) { continue; } sz = write(fd, &msg[i], 1); diff --git a/source/smbd/msdfs.c b/source/smbd/msdfs.c index 32240ff0d5..aef4ff6638 100644 --- a/source/smbd/msdfs.c +++ b/source/smbd/msdfs.c @@ -215,40 +215,37 @@ static NTSTATUS parse_dfs_path(connection_struct *conn, Note this CHANGES CWD !!!! JRA. *********************************************************/ -NTSTATUS create_conn_struct(TALLOC_CTX *ctx, - connection_struct **pconn, +static NTSTATUS create_conn_struct(TALLOC_CTX *ctx, + connection_struct *conn, int snum, - const char *path, - char **poldcwd) + const char *path) { - connection_struct *conn; char *connpath; - char *oldcwd; - conn = TALLOC_ZERO_P(ctx, connection_struct); - if (conn == NULL) { - return NT_STATUS_NO_MEMORY; - } + ZERO_STRUCTP(conn); - connpath = talloc_strdup(conn, path); + connpath = talloc_strdup(ctx, path); if (!connpath) { - TALLOC_FREE(conn); return NT_STATUS_NO_MEMORY; } - connpath = talloc_string_sub(conn, + connpath = talloc_string_sub(ctx, connpath, "%S", lp_servicename(snum)); if (!connpath) { - TALLOC_FREE(conn); return NT_STATUS_NO_MEMORY; } /* needed for smbd_vfs_init() */ - if (!(conn->params = TALLOC_ZERO_P(conn, struct share_params))) { + if ((conn->mem_ctx=talloc_init("connection_struct")) == NULL) { + DEBUG(0,("talloc_init(connection_struct) failed!\n")); + return NT_STATUS_NO_MEMORY; + } + + if (!(conn->params = TALLOC_ZERO_P(conn->mem_ctx, + struct share_params))) { DEBUG(0, ("TALLOC failed\n")); - TALLOC_FREE(conn); return NT_STATUS_NO_MEMORY; } @@ -269,14 +266,6 @@ NTSTATUS create_conn_struct(TALLOC_CTX *ctx, * user we will fail.... WTF ? JRA. */ - oldcwd = vfs_GetWd(ctx, conn); - if (oldcwd == NULL) { - NTSTATUS status = map_nt_error_from_unix(errno); - DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno))); - conn_free_internal(conn); - return status; - } - if (vfs_ChDir(conn,conn->connectpath) != 0) { NTSTATUS status = map_nt_error_from_unix(errno); DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. " @@ -286,9 +275,6 @@ NTSTATUS create_conn_struct(TALLOC_CTX *ctx, return status; } - *pconn = conn; - *poldcwd = oldcwd; - return NT_STATUS_OK; } @@ -684,17 +670,6 @@ static NTSTATUS dfs_redirect(TALLOC_CTX *ctx, return NT_STATUS_OK; } - if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn))) - || (strequal(pdp->servicename, HOMES_NAME) - && strequal(lp_servicename(SNUM(conn)), - conn->server_info->sanitized_username) )) ) { - - /* The given sharename doesn't match this connection. */ - TALLOC_FREE(pdp); - - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - status = dfs_path_lookup(ctx, conn, path_in, pdp, search_wcard_flag, NULL, NULL); if (!NT_STATUS_IS_OK(status)) { @@ -765,18 +740,19 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, int *consumedcntp, bool *self_referralp) { - struct connection_struct *conn; + struct connection_struct conns; + struct connection_struct *conn = &conns; char *targetpath = NULL; int snum; NTSTATUS status = NT_STATUS_NOT_FOUND; bool dummy; struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path); - char *oldpath; if (!pdp) { return NT_STATUS_NO_MEMORY; } + ZERO_STRUCT(conns); *self_referralp = False; status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy); @@ -880,8 +856,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, return NT_STATUS_OK; } - status = create_conn_struct(ctx, &conn, snum, lp_pathname(snum), - &oldpath); + status = create_conn_struct(ctx, conn, snum, lp_pathname(snum)); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(pdp); return status; @@ -896,7 +871,6 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) { DEBUG(3,("get_referred_path: No valid referrals for path %s\n", dfs_path)); - vfs_ChDir(conn, oldpath); conn_free_internal(conn); TALLOC_FREE(pdp); return status; @@ -908,13 +882,11 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, &jucn->referral_count)) { DEBUG(3,("get_referred_path: failed to parse symlink " "target %s\n", targetpath )); - vfs_ChDir(conn, oldpath); conn_free_internal(conn); TALLOC_FREE(pdp); return NT_STATUS_NOT_FOUND; } - vfs_ChDir(conn, oldpath); conn_free_internal(conn); TALLOC_FREE(pdp); return NT_STATUS_OK; @@ -1309,30 +1281,26 @@ bool create_junction(TALLOC_CTX *ctx, **********************************************************************/ static bool junction_to_local_path(const struct junction_map *jucn, - char **pp_path_out, - connection_struct **conn_out, - char **oldpath) + char **pp_path_out, + connection_struct *conn_out) { int snum; - NTSTATUS status; snum = lp_servicenumber(jucn->service_name); if(snum < 0) { return False; } - status = create_conn_struct(talloc_tos(), conn_out, snum, - lp_pathname(snum), oldpath); - if (!NT_STATUS_IS_OK(status)) { + if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(), + conn_out, snum, + lp_pathname(snum)))) { return False; } - *pp_path_out = talloc_asprintf(*conn_out, + *pp_path_out = talloc_asprintf(conn_out->mem_ctx, "%s/%s", lp_pathname(snum), jucn->volume_name); if (!*pp_path_out) { - vfs_ChDir(*conn_out, *oldpath); - conn_free_internal(*conn_out); return False; } return True; @@ -1341,19 +1309,21 @@ static bool junction_to_local_path(const struct junction_map *jucn, bool create_msdfs_link(const struct junction_map *jucn) { char *path = NULL; - char *cwd; char *msdfs_link = NULL; - connection_struct *conn; + connection_struct conns; + connection_struct *conn = &conns; int i=0; bool insert_comma = False; bool ret = False; - if(!junction_to_local_path(jucn, &path, &conn, &cwd)) { + ZERO_STRUCT(conns); + + if(!junction_to_local_path(jucn, &path, conn)) { return False; } /* Form the msdfs_link contents */ - msdfs_link = talloc_strdup(conn, "msdfs:"); + msdfs_link = talloc_strdup(conn->mem_ctx, "msdfs:"); if (!msdfs_link) { goto out; } @@ -1406,7 +1376,7 @@ bool create_msdfs_link(const struct junction_map *jucn) ret = True; out: - vfs_ChDir(conn, cwd); + conn_free_internal(conn); return ret; } @@ -1414,19 +1384,18 @@ out: bool remove_msdfs_link(const struct junction_map *jucn) { char *path = NULL; - char *cwd; - connection_struct *conn; + connection_struct conns; + connection_struct *conn = &conns; bool ret = False; - if (!junction_to_local_path(jucn, &path, &conn, &cwd)) { - return false; - } + ZERO_STRUCT(conns); - if( SMB_VFS_UNLINK(conn, path) == 0 ) { - ret = True; + if( junction_to_local_path(jucn, &path, conn) ) { + if( SMB_VFS_UNLINK(conn, path) == 0 ) { + ret = True; + } } - vfs_ChDir(conn, cwd); conn_free_internal(conn); return ret; } @@ -1442,9 +1411,9 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum) char *dname = NULL; const char *connect_path = lp_pathname(snum); const char *msdfs_proxy = lp_msdfs_proxy(snum); - connection_struct *conn; - NTSTATUS status; - char *cwd; + connection_struct conn; + + ZERO_STRUCT(conn); if(*connect_path == '\0') { return 0; @@ -1454,11 +1423,8 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum) * Fake up a connection struct for the VFS layer. */ - status = create_conn_struct(talloc_tos(), &conn, snum, connect_path, - &cwd); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("create_conn_struct failed: %s\n", - nt_errstr(status))); + if (!NT_STATUS_IS_OK(create_conn_struct(talloc_tos(), + &conn, snum, connect_path))) { return 0; } @@ -1471,24 +1437,24 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum) } /* Now enumerate all dfs links */ - dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0); + dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0); if(!dirp) { goto out; } - while ((dname = vfs_readdirname(conn, dirp)) != NULL) { - if (is_msdfs_link(conn, + while ((dname = vfs_readdirname(&conn, dirp)) != NULL) { + if (is_msdfs_link(&conn, dname, NULL)) { cnt++; } } - SMB_VFS_CLOSEDIR(conn,dirp); + SMB_VFS_CLOSEDIR(&conn,dirp); out: - vfs_ChDir(conn, cwd); - conn_free_internal(conn); + + conn_free_internal(&conn); return cnt; } @@ -1506,10 +1472,10 @@ static int form_junctions(TALLOC_CTX *ctx, const char *connect_path = lp_pathname(snum); char *service_name = lp_servicename(snum); const char *msdfs_proxy = lp_msdfs_proxy(snum); - connection_struct *conn; + connection_struct conn; struct referral *ref = NULL; - char *cwd; - NTSTATUS status; + + ZERO_STRUCT(conn); if (jn_remain == 0) { return 0; @@ -1523,10 +1489,7 @@ static int form_junctions(TALLOC_CTX *ctx, * Fake up a connection struct for the VFS layer. */ - status = create_conn_struct(ctx, &conn, snum, connect_path, &cwd); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("create_conn_struct failed: %s\n", - nt_errstr(status))); + if (!NT_STATUS_IS_OK(create_conn_struct(ctx, &conn, snum, connect_path))) { return 0; } @@ -1570,12 +1533,12 @@ static int form_junctions(TALLOC_CTX *ctx, } /* Now enumerate all dfs links */ - dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0); + dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0); if(!dirp) { goto out; } - while ((dname = vfs_readdirname(conn, dirp)) != NULL) { + while ((dname = vfs_readdirname(&conn, dirp)) != NULL) { char *link_target = NULL; if (cnt >= jn_remain) { DEBUG(2, ("form_junctions: ran out of MSDFS " @@ -1583,7 +1546,7 @@ static int form_junctions(TALLOC_CTX *ctx, goto out; } if (is_msdfs_link_internal(ctx, - conn, + &conn, dname, &link_target, NULL)) { if (parse_msdfs_symlink(ctx, @@ -1609,11 +1572,10 @@ static int form_junctions(TALLOC_CTX *ctx, out: if (dirp) { - SMB_VFS_CLOSEDIR(conn,dirp); + SMB_VFS_CLOSEDIR(&conn,dirp); } - vfs_ChDir(conn, cwd); - conn_free_internal(conn); + conn_free_internal(&conn); return cnt; } diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c index 84f111fb02..9f56949eeb 100644 --- a/source/smbd/negprot.c +++ b/source/smbd/negprot.c @@ -516,7 +516,6 @@ void reply_negprot(struct smb_request *req) int num_cliprotos; char **cliprotos; int i; - size_t converted_size; static bool done_negprot = False; @@ -556,8 +555,8 @@ void reply_negprot(struct smb_request *req) cliprotos = tmp; - if (!pull_ascii_talloc(cliprotos, &cliprotos[num_cliprotos], p, - &converted_size)) { + if (pull_ascii_talloc(cliprotos, &cliprotos[num_cliprotos], p) + == (size_t)-1) { DEBUG(0, ("pull_ascii_talloc failed\n")); TALLOC_FREE(cliprotos); reply_nterror(req, NT_STATUS_NO_MEMORY); diff --git a/source/smbd/notify.c b/source/smbd/notify.c index 139dfe7d5b..eb3384d9a4 100644 --- a/source/smbd/notify.c +++ b/source/smbd/notify.c @@ -114,9 +114,6 @@ static bool notify_marshall_changes(int num_changes, if (prs_offset(ps) > max_offset) { /* Too much data for client. */ - DEBUG(10, ("Client only wanted %d bytes, trying to " - "marshall %d bytes\n", (int)max_offset, - (int)prs_offset(ps))); return False; } } @@ -259,9 +256,6 @@ NTSTATUS change_notify_add_request(const struct smb_request *req, struct notify_change_request *request = NULL; struct notify_mid_map *map = NULL; - DEBUG(10, ("change_notify_add_request: Adding request for %s: " - "max_param = %d\n", fsp->fsp_name, (int)max_param)); - if (!(request = SMB_MALLOC_P(struct notify_change_request)) || !(map = SMB_MALLOC_P(struct notify_mid_map))) { SAFE_FREE(request); diff --git a/source/smbd/ntquotas.c b/source/smbd/ntquotas.c index c616c494dc..fcccf9d9fc 100644 --- a/source/smbd/ntquotas.c +++ b/source/smbd/ntquotas.c @@ -222,13 +222,6 @@ int vfs_get_user_ntquota_list(files_struct *fsp, SMB_NTQUOTA_LIST **qt_list) return 0; } -static int quota_handle_destructor(SMB_NTQUOTA_HANDLE *handle) -{ - if (handle->quota_list) - free_ntquota_list(&handle->quota_list); - return 0; -} - void *init_quota_handle(TALLOC_CTX *mem_ctx) { SMB_NTQUOTA_HANDLE *qt_handle; @@ -242,6 +235,24 @@ void *init_quota_handle(TALLOC_CTX *mem_ctx) return NULL; } - talloc_set_destructor(qt_handle, quota_handle_destructor); - return (void *)qt_handle; + return (void *)qt_handle; +} + +void destroy_quota_handle(void **pqt_handle) +{ + SMB_NTQUOTA_HANDLE *qt_handle = NULL; + if (!pqt_handle||!(*pqt_handle)) + return; + + qt_handle = (SMB_NTQUOTA_HANDLE *)(*pqt_handle); + + + if (qt_handle->quota_list) + free_ntquota_list(&qt_handle->quota_list); + + qt_handle->quota_list = NULL; + qt_handle->tmp_list = NULL; + qt_handle = NULL; + + return; } diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index 567c428bb8..13caf77b98 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -22,6 +22,28 @@ extern int max_send; extern enum protocol_types Protocol; +extern struct current_user current_user; + +static const char *known_nt_pipes[] = { + "\\LANMAN", + "\\srvsvc", + "\\samr", + "\\wkssvc", + "\\NETLOGON", + "\\ntlsa", + "\\ntsvcs", + "\\lsass", + "\\lsarpc", + "\\winreg", + "\\initshutdown", + "\\spoolss", + "\\netdfs", + "\\rpcecho", + "\\svcctl", + "\\eventlog", + "\\unixinfo", + NULL +}; static char *nttrans_realloc(char **ptr, size_t size) { @@ -268,12 +290,25 @@ static void nt_open_pipe(char *fname, connection_struct *conn, struct smb_request *req, int *ppnum) { smb_np_struct *p = NULL; + int i; DEBUG(4,("nt_open_pipe: Opening pipe %s.\n", fname)); /* See if it is one we want to handle. */ - if (!is_known_pipename(fname)) { + if (lp_disable_spoolss() && strequal(fname, "\\spoolss")) { + reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ERRDOS, ERRbadpipe); + return; + } + + for( i = 0; known_nt_pipes[i]; i++ ) { + if( strequal(fname,known_nt_pipes[i])) { + break; + } + } + + if ( known_nt_pipes[i] == NULL ) { reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERRbadpipe); return; @@ -739,7 +774,13 @@ static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len, security_info_sent &= ~DACL_SECURITY_INFORMATION; } - status = SMB_VFS_FSET_NT_ACL(fsp, security_info_sent, psd); + if (fsp->fh->fd != -1) { + status = SMB_VFS_FSET_NT_ACL(fsp, security_info_sent, psd); + } + else { + status = SMB_VFS_SET_NT_ACL(fsp, fsp->fsp_name, + security_info_sent, psd); + } TALLOC_FREE(psd); @@ -1495,7 +1536,7 @@ static void call_nt_transact_rename(connection_struct *conn, } fsp = file_fsp(SVAL(params, 0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { return; } srvstr_get_path_wcard(ctx, params, req->flags2, &new_name, params+4, @@ -1587,8 +1628,14 @@ static void call_nt_transact_query_security_desc(connection_struct *conn, if (!lp_nt_acl_support(SNUM(conn))) { status = get_null_nt_acl(talloc_tos(), &psd); } else { - status = SMB_VFS_FGET_NT_ACL( - fsp, security_info_wanted, &psd); + if (fsp->fh->fd != -1) { + status = SMB_VFS_FGET_NT_ACL( + fsp, security_info_wanted, &psd); + } + else { + status = SMB_VFS_GET_NT_ACL( + conn, fsp->fsp_name, security_info_wanted, &psd); + } } if (!NT_STATUS_IS_OK(status)) { @@ -1748,7 +1795,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on FID[0x%04X]\n",fidnum)); - if (!fsp_belongs_conn(conn, req, fsp)) { + if (!fsp_belongs_conn(conn, req, fsp, ¤t_user)) { return; } @@ -1803,7 +1850,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, uint32 i; char *cur_pdata; - if (!fsp_belongs_conn(conn, req, fsp)) { + if (!fsp_belongs_conn(conn, req, fsp, ¤t_user)) { return; } @@ -1926,7 +1973,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n",fidnum)); - if (!fsp_belongs_conn(conn, req, fsp)) { + if (!fsp_belongs_conn(conn, req, fsp, ¤t_user)) { return; } @@ -2011,10 +2058,9 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, ZERO_STRUCT(qt); /* access check */ - if (conn->server_info->utok.uid != 0) { - DEBUG(1,("get_user_quota: access_denied service [%s] user " - "[%s]\n", lp_servicename(SNUM(conn)), - conn->server_info->unix_name)); + if (current_user.ut.uid != 0) { + DEBUG(1,("get_user_quota: access_denied service [%s] user [%s]\n", + lp_servicename(SNUM(conn)),conn->user)); reply_doserror(req, ERRDOS, ERRnoaccess); return; } @@ -2031,7 +2077,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, /* maybe we can check the quota_fnum */ fsp = file_fsp(SVAL(params,0)); - if (!check_fsp_ntquota_handle(conn, req, fsp)) { + if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); reply_nterror(req, NT_STATUS_INVALID_HANDLE); return; @@ -2040,7 +2086,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, /* the NULL pointer checking for fsp->fake_file_handle->pd * is done by CHECK_NTQUOTA_HANDLE_OK() */ - qt_handle = (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->private_data; + qt_handle = (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->pd; level = SVAL(params,2); @@ -2278,10 +2324,9 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, ZERO_STRUCT(qt); /* access check */ - if (conn->server_info->utok.uid != 0) { - DEBUG(1,("set_user_quota: access_denied service [%s] user " - "[%s]\n", lp_servicename(SNUM(conn)), - conn->server_info->unix_name)); + if (current_user.ut.uid != 0) { + DEBUG(1,("set_user_quota: access_denied service [%s] user [%s]\n", + lp_servicename(SNUM(conn)),conn->user)); reply_doserror(req, ERRDOS, ERRnoaccess); return; } @@ -2298,7 +2343,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, /* maybe we can check the quota_fnum */ fsp = file_fsp(SVAL(params,0)); - if (!check_fsp_ntquota_handle(conn, req, fsp)) { + if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); reply_nterror(req, NT_STATUS_INVALID_HANDLE); return; @@ -2560,7 +2605,7 @@ void reply_nttrans(struct smb_request *req) return; } - if ((state = TALLOC_P(conn, struct trans_state)) == NULL) { + if ((state = TALLOC_P(conn->mem_ctx, struct trans_state)) == NULL) { reply_doserror(req, ERRSRV, ERRaccess); END_PROFILE(SMBnttrans); return; diff --git a/source/smbd/open.c b/source/smbd/open.c index ad024a58ef..afe8d5e9b3 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -22,6 +22,8 @@ #include "includes.h" extern const struct generic_mapping file_generic_mapping; +extern struct current_user current_user; +extern userdom_struct current_user_info; extern bool global_client_failed_oplock_break; struct deferred_open_record { @@ -321,7 +323,7 @@ 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, path, + inherit_access_acl(conn, parent_dir, path, unx_mode); } @@ -389,6 +391,7 @@ static NTSTATUS open_file(files_struct *fsp, fsp->modified = False; fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = False; + fsp->is_stat = False; if (conn->aio_write_behind_list && is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) { fsp->aio_write_behind = True; @@ -398,8 +401,8 @@ static NTSTATUS open_file(files_struct *fsp, fsp->wcp = NULL; /* Write cache pointer. */ DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", - conn->server_info->unix_name, - fsp->fsp_name, + *current_user_info.smb_name ? + current_user_info.smb_name : conn->user,fsp->fsp_name, BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write), conn->num_files_open + 1)); @@ -1178,7 +1181,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname)); - return print_fsp_open(conn, fname, req->vuid, result); + return print_fsp_open(conn, fname, result); } if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir, @@ -1568,7 +1571,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, } if (((can_access_mask & FILE_WRITE_DATA) && !CAN_WRITE(conn)) || - !can_access_file_data(conn,fname,psbuf,can_access_mask)) { + !can_access_file(conn,fname,psbuf,can_access_mask)) { can_access = False; } @@ -1847,8 +1850,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, new_file_created = True; } - set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, - fsp->oplock_type, new_file_created); + set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type, new_file_created); /* Handle strange delete on close create semantics. */ if ((create_options & FILE_DELETE_ON_CLOSE) @@ -2057,7 +2059,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn, } if (lp_inherit_perms(SNUM(conn))) { - inherit_access_posix_acl(conn, parent_dir, name, mode); + inherit_access_acl(conn, parent_dir, name, mode); } if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) { @@ -2224,6 +2226,7 @@ NTSTATUS open_directory(connection_struct *conn, fsp->oplock_type = NO_OPLOCK; fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = True; + fsp->is_stat = False; fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False; string_set(&fsp->fsp_name,fname); @@ -2250,8 +2253,7 @@ NTSTATUS open_directory(connection_struct *conn, return status; } - set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, NO_OPLOCK, - True); + set_share_mode(lck, fsp, current_user.ut.uid, 0, NO_OPLOCK, True); /* For directories the delete on close bit at open time seems always to be honored on close... See test 19 in Samba4 BASE-DELETE. */ @@ -2307,6 +2309,58 @@ NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, cons } /**************************************************************************** + Open a pseudo-file (no locking checks - a 'stat' open). +****************************************************************************/ + +NTSTATUS open_file_stat(connection_struct *conn, struct smb_request *req, + const char *fname, SMB_STRUCT_STAT *psbuf, + files_struct **result) +{ + files_struct *fsp = NULL; + NTSTATUS status; + + if (!VALID_STAT(*psbuf)) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* Can't 'stat' open directories. */ + if(S_ISDIR(psbuf->st_mode)) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + status = file_new(conn, &fsp); + if(!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(5,("open_file_stat: 'opening' file %s\n", fname)); + + /* + * Setup the files_struct for it. + */ + + 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; + fsp->can_read = False; + fsp->can_write = False; + fsp->print_file = False; + fsp->modified = False; + fsp->oplock_type = NO_OPLOCK; + fsp->sent_oplock_break = NO_BREAK_SENT; + fsp->is_directory = False; + fsp->is_stat = True; + string_set(&fsp->fsp_name,fname); + + conn->num_files_open++; + + *result = fsp; + return NT_STATUS_OK; +} + +/**************************************************************************** Receive notification that one of our open files has been renamed by another smbd process. ****************************************************************************/ @@ -2608,7 +2662,9 @@ 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, fname))) { + && (((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY) + && !lp_delete_readonly(SNUM(conn))) + || !can_delete_file_in_directory(conn, fname))) { status = NT_STATUS_ACCESS_DENIED; goto fail; } @@ -2996,8 +3052,7 @@ NTSTATUS create_file(connection_struct *conn, * also tries a QUERY_FILE_INFO on the file and then * close it */ - status = open_fake_file(conn, req->vuid, - fake_file_type, fname, + status = open_fake_file(conn, fake_file_type, fname, access_mask, &fsp); if (!NT_STATUS_IS_OK(status)) { goto fail; diff --git a/source/smbd/password.c b/source/smbd/password.c index 1d3514429f..80eba562c5 100644 --- a/source/smbd/password.c +++ b/source/smbd/password.c @@ -119,6 +119,8 @@ void invalidate_vuid(uint16 vuid) session_yield(vuser); + data_blob_free(&vuser->session_key); + if (vuser->auth_ntlmssp_state) { auth_ntlmssp_end(&vuser->auth_ntlmssp_state); } @@ -127,7 +129,7 @@ void invalidate_vuid(uint16 vuid) /* clear the vuid from the 'cache' on each connection, and from the vuid 'owner' of connections */ - conn_clear_vuid_caches(vuid); + conn_clear_vuid_cache(vuid); TALLOC_FREE(vuser); num_validated_vuids--; @@ -199,37 +201,6 @@ int register_initial_vuid(void) return vuser->vuid; } -static int register_homes_share(const char *username) -{ - int result; - struct passwd *pwd; - - result = lp_servicenumber(username); - if (result != -1) { - DEBUG(3, ("Using static (or previously created) service for " - "user '%s'; path = '%s'\n", username, - lp_pathname(result))); - return result; - } - - pwd = getpwnam_alloc(talloc_tos(), username); - - if ((pwd == NULL) || (pwd->pw_dir[0] == '\0')) { - DEBUG(3, ("No home directory defined for user '%s'\n", - username)); - TALLOC_FREE(pwd); - return -1; - } - - DEBUG(3, ("Adding homes service for user '%s' using home directory: " - "'%s'\n", username, pwd->pw_dir)); - - result = add_home_service(username, username, pwd->pw_dir); - - TALLOC_FREE(pwd); - return result; -} - /** * register that a valid login has been performed, establish 'session'. * @param server_info The token returned from the authentication process. @@ -250,47 +221,109 @@ static int register_homes_share(const char *username) int register_existing_vuid(uint16 vuid, auth_serversupplied_info *server_info, + DATA_BLOB session_key, DATA_BLOB response_blob, const char *smb_name) { - fstring tmp; - user_struct *vuser; - - vuser = get_partial_auth_user_struct(vuid); + user_struct *vuser = get_partial_auth_user_struct(vuid); if (!vuser) { goto fail; } /* Use this to keep tabs on all our info from the authentication */ - vuser->server_info = talloc_move(vuser, &server_info); + vuser->server_info = server_info; + + /* Ensure that the server_info will disappear with + * the vuser it is now attached to */ + + talloc_steal(vuser, vuser->server_info); + + /* the next functions should be done by a SID mapping system (SMS) as + * the new real sam db won't have reference to unix uids or gids + */ + + vuser->uid = server_info->uid; + vuser->gid = server_info->gid; + + vuser->n_groups = server_info->n_groups; + if (vuser->n_groups) { + if (!(vuser->groups = (gid_t *)talloc_memdup(vuser, + server_info->groups, + sizeof(gid_t)*vuser->n_groups))) { + DEBUG(0,("register_existing_vuid: " + "failed to talloc_memdup vuser->groups\n")); + goto fail; + } + } + + vuser->guest = server_info->guest; + fstrcpy(vuser->user.unix_name, server_info->unix_name); /* This is a potentially untrusted username */ - alpha_strcpy(tmp, smb_name, ". _-$", sizeof(tmp)); + alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$", + sizeof(vuser->user.smb_name)); + + fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account)); + fstrcpy(vuser->user.full_name, + pdb_get_fullname(server_info->sam_account)); + + { + /* Keep the homedir handy */ + const char *homedir = + pdb_get_homedir(server_info->sam_account); + const char *logon_script = + pdb_get_logon_script(server_info->sam_account); + + if (!IS_SAM_DEFAULT(server_info->sam_account, + PDB_UNIXHOMEDIR)) { + const char *unix_homedir = + pdb_get_unix_homedir(server_info->sam_account); + if (unix_homedir) { + vuser->unix_homedir = unix_homedir; + } + } else { + struct passwd *passwd = + getpwnam_alloc(vuser, vuser->user.unix_name); + if (passwd) { + vuser->unix_homedir = passwd->pw_dir; + /* Ensure that the unix_homedir now + * belongs to vuser, so it goes away + * with it, not with passwd below: */ + talloc_steal(vuser, vuser->unix_homedir); + TALLOC_FREE(passwd); + } + } - vuser->server_info->sanitized_username = talloc_strdup( - vuser->server_info, tmp); + if (homedir) { + vuser->homedir = homedir; + } + if (logon_script) { + vuser->logon_script = logon_script; + } + } + vuser->session_key = session_key; DEBUG(10,("register_existing_vuid: (%u,%u) %s %s %s guest=%d\n", - (unsigned int)vuser->server_info->utok.uid, - (unsigned int)vuser->server_info->utok.gid, - vuser->server_info->unix_name, - vuser->server_info->sanitized_username, - pdb_get_domain(vuser->server_info->sam_account), - vuser->server_info->guest )); + (unsigned int)vuser->uid, + (unsigned int)vuser->gid, + vuser->user.unix_name, vuser->user.smb_name, + vuser->user.domain, vuser->guest )); DEBUG(3, ("register_existing_vuid: User name: %s\t" - "Real name: %s\n", vuser->server_info->unix_name, - pdb_get_fullname(vuser->server_info->sam_account))); + "Real name: %s\n", vuser->user.unix_name, + vuser->user.full_name)); - if (!vuser->server_info->ptok) { + if (server_info->ptok) { + vuser->nt_user_token = dup_nt_token(vuser, server_info->ptok); + } else { DEBUG(1, ("register_existing_vuid: server_info does not " "contain a user_token - cannot continue\n")); goto fail; } DEBUG(3,("register_existing_vuid: UNIX uid %d is UNIX user %s, " - "and will be vuid %u\n", (int)vuser->server_info->utok.uid, - vuser->server_info->unix_name, vuser->vuid)); + "and will be vuid %u\n", + (int)vuser->uid,vuser->user.unix_name, vuser->vuid)); next_vuid++; num_validated_vuids++; @@ -309,26 +342,34 @@ int register_existing_vuid(uint16 vuid, If a share exists by this name (autoloaded or not) reuse it . */ vuser->homes_snum = -1; - - if (!vuser->server_info->guest) { - vuser->homes_snum = register_homes_share( - vuser->server_info->unix_name); + if ( (!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir)) { + int servicenumber = lp_servicenumber(vuser->user.unix_name); + if ( servicenumber == -1 ) { + DEBUG(3, ("Adding homes service for user '%s' using " + "home directory: '%s'\n", + vuser->user.unix_name, vuser->unix_homedir)); + vuser->homes_snum = + add_home_service(vuser->user.unix_name, + vuser->user.unix_name, + vuser->unix_homedir); + } else { + DEBUG(3, ("Using static (or previously created) " + "service for user '%s'; path = '%s'\n", + vuser->user.unix_name, + lp_pathname(servicenumber) )); + vuser->homes_snum = servicenumber; + } } - if (srv_is_signing_negotiated() && !vuser->server_info->guest && + if (srv_is_signing_negotiated() && !vuser->guest && !srv_signing_started()) { /* Try and turn on server signing on the first non-guest * sessionsetup. */ - srv_set_signing(vuser->server_info->user_session_key, response_blob); + srv_set_signing(vuser->session_key, response_blob); } /* fill in the current_user_info struct */ - set_current_user_info( - vuser->server_info->sanitized_username, - vuser->server_info->unix_name, - pdb_get_fullname(vuser->server_info->sam_account), - pdb_get_domain(vuser->server_info->sam_account)); - + set_current_user_info( &vuser->user ); return vuser->vuid; fail: diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c index 4fdcdcc557..6b4b83d97d 100644 --- a/source/smbd/pipes.c +++ b/source/smbd/pipes.c @@ -44,6 +44,9 @@ struct pipe_dbrec { fstring user; }; + +extern struct pipe_id_info pipe_names[]; + /**************************************************************************** Reply to an open and X on a named pipe. This code is basically stolen from reply_open_and_X with some @@ -56,6 +59,7 @@ void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req) char *pipe_name = NULL; smb_np_struct *p; int size=0,fmode=0,mtime=0,rmode=0; + int i; TALLOC_CTX *ctx = talloc_tos(); /* XXXX we need to handle passed times, sattr and flags */ @@ -78,7 +82,13 @@ void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req) DEBUG(4,("Opening pipe %s.\n", pipe_name)); /* See if it is one we want to handle. */ - if (!is_known_pipename(pipe_name)) { + for( i = 0; pipe_names[i].client_pipe ; i++ ) { + if( strequal(pipe_name,pipe_names[i].client_pipe)) { + break; + } + } + + if (pipe_names[i].client_pipe == NULL) { reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERRbadpipe); return; diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index 7479aea076..d798fa8da4 100644 --- a/source/smbd/posix_acls.c +++ b/source/smbd/posix_acls.c @@ -904,7 +904,7 @@ static SEC_ACCESS map_canon_ace_perms(int snum, if (directory_ace) { nt_mask = UNIX_DIRECTORY_ACCESS_RWX; } else { - nt_mask = (UNIX_ACCESS_RWX & ~DELETE_ACCESS); + nt_mask = UNIX_ACCESS_RWX; } } else if ((perms & ALL_ACE_PERMS) == (mode_t)0) { /* @@ -2207,7 +2207,9 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn, posix_id unix_ug; enum ace_owner owner_type; - entry_id = SMB_ACL_NEXT_ENTRY; + /* get_next... */ + if (entry_id == SMB_ACL_FIRST_ENTRY) + entry_id = SMB_ACL_NEXT_ENTRY; /* Is this a MASK entry ? */ if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) @@ -3701,7 +3703,9 @@ int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode SMB_ACL_TAG_T tagtype; SMB_ACL_PERMSET_T permset; - entry_id = SMB_ACL_NEXT_ENTRY; + /* get_next... */ + if (entry_id == SMB_ACL_FIRST_ENTRY) + entry_id = SMB_ACL_NEXT_ENTRY; if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1) break; @@ -3739,7 +3743,9 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo SMB_ACL_PERMSET_T permset; mode_t perms; - entry_id = SMB_ACL_NEXT_ENTRY; + /* get_next... */ + if (entry_id == SMB_ACL_FIRST_ENTRY) + entry_id = SMB_ACL_NEXT_ENTRY; if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) return -1; @@ -3796,7 +3802,7 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo resulting ACL on TO. Note that name is in UNIX character set. ****************************************************************************/ -static int copy_access_posix_acl(connection_struct *conn, const char *from, const char *to, mode_t mode) +static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode) { SMB_ACL_T posix_acl = NULL; int ret = -1; @@ -3823,27 +3829,7 @@ static int copy_access_posix_acl(connection_struct *conn, const char *from, cons int chmod_acl(connection_struct *conn, const char *name, mode_t mode) { - return copy_access_posix_acl(conn, name, name, mode); -} - -/**************************************************************************** - Check for an existing default POSIX ACL on a directory. -****************************************************************************/ - -static bool directory_has_default_posix_acl(connection_struct *conn, const char *fname) -{ - SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT); - bool has_acl = False; - SMB_ACL_ENTRY_T entry; - - if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) { - has_acl = True; - } - - if (def_acl) { - SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); - } - return has_acl; + return copy_access_acl(conn, name, name, mode); } /**************************************************************************** @@ -3851,13 +3837,13 @@ static bool directory_has_default_posix_acl(connection_struct *conn, const char inherit this Access ACL to file name. ****************************************************************************/ -int inherit_access_posix_acl(connection_struct *conn, const char *inherit_from_dir, +int inherit_access_acl(connection_struct *conn, const char *inherit_from_dir, const char *name, mode_t mode) { - if (directory_has_default_posix_acl(conn, inherit_from_dir)) + if (directory_has_default_acl(conn, inherit_from_dir)) return 0; - return copy_access_posix_acl(conn, inherit_from_dir, name, mode); + return copy_access_acl(conn, inherit_from_dir, name, mode); } /**************************************************************************** @@ -3886,6 +3872,26 @@ int fchmod_acl(files_struct *fsp, mode_t mode) } /**************************************************************************** + Check for an existing default POSIX ACL on a directory. +****************************************************************************/ + +bool directory_has_default_acl(connection_struct *conn, const char *fname) +{ + SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT); + bool has_acl = False; + SMB_ACL_ENTRY_T entry; + + if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) { + has_acl = True; + } + + if (def_acl) { + SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); + } + return has_acl; +} + +/**************************************************************************** Map from wire type to permset. ****************************************************************************/ @@ -4159,7 +4165,9 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c SMB_ACL_TAG_T tagtype; SMB_ACL_PERMSET_T permset; - entry_id = SMB_ACL_NEXT_ENTRY; + /* get_next... */ + if (entry_id == SMB_ACL_FIRST_ENTRY) + entry_id = SMB_ACL_NEXT_ENTRY; if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) { DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n", @@ -4273,29 +4281,30 @@ bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char * SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) { SEC_DESC *psd, *ret_sd; - connection_struct *conn; + connection_struct conn; files_struct finfo; struct fd_handle fh; - conn = TALLOC_ZERO_P(ctx, connection_struct); - if (conn == NULL) { - DEBUG(0, ("talloc failed\n")); + ZERO_STRUCT( conn ); + + if ( !(conn.mem_ctx = talloc_init( "novfs_get_nt_acl" )) ) { + DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n")); return NULL; } - if (!(conn->params = TALLOC_P(conn, struct share_params))) { + if (!(conn.params = TALLOC_P(conn.mem_ctx, struct share_params))) { DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n")); - TALLOC_FREE(conn); + TALLOC_FREE(conn.mem_ctx); return NULL; } - conn->params->service = -1; + conn.params->service = -1; - set_conn_connectpath(conn, "/"); + set_conn_connectpath(&conn, "/"); - if (!smbd_vfs_init(conn)) { + if (!smbd_vfs_init(&conn)) { DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n")); - conn_free_internal( conn ); + conn_free_internal( &conn ); return NULL; } @@ -4303,20 +4312,20 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) ZERO_STRUCT( fh ); finfo.fnum = -1; - finfo.conn = conn; + finfo.conn = &conn; finfo.fh = &fh; finfo.fh->fd = -1; finfo.fsp_name = CONST_DISCARD(char *,fname); if (!NT_STATUS_IS_OK(posix_fget_nt_acl( &finfo, DACL_SECURITY_INFORMATION, &psd))) { DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n")); - conn_free_internal( conn ); + conn_free_internal( &conn ); return NULL; } ret_sd = dup_sec_desc( ctx, psd ); - conn_free_internal( conn ); + conn_free_internal( &conn ); return ret_sd; } diff --git a/source/smbd/process.c b/source/smbd/process.c index c7e5c4cde3..cb465aec94 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -152,7 +152,7 @@ static NTSTATUS read_packet_remainder(int fd, char *buffer, 1 /* pad byte */) static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, - const char *lenbuf, + const char lenbuf[4], int fd, char **buffer, unsigned int timeout, size_t *p_unread, @@ -1245,8 +1245,7 @@ static const struct smb_message_struct { allocate and initialize a reply packet ********************************************************************/ -bool create_outbuf(TALLOC_CTX *mem_ctx, const char *inbuf, char **outbuf, - uint8_t num_words, uint32_t num_bytes) +void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes) { /* * Protect against integer wrap @@ -1261,33 +1260,23 @@ bool create_outbuf(TALLOC_CTX *mem_ctx, const char *inbuf, char **outbuf, smb_panic(msg); } - *outbuf = TALLOC_ARRAY(mem_ctx, char, - smb_size + num_words*2 + num_bytes); - if (*outbuf == NULL) { - return false; + if (!(req->outbuf = TALLOC_ARRAY( + req, uint8, + smb_size + num_words*2 + num_bytes))) { + smb_panic("could not allocate output buffer\n"); } - construct_reply_common(inbuf, *outbuf); - srv_set_message(*outbuf, num_words, num_bytes, false); + construct_reply_common((char *)req->inbuf, (char *)req->outbuf); + srv_set_message((char *)req->outbuf, num_words, num_bytes, false); /* * Zero out the word area, the caller has to take care of the bcc area * himself */ if (num_words != 0) { - memset(*outbuf + smb_vwv0, 0, num_words*2); + memset(req->outbuf + smb_vwv0, 0, num_words*2); } - return true; -} - -void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes) -{ - char *outbuf; - if (!create_outbuf(req, (char *)req->inbuf, &outbuf, num_words, - num_bytes)) { - smb_panic("could not allocate output buffer\n"); - } - req->outbuf = (uint8_t *)outbuf; + return; } @@ -1392,13 +1381,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in if(session_tag != UID_FIELD_INVALID) { vuser = get_valid_user_struct(session_tag); if (vuser) { - set_current_user_info( - vuser->server_info->sanitized_username, - vuser->server_info->unix_name, - pdb_get_fullname(vuser->server_info - ->sam_account), - pdb_get_domain(vuser->server_info - ->sam_account)); + set_current_user_info(&vuser->user); } } } diff --git a/source/smbd/reply.c b/source/smbd/reply.c index fbda57db51..466fef960c 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -32,6 +32,7 @@ extern int max_recv; unsigned int smb_echo_count = 0; extern uint32 global_client_caps; +extern struct current_user current_user; extern bool global_encrypted_passwords_negotiated; /**************************************************************************** @@ -326,13 +327,13 @@ size_t srvstr_get_path(TALLOC_CTX *ctx, ****************************************************************************/ bool check_fsp_open(connection_struct *conn, struct smb_request *req, - files_struct *fsp) + files_struct *fsp, struct current_user *user) { if (!(fsp) || !(conn)) { reply_nterror(req, NT_STATUS_INVALID_HANDLE); return False; } - if (((conn) != (fsp)->conn) || req->vuid != (fsp)->vuid) { + if (((conn) != (fsp)->conn) || user->vuid != (fsp)->vuid) { reply_nterror(req, NT_STATUS_INVALID_HANDLE); return False; } @@ -345,9 +346,9 @@ bool check_fsp_open(connection_struct *conn, struct smb_request *req, ****************************************************************************/ bool check_fsp(connection_struct *conn, struct smb_request *req, - files_struct *fsp) + files_struct *fsp, struct current_user *user) { - if (!check_fsp_open(conn, req, fsp)) { + if (!check_fsp_open(conn, req, fsp, user)) { return False; } if ((fsp)->is_directory) { @@ -363,45 +364,14 @@ bool check_fsp(connection_struct *conn, struct smb_request *req, } /**************************************************************************** - Check if we have a correct fsp pointing to a quota fake file. Replacement for - the CHECK_NTQUOTA_HANDLE_OK macro. -****************************************************************************/ - -bool check_fsp_ntquota_handle(connection_struct *conn, struct smb_request *req, - files_struct *fsp) -{ - if (!check_fsp_open(conn, req, fsp)) { - return false; - } - - if (fsp->is_directory) { - return false; - } - - if (fsp->fake_file_handle == NULL) { - return false; - } - - if (fsp->fake_file_handle->type != FAKE_FILE_TYPE_QUOTA) { - return false; - } - - if (fsp->fake_file_handle->private_data == NULL) { - return false; - } - - return true; -} - -/**************************************************************************** Check if we have a correct fsp. Replacement for the FSP_BELONGS_CONN macro ****************************************************************************/ bool fsp_belongs_conn(connection_struct *conn, struct smb_request *req, - files_struct *fsp) + files_struct *fsp, struct current_user *user) { if ((fsp) && (conn) && ((conn)==(fsp)->conn) - && (req->vuid == (fsp)->vuid)) { + && (current_user.vuid==(fsp)->vuid)) { return True; } @@ -2131,7 +2101,7 @@ void reply_ctemp(struct smb_request *req) return; } - status = check_name(conn, fname); + status = check_name(conn, CONST_DISCARD(char *,fname)); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBctemp); @@ -2358,13 +2328,13 @@ static NTSTATUS do_unlink(connection_struct *conn, &sbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("create_file_unixpath failed: %s\n", + DEBUG(10, ("open_file_ntcreate failed: %s\n", nt_errstr(status))); 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)) { + if (!set_delete_on_close(fsp, True, ¤t_user.ut)) { close_file(fsp, NORMAL_CLOSE); return NT_STATUS_ACCESS_DENIED; } @@ -2819,7 +2789,7 @@ void reply_readbraw(struct smb_request *req) */ if (!fsp || !conn || conn != fsp->conn || - req->vuid != fsp->vuid || + current_user.vuid != fsp->vuid || fsp->is_directory || fsp->fh->fd == -1) { /* * fsp could be NULL here so use the value from the packet. JRA. @@ -2954,7 +2924,7 @@ void reply_lockread(struct smb_request *req) fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBlockread); return; } @@ -3062,7 +3032,7 @@ void reply_read(struct smb_request *req) fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBread); return; } @@ -3318,7 +3288,7 @@ void reply_read_and_X(struct smb_request *req) return; } - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBreadX); return; } @@ -3456,7 +3426,7 @@ void reply_writebraw(struct smb_request *req) } fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { error_to_writebrawerr(req); END_PROFILE(SMBwritebraw); return; @@ -3662,7 +3632,7 @@ void reply_writeunlock(struct smb_request *req) fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBwriteunlock); return; } @@ -3769,7 +3739,7 @@ void reply_write(struct smb_request *req) fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBwrite); return; } @@ -4001,7 +3971,7 @@ void reply_write_and_X(struct smb_request *req) startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3); write_through = BITSETW(req->inbuf+smb_vwv7,0); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBwriteX); return; } @@ -4120,7 +4090,7 @@ void reply_lseek(struct smb_request *req) fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { return; } @@ -4206,7 +4176,7 @@ void reply_flush(struct smb_request *req) fnum = SVAL(req->inbuf,smb_vwv0); fsp = file_fsp(fnum); - if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp)) { + if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp, ¤t_user)) { return; } @@ -4279,7 +4249,7 @@ void reply_close(struct smb_request *req) * We can only use CHECK_FSP if we know it's not a directory. */ - if(!fsp || (fsp->conn != conn) || (fsp->vuid != req->vuid)) { + if(!fsp || (fsp->conn != conn) || (fsp->vuid != current_user.vuid)) { reply_doserror(req, ERRDOS, ERRbadfid); END_PROFILE(SMBclose); return; @@ -4353,7 +4323,7 @@ void reply_writeclose(struct smb_request *req) fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBwriteclose); return; } @@ -4440,7 +4410,7 @@ void reply_lock(struct smb_request *req) fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBlock); return; } @@ -4499,7 +4469,7 @@ void reply_unlock(struct smb_request *req) fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBunlock); return; } @@ -4645,7 +4615,7 @@ void reply_printopen(struct smb_request *req) } /* Open for exclusive use, write only. */ - status = print_fsp_open(conn, NULL, req->vuid, &fsp); + status = print_fsp_open(conn, NULL, &fsp); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -4683,7 +4653,7 @@ void reply_printclose(struct smb_request *req) fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBsplclose); return; } @@ -4825,7 +4795,7 @@ void reply_printwrite(struct smb_request *req) fsp = file_fsp(SVAL(req->inbuf,smb_vwv0)); - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBsplwr); return; } @@ -5586,10 +5556,10 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, 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, newname); - rename_open_files(conn, lck, newname); + notify_rename(conn, fsp->is_directory, fsp->fsp_name, newname); + /* * A rename acts as a new file create w.r.t. allowing an initial delete * on close, probably because in Windows there is a new handle to the @@ -6659,7 +6629,7 @@ void reply_lockingX(struct smb_request *req) lock_timeout = IVAL(req->inbuf,smb_vwv4); large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False; - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { END_PROFILE(SMBlockingX); return; } diff --git a/source/smbd/sec_ctx.c b/source/smbd/sec_ctx.c index a618f06e6b..0f307f6a64 100644 --- a/source/smbd/sec_ctx.c +++ b/source/smbd/sec_ctx.c @@ -145,7 +145,7 @@ static void gain_root(void) Get the list of current groups. ****************************************************************************/ -static int get_current_groups(gid_t gid, size_t *p_ngroups, gid_t **p_groups) +static int get_current_groups(gid_t gid, int *p_ngroups, gid_t **p_groups) { int i; gid_t grp; diff --git a/source/smbd/server.c b/source/smbd/server.c index 53116f3d98..176cd5f973 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -90,12 +90,9 @@ struct messaging_context *smbd_messaging_context(void) { static struct messaging_context *ctx; - if (ctx == NULL) { - ctx = messaging_init(NULL, server_id_self(), - smbd_event_context()); - } - if (ctx == NULL) { - DEBUG(0, ("Could not init smbd messaging context.\n")); + if (!ctx && !(ctx = messaging_init(NULL, server_id_self(), + smbd_event_context()))) { + smb_panic("Could not init smbd messaging context"); } return ctx; } @@ -296,7 +293,6 @@ static void remove_child_pid(pid_t pid, bool unclean_shutdown) /* a child terminated uncleanly so tickle all processes to see if they can grab any of the pending locks */ - DEBUG(3,(__location__ " Unclean shutdown of pid %u\n", pid)); messaging_send_buf(smbd_messaging_context(), procid_self(), MSG_SMB_BRL_VALIDATE, NULL, 0); message_send_all(smbd_messaging_context(), @@ -575,12 +571,6 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_ MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete); brl_register_msgs(smbd_messaging_context()); -#ifdef CLUSTER_SUPPORT - if (lp_clustering()) { - ctdbd_register_reconfigure(messaging_ctdbd_connection()); - } -#endif - #ifdef DEVELOPER messaging_register(smbd_messaging_context(), NULL, MSG_SMB_INJECT_FAULT, msg_inject_fault); @@ -894,7 +884,6 @@ static void exit_server_common(enum server_exit_reason how, const char *const reason) { static int firsttime=1; - bool had_open_conn; if (!firsttime) exit(0); @@ -906,7 +895,7 @@ static void exit_server_common(enum server_exit_reason how, (negprot_global_auth_context->free)(&negprot_global_auth_context); } - had_open_conn = conn_close_all(); + conn_close_all(); invalidate_all_vuids(); @@ -956,15 +945,7 @@ static void exit_server_common(enum server_exit_reason how, (reason ? reason : "normal exit"))); } - /* if we had any open SMB connections when we exited then we - need to tell the parent smbd so that it can trigger a retry - of any locks we may have been holding or open files we were - blocking */ - if (had_open_conn) { - exit(1); - } else { - exit(0); - } + exit(0); } void exit_server(const char *const explanation) @@ -998,9 +979,7 @@ static void release_ip(const char *ip, void *priv) away */ DEBUG(0,("Got release IP message for our IP %s - exiting immediately\n", ip)); - /* note we must exit with non-zero status so the unclean handler gets - called in the parent, so that the brl database is tickled */ - _exit(1); + _exit(0); } } @@ -1116,6 +1095,8 @@ extern void build_options(bool screen); TimeInit(); + db_tdb2_setup_messaging(NULL, false); + #ifdef HAVE_SET_AUTH_PARAMETERS set_auth_parameters(argc,argv); #endif @@ -1247,6 +1228,11 @@ extern void build_options(bool screen); if (smbd_messaging_context() == NULL) exit(1); + /* + * Do this before reload_services. + */ + db_tdb2_setup_messaging(smbd_messaging_context(), true); + if (!reload_services(False)) return(-1); diff --git a/source/smbd/service.c b/source/smbd/service.c index 0b851f1e48..491a67a2eb 100644 --- a/source/smbd/service.c +++ b/source/smbd/service.c @@ -523,6 +523,31 @@ static NTSTATUS share_sanity_checks(int snum, fstring dev) return NT_STATUS_OK; } +static NTSTATUS find_forced_user(connection_struct *conn, bool vuser_is_guest, fstring username) +{ + int snum = conn->params->service; + char *fuser, *found_username; + NTSTATUS result; + + if (!(fuser = talloc_string_sub(conn->mem_ctx, lp_force_user(snum), "%S", + lp_servicename(snum)))) { + return NT_STATUS_NO_MEMORY; + } + + result = create_token_from_username(conn->mem_ctx, fuser, vuser_is_guest, + &conn->uid, &conn->gid, &found_username, + &conn->nt_user_token); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + fstrcpy(username, found_username); + + TALLOC_FREE(fuser); + TALLOC_FREE(found_username); + return NT_STATUS_OK; +} + /* * Go through lookup_name etc to find the force'd group. * @@ -536,14 +561,23 @@ static NTSTATUS find_forced_group(bool force_user, gid_t *pgid) { NTSTATUS result = NT_STATUS_NO_SUCH_GROUP; - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *mem_ctx; DOM_SID group_sid; enum lsa_SidType type; char *groupname; bool user_must_be_member = False; gid_t gid; - groupname = talloc_strdup(talloc_tos(), lp_force_group(snum)); + ZERO_STRUCTP(pgroup_sid); + *pgid = (gid_t)-1; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return NT_STATUS_NO_MEMORY; + } + + groupname = talloc_strdup(mem_ctx, lp_force_group(snum)); if (groupname == NULL) { DEBUG(1, ("talloc_strdup failed\n")); result = NT_STATUS_NO_MEMORY; @@ -555,15 +589,10 @@ static NTSTATUS find_forced_group(bool force_user, groupname += 1; } - groupname = talloc_string_sub(talloc_tos(), groupname, + groupname = talloc_string_sub(mem_ctx, groupname, "%S", lp_servicename(snum)); - if (groupname == NULL) { - DEBUG(1, ("talloc_string_sub failed\n")); - result = NT_STATUS_NO_MEMORY; - goto done; - } - if (!lookup_name_smbconf(talloc_tos(), groupname, + if (!lookup_name_smbconf(mem_ctx, groupname, LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP, NULL, NULL, &group_sid, &type)) { DEBUG(10, ("lookup_name_smbconf(%s) failed\n", @@ -612,88 +641,11 @@ static NTSTATUS find_forced_group(bool force_user, result = NT_STATUS_OK; done: - TALLOC_FREE(frame); + TALLOC_FREE(mem_ctx); return result; } /**************************************************************************** - Create an auth_serversupplied_info structure for a connection_struct -****************************************************************************/ - -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) -{ - if (lp_guest_only(snum)) { - return make_server_info_guest(mem_ctx, presult); - } - - if (vuid_serverinfo != NULL) { - - struct auth_serversupplied_info *result; - - /* - * This is the normal security != share case where we have a - * valid vuid from the session setup. */ - - if (vuid_serverinfo->guest) { - if (!lp_guest_ok(snum)) { - DEBUG(2, ("guest user (from session setup) " - "not permitted to access this share " - "(%s)\n", lp_servicename(snum))); - return NT_STATUS_ACCESS_DENIED; - } - } else { - if (!user_ok_token(vuid_serverinfo->unix_name, - pdb_get_domain(vuid_serverinfo->sam_account), - vuid_serverinfo->ptok, snum)) { - DEBUG(2, ("user '%s' (from session setup) not " - "permitted to access this share " - "(%s)\n", - vuid_serverinfo->unix_name, - lp_servicename(snum))); - return NT_STATUS_ACCESS_DENIED; - } - } - - result = copy_serverinfo(mem_ctx, vuid_serverinfo); - if (result == NULL) { - return NT_STATUS_NO_MEMORY; - } - - *presult = result; - return NT_STATUS_OK; - } - - if (lp_security() == SEC_SHARE) { - - fstring user; - bool guest; - - /* add the sharename as a possible user name if we - are in share mode security */ - - add_session_user(lp_servicename(snum)); - - /* shall we let them in? */ - - if (!authorise_login(snum,user,password,&guest)) { - DEBUG( 2, ( "Invalid username/password for [%s]\n", - lp_servicename(snum)) ); - return NT_STATUS_WRONG_PASSWORD; - } - - return make_serverinfo_from_username(mem_ctx, user, guest, - presult); - } - - DEBUG(0, ("invalid VUID (vuser) but not in security=share\n")); - return NT_STATUS_ACCESS_DENIED; -} - - -/**************************************************************************** Make a connection, given the snum to connect to, and the vuser of the connecting user if appropriate. ****************************************************************************/ @@ -701,49 +653,132 @@ static NTSTATUS create_connection_server_info(TALLOC_CTX *mem_ctx, int snum, static connection_struct *make_connection_snum(int snum, user_struct *vuser, DATA_BLOB password, const char *pdev, - NTSTATUS *pstatus) + NTSTATUS *status) { + struct passwd *pass = NULL; + bool guest = False; connection_struct *conn; SMB_STRUCT_STAT st; + fstring user; fstring dev; int ret; char addr[INET6_ADDRSTRLEN]; bool on_err_call_dis_hook = false; - NTSTATUS status; + *user = 0; fstrcpy(dev, pdev); SET_STAT_INVALID(st); - if (NT_STATUS_IS_ERR(*pstatus = share_sanity_checks(snum, dev))) { + if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) { return NULL; } conn = conn_new(); if (!conn) { DEBUG(0,("Couldn't find free connection.\n")); - *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; + *status = NT_STATUS_INSUFFICIENT_RESOURCES; return NULL; } conn->params->service = snum; - - status = create_connection_server_info( - conn, snum, vuser ? vuser->server_info : NULL, password, - &conn->server_info); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("create_connection_server_info failed: %s\n", - nt_errstr(status))); - *pstatus = status; + conn->nt_user_token = NULL; + + if (lp_guest_only(snum)) { + const char *guestname = lp_guestaccount(); + NTSTATUS status2; + char *found_username = NULL; + + guest = True; + pass = getpwnam_alloc(NULL, guestname); + if (!pass) { + DEBUG(0,("make_connection_snum: Invalid guest " + "account %s??\n",guestname)); + conn_free(conn); + *status = NT_STATUS_NO_SUCH_USER; + return NULL; + } + status2 = create_token_from_username(conn->mem_ctx, pass->pw_name, True, + &conn->uid, &conn->gid, + &found_username, + &conn->nt_user_token); + if (!NT_STATUS_IS_OK(status2)) { + TALLOC_FREE(pass); + conn_free(conn); + *status = status2; + return NULL; + } + fstrcpy(user, found_username); + string_set(&conn->user,user); + conn->force_user = True; + TALLOC_FREE(found_username); + TALLOC_FREE(pass); + DEBUG(3,("Guest only user %s\n",user)); + } else if (vuser) { + if (vuser->guest) { + if (!lp_guest_ok(snum)) { + DEBUG(2, ("guest user (from session setup) " + "not permitted to access this share " + "(%s)\n", lp_servicename(snum))); + conn_free(conn); + *status = NT_STATUS_ACCESS_DENIED; + return NULL; + } + } else { + if (!user_ok_token(vuser->user.unix_name, + vuser->nt_user_token, snum)) { + DEBUG(2, ("user '%s' (from session setup) not " + "permitted to access this share " + "(%s)\n", vuser->user.unix_name, + lp_servicename(snum))); + conn_free(conn); + *status = NT_STATUS_ACCESS_DENIED; + return NULL; + } + } + conn->vuid = vuser->vuid; + conn->uid = vuser->uid; + conn->gid = vuser->gid; + string_set(&conn->user,vuser->user.unix_name); + fstrcpy(user,vuser->user.unix_name); + guest = vuser->guest; + } else if (lp_security() == SEC_SHARE) { + NTSTATUS status2; + char *found_username = NULL; + + /* add it as a possible user name if we + are in share mode security */ + add_session_user(lp_servicename(snum)); + /* shall we let them in? */ + if (!authorise_login(snum,user,password,&guest)) { + DEBUG( 2, ( "Invalid username/password for [%s]\n", + lp_servicename(snum)) ); + conn_free(conn); + *status = NT_STATUS_WRONG_PASSWORD; + return NULL; + } + pass = Get_Pwnam_alloc(talloc_tos(), user); + status2 = create_token_from_username(conn->mem_ctx, pass->pw_name, True, + &conn->uid, &conn->gid, + &found_username, + &conn->nt_user_token); + TALLOC_FREE(pass); + if (!NT_STATUS_IS_OK(status2)) { + conn_free(conn); + *status = status2; + return NULL; + } + fstrcpy(user, found_username); + string_set(&conn->user,user); + TALLOC_FREE(found_username); + conn->force_user = True; + } else { + DEBUG(0, ("invalid VUID (vuser) but not in security=share\n")); conn_free(conn); + *status = NT_STATUS_ACCESS_DENIED; return NULL; } - if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) { - conn->force_user = true; - } - - add_session_user(conn->server_info->unix_name); + add_session_user(user); safe_strcpy(conn->client_address, client_addr(get_client_fd(),addr,sizeof(addr)), @@ -775,84 +810,126 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->veto_oplock_list = NULL; conn->aio_write_behind_list = NULL; string_set(&conn->dirpath,""); + string_set(&conn->user,user); conn->read_only = lp_readonly(SNUM(conn)); conn->admin_user = False; + /* + * If force user is true, then store the given userid and the gid of + * the user we're forcing. + * For auxiliary groups see below. + */ + if (*lp_force_user(snum)) { + NTSTATUS status2; - /* - * Replace conn->server_info with a completely faked up one - * from the username we are forced into :-) - */ - - char *fuser; - struct auth_serversupplied_info *forced_serverinfo; - - fuser = talloc_string_sub(conn, lp_force_user(snum), "%S", - lp_servicename(snum)); - if (fuser == NULL) { - conn_free(conn); - *pstatus = NT_STATUS_NO_MEMORY; - return NULL; - } - - status = make_serverinfo_from_username( - conn, fuser, conn->server_info->guest, - &forced_serverinfo); - if (!NT_STATUS_IS_OK(status)) { + status2 = find_forced_user(conn, + (vuser != NULL) && vuser->guest, + user); + if (!NT_STATUS_IS_OK(status2)) { conn_free(conn); - *pstatus = status; + *status = status2; return NULL; } - - TALLOC_FREE(conn->server_info); - conn->server_info = forced_serverinfo; - + string_set(&conn->user,user); conn->force_user = True; - DEBUG(3,("Forced user %s\n", fuser)); + DEBUG(3,("Forced user %s\n",user)); } /* * If force group is true, then override * any groupid stored for the connecting user. */ - + if (*lp_force_group(snum)) { + NTSTATUS status2; + DOM_SID group_sid; - status = find_forced_group( - conn->force_user, snum, conn->server_info->unix_name, - &conn->server_info->ptok->user_sids[1], - &conn->server_info->utok.gid); - - if (!NT_STATUS_IS_OK(status)) { + status2 = find_forced_group(conn->force_user, + snum, user, + &group_sid, &conn->gid); + if (!NT_STATUS_IS_OK(status2)) { conn_free(conn); - *pstatus = status; + *status = status2; return NULL; } + + if ((conn->nt_user_token == NULL) && (vuser != NULL)) { + + /* Not force user and not security=share, but force + * group. vuser has a token to copy */ + + conn->nt_user_token = dup_nt_token( + NULL, vuser->nt_user_token); + if (conn->nt_user_token == NULL) { + DEBUG(0, ("dup_nt_token failed\n")); + conn_free(conn); + *status = NT_STATUS_NO_MEMORY; + return NULL; + } + } + + /* If conn->nt_user_token is still NULL, we have + * security=share. This means ignore the SID, as we had no + * vuser to copy from */ + + if (conn->nt_user_token != NULL) { + /* Overwrite the primary group sid */ + sid_copy(&conn->nt_user_token->user_sids[1], + &group_sid); + + } + conn->force_group = True; } - conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID; + if (conn->nt_user_token != NULL) { + size_t i; + + /* We have a share-specific token from force [user|group]. + * This means we have to create the list of unix groups from + * the list of sids. */ + + conn->ngroups = 0; + conn->groups = NULL; + + for (i=0; i<conn->nt_user_token->num_sids; i++) { + gid_t gid; + DOM_SID *sid = &conn->nt_user_token->user_sids[i]; + + if (!sid_to_gid(sid, &gid)) { + DEBUG(10, ("Could not convert SID %s to gid, " + "ignoring it\n", + sid_string_dbg(sid))); + continue; + } + if (!add_gid_to_array_unique(conn->mem_ctx, gid, &conn->groups, + &conn->ngroups)) { + DEBUG(0, ("add_gid_to_array_unique failed\n")); + conn_free(conn); + *status = NT_STATUS_NO_MEMORY; + return NULL; + } + } + } { char *s = talloc_sub_advanced(talloc_tos(), - lp_servicename(SNUM(conn)), - conn->server_info->unix_name, - conn->connectpath, - conn->server_info->utok.gid, - conn->server_info->sanitized_username, - pdb_get_domain(conn->server_info->sam_account), + lp_servicename(SNUM(conn)), conn->user, + conn->connectpath, conn->gid, + get_current_username(), + current_user_info.domain, lp_pathname(snum)); if (!s) { conn_free(conn); - *pstatus = NT_STATUS_NO_MEMORY; + *status = NT_STATUS_NO_MEMORY; return NULL; } if (!set_conn_connectpath(conn,s)) { TALLOC_FREE(s); conn_free(conn); - *pstatus = NT_STATUS_NO_MEMORY; + *status = NT_STATUS_NO_MEMORY; return NULL; } DEBUG(3,("Connect path is '%s' for service [%s]\n",s, @@ -869,13 +946,32 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, { bool can_write = False; + NT_USER_TOKEN *token = conn->nt_user_token ? + conn->nt_user_token : + (vuser ? vuser->nt_user_token : NULL); + + /* + * I don't believe this can happen. But the + * logic above is convoluted enough to confuse + * automated checkers, so be sure. JRA. + */ + + if (token == NULL) { + DEBUG(0,("make_connection: connection to %s " + "denied due to missing " + "NT token.\n", + lp_servicename(snum))); + conn_free(conn); + *status = NT_STATUS_ACCESS_DENIED; + return NULL; + } - can_write = share_access_check(conn->server_info->ptok, - lp_servicename(snum), - FILE_WRITE_DATA); + can_write = share_access_check(token, + lp_servicename(snum), + FILE_WRITE_DATA); if (!can_write) { - if (!share_access_check(conn->server_info->ptok, + if (!share_access_check(token, lp_servicename(snum), FILE_READ_DATA)) { /* No access, read or write. */ @@ -884,7 +980,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, "descriptor.\n", lp_servicename(snum))); conn_free(conn); - *pstatus = NT_STATUS_ACCESS_DENIED; + *status = NT_STATUS_ACCESS_DENIED; return NULL; } else { conn->read_only = True; @@ -897,7 +993,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(snum))); conn_free(conn); - *pstatus = NT_STATUS_BAD_NETWORK_NAME; + *status = NT_STATUS_BAD_NETWORK_NAME; return NULL; } @@ -915,13 +1011,13 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, lp_servicename(snum), conn->connectpath)); conn_free(conn); - *pstatus = NT_STATUS_BAD_NETWORK_NAME; + *status = NT_STATUS_BAD_NETWORK_NAME; return NULL; } } if ((!conn->printer) && (!conn->ipc)) { - conn->notify_ctx = notify_init(conn, server_id_self(), + conn->notify_ctx = notify_init(conn->mem_ctx, server_id_self(), smbd_messaging_context(), smbd_event_context(), conn); @@ -939,7 +1035,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, DEBUG(1, ("Max connections (%d) exceeded for %s\n", lp_max_connections(snum), lp_servicename(snum))); conn_free(conn); - *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; + *status = NT_STATUS_INSUFFICIENT_RESOURCES; return NULL; } @@ -949,7 +1045,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, if (!claim_connection(conn, lp_servicename(snum), 0)) { DEBUG(1, ("Could not store connections entry\n")); conn_free(conn); - *pstatus = NT_STATUS_INTERNAL_DB_ERROR; + *status = NT_STATUS_INTERNAL_DB_ERROR; return NULL; } @@ -958,12 +1054,10 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, /* execute any "root preexec = " line */ if (*lp_rootpreexec(snum)) { char *cmd = talloc_sub_advanced(talloc_tos(), - lp_servicename(SNUM(conn)), - conn->server_info->unix_name, - conn->connectpath, - conn->server_info->utok.gid, - conn->server_info->sanitized_username, - pdb_get_domain(conn->server_info->sam_account), + lp_servicename(SNUM(conn)), conn->user, + conn->connectpath, conn->gid, + get_current_username(), + current_user_info.domain, lp_rootpreexec(snum)); DEBUG(5,("cmd=%s\n",cmd)); ret = smbrun(cmd,NULL); @@ -973,7 +1067,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, "connection\n", ret)); yield_connection(conn, lp_servicename(snum)); conn_free(conn); - *pstatus = NT_STATUS_ACCESS_DENIED; + *status = NT_STATUS_ACCESS_DENIED; return NULL; } } @@ -984,7 +1078,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, DEBUG(0,("Can't become connected user!\n")); yield_connection(conn, lp_servicename(snum)); conn_free(conn); - *pstatus = NT_STATUS_LOGON_FAILURE; + *status = NT_STATUS_LOGON_FAILURE; return NULL; } @@ -997,19 +1091,17 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, /* execute any "preexec = " line */ if (*lp_preexec(snum)) { char *cmd = talloc_sub_advanced(talloc_tos(), - lp_servicename(SNUM(conn)), - conn->server_info->unix_name, - conn->connectpath, - conn->server_info->utok.gid, - conn->server_info->sanitized_username, - pdb_get_domain(conn->server_info->sam_account), + lp_servicename(SNUM(conn)), conn->user, + conn->connectpath, conn->gid, + get_current_username(), + current_user_info.domain, lp_preexec(snum)); ret = smbrun(cmd,NULL); TALLOC_FREE(cmd); if (ret != 0 && lp_preexec_close(snum)) { DEBUG(1,("preexec gave %d - failing connection\n", ret)); - *pstatus = NT_STATUS_ACCESS_DENIED; + *status = NT_STATUS_ACCESS_DENIED; goto err_root_exit; } } @@ -1033,10 +1125,9 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, to allow any filesystems needing user credentials to initialize themselves. */ - if (SMB_VFS_CONNECT(conn, lp_servicename(snum), - conn->server_info->unix_name) < 0) { + if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) { DEBUG(0,("make_connection: VFS make connection failed!\n")); - *pstatus = NT_STATUS_UNSUCCESSFUL; + *status = NT_STATUS_UNSUCCESSFUL; goto err_root_exit; } @@ -1060,7 +1151,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->connectpath, lp_servicename(snum), strerror(errno) )); } - *pstatus = NT_STATUS_BAD_NETWORK_NAME; + *status = NT_STATUS_BAD_NETWORK_NAME; goto err_root_exit; } @@ -1101,8 +1192,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->client_address ); 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 ); + dbgtext( "initially as user %s ", user ); dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() ); dbgtext( "(pid %d)\n", (int)sys_getpid() ); } @@ -1143,7 +1233,7 @@ connection_struct *make_connection_with_chdir(const char *service_in, */ if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) { - DEBUG(0,("make_connection_with_chdir: Can't change " + DEBUG(0,("move_driver_to_download_area: Can't change " "directory to %s for [print$] (%s)\n", conn->connectpath,strerror(errno))); yield_connection(conn, lp_servicename(SNUM(conn))); @@ -1322,12 +1412,10 @@ void close_cnum(connection_struct *conn, uint16 vuid) if (*lp_postexec(SNUM(conn)) && change_to_user(conn, vuid)) { char *cmd = talloc_sub_advanced(talloc_tos(), - lp_servicename(SNUM(conn)), - conn->server_info->unix_name, - conn->connectpath, - conn->server_info->utok.gid, - conn->server_info->sanitized_username, - pdb_get_domain(conn->server_info->sam_account), + lp_servicename(SNUM(conn)), conn->user, + conn->connectpath, conn->gid, + get_current_username(), + current_user_info.domain, lp_postexec(SNUM(conn))); smbrun(cmd,NULL); TALLOC_FREE(cmd); @@ -1338,12 +1426,10 @@ void close_cnum(connection_struct *conn, uint16 vuid) /* execute any "root postexec = " line */ if (*lp_rootpostexec(SNUM(conn))) { char *cmd = talloc_sub_advanced(talloc_tos(), - lp_servicename(SNUM(conn)), - conn->server_info->unix_name, - conn->connectpath, - conn->server_info->utok.gid, - conn->server_info->sanitized_username, - pdb_get_domain(conn->server_info->sam_account), + lp_servicename(SNUM(conn)), conn->user, + conn->connectpath, conn->gid, + get_current_username(), + current_user_info.domain, lp_rootpostexec(SNUM(conn))); smbrun(cmd,NULL); TALLOC_FREE(cmd); diff --git a/source/smbd/session.c b/source/smbd/session.c index 3b431a19be..000b2f5d9c 100644 --- a/source/smbd/session.c +++ b/source/smbd/session.c @@ -75,7 +75,7 @@ bool session_claim(user_struct *vuser) /* don't register sessions for the guest user - its just too expensive to go through pam session code for browsing etc */ - if (vuser->server_info->guest) { + if (vuser->guest) { return True; } @@ -164,12 +164,12 @@ bool session_claim(user_struct *vuser) hostname = client_addr(get_client_fd(),addr,sizeof(addr)); } - fstrcpy(sessionid.username, vuser->server_info->unix_name); + fstrcpy(sessionid.username, vuser->user.unix_name); fstrcpy(sessionid.hostname, hostname); sessionid.id_num = i; /* Only valid for utmp sessions */ sessionid.pid = pid; - sessionid.uid = vuser->server_info->utok.uid; - sessionid.gid = vuser->server_info->utok.gid; + sessionid.uid = vuser->uid; + sessionid.gid = vuser->gid; fstrcpy(sessionid.remote_machine, get_remote_machine_name()); fstrcpy(sessionid.ip_addr_str, client_addr(get_client_fd(),addr,sizeof(addr))); diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c index 9c9d0a97bc..98594b0769 100644 --- a/source/smbd/sesssetup.c +++ b/source/smbd/sesssetup.c @@ -45,7 +45,7 @@ static NTSTATUS do_map_to_guest(NTSTATUS status, (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) { DEBUG(3,("No such user %s [%s] - using guest account\n", user, domain)); - status = make_server_info_guest(NULL, server_info); + status = make_server_info_guest(server_info); } } @@ -53,7 +53,7 @@ static NTSTATUS do_map_to_guest(NTSTATUS status, if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) { DEBUG(3,("Registered username %s for guest access\n", user)); - status = make_server_info_guest(NULL, server_info); + status = make_server_info_guest(server_info); } } @@ -442,7 +442,7 @@ static void reply_spnego_kerberos(struct smb_request *req, if (pw) { /* if a real user check pam account restrictions */ /* only really perfomed if "obey pam restriction" is true */ - /* do this before an eventual mapping to guest occurs */ + /* do this before an eventual mappign to guest occurs */ ret = smb_pam_accountcheck(pw->pw_name); if ( !NT_STATUS_IS_OK(ret)) { DEBUG(1,("PAM account restriction " @@ -488,7 +488,7 @@ static void reply_spnego_kerberos(struct smb_request *req, reload_services(True); if ( map_domainuser_to_guest ) { - make_server_info_guest(NULL, &server_info); + make_server_info_guest(&server_info); } else if (logon_info) { /* pass the unmapped username here since map_username() will be called again from inside make_server_info_info3() */ @@ -530,7 +530,9 @@ static void reply_spnego_kerberos(struct smb_request *req, } } - server_info->nss_token |= username_was_mapped; + if (username_was_mapped) { + server_info->was_mapped = username_was_mapped; + } /* we need to build the token for the user. make_server_info_guest() already does this */ @@ -558,13 +560,9 @@ static void reply_spnego_kerberos(struct smb_request *req, if (!is_partial_auth_vuid(sess_vuid)) { sess_vuid = register_initial_vuid(); } - - data_blob_free(&server_info->user_session_key); - server_info->user_session_key = session_key; - session_key = data_blob_null; - sess_vuid = register_existing_vuid(sess_vuid, server_info, + session_key, nullblob, client); @@ -575,6 +573,7 @@ static void reply_spnego_kerberos(struct smb_request *req, if (sess_vuid == UID_FIELD_INVALID ) { ret = NT_STATUS_LOGON_FAILURE; + data_blob_free(&session_key); } else { /* current_user_info is changed on new vuid */ reload_services( True ); @@ -644,24 +643,23 @@ static void reply_spnego_ntlmssp(struct smb_request *req, if (NT_STATUS_IS_OK(nt_status)) { DATA_BLOB nullblob = data_blob_null; + DATA_BLOB session_key = + data_blob( + (*auth_ntlmssp_state)->ntlmssp_state->session_key.data, + (*auth_ntlmssp_state)->ntlmssp_state->session_key.length); if (!is_partial_auth_vuid(vuid)) { + data_blob_free(&session_key); nt_status = NT_STATUS_LOGON_FAILURE; goto out; } - - data_blob_free(&server_info->user_session_key); - server_info->user_session_key = - data_blob_talloc( - server_info, - (*auth_ntlmssp_state)->ntlmssp_state->session_key.data, - (*auth_ntlmssp_state)->ntlmssp_state->session_key.length); - /* register_existing_vuid keeps the server info */ if (register_existing_vuid(vuid, - server_info, nullblob, + server_info, + session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user) != vuid) { + data_blob_free(&session_key); nt_status = NT_STATUS_LOGON_FAILURE; goto out; } @@ -1352,9 +1350,6 @@ static int shutdown_other_smbds(struct db_record *rec, return 0; } - DEBUG(0,("shutdown_other_smbds: shutting down pid %d " - "(IP %s)\n", procid_to_pid(&crec->pid), ip)); - messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN, &data_blob_null); return 0; @@ -1403,6 +1398,8 @@ void reply_sesssetup_and_X(struct smb_request *req) bool doencrypt = global_encrypted_passwords_negotiated; + DATA_BLOB session_key; + START_PROFILE(SMBsesssetupX); ZERO_STRUCT(lm_resp); @@ -1753,6 +1750,13 @@ void reply_sesssetup_and_X(struct smb_request *req) } } + if (server_info->user_session_key.data) { + session_key = data_blob(server_info->user_session_key.data, + server_info->user_session_key.length); + } else { + session_key = data_blob_null; + } + data_blob_clear_free(&plaintext_password); /* it's ok - setup a reply */ @@ -1771,6 +1775,7 @@ void reply_sesssetup_and_X(struct smb_request *req) if (lp_security() == SEC_SHARE) { sess_vuid = UID_FIELD_INVALID; + data_blob_free(&session_key); TALLOC_FREE(server_info); } else { /* Ignore the initial vuid. */ @@ -1778,6 +1783,7 @@ void reply_sesssetup_and_X(struct smb_request *req) if (sess_vuid == UID_FIELD_INVALID) { data_blob_free(&nt_resp); data_blob_free(&lm_resp); + data_blob_free(&session_key); reply_nterror(req, nt_status_squash( NT_STATUS_LOGON_FAILURE)); END_PROFILE(SMBsesssetupX); @@ -1786,11 +1792,13 @@ void reply_sesssetup_and_X(struct smb_request *req) /* register_existing_vuid keeps the server info */ sess_vuid = register_existing_vuid(sess_vuid, server_info, + session_key, nt_resp.data ? nt_resp : lm_resp, sub_user); if (sess_vuid == UID_FIELD_INVALID) { data_blob_free(&nt_resp); data_blob_free(&lm_resp); + data_blob_free(&session_key); reply_nterror(req, nt_status_squash( NT_STATUS_LOGON_FAILURE)); END_PROFILE(SMBsesssetupX); diff --git a/source/smbd/share_access.c b/source/smbd/share_access.c index f5f79c86e5..512126254a 100644 --- a/source/smbd/share_access.c +++ b/source/smbd/share_access.c @@ -27,6 +27,8 @@ * + and & may be combined */ +extern userdom_struct current_user_info; + static bool do_group_checks(const char **name, const char **pattern) { if ((*name)[0] == '@') { @@ -64,7 +66,6 @@ static bool do_group_checks(const char **name, const char **pattern) static bool token_contains_name(TALLOC_CTX *mem_ctx, const char *username, - const char *domain, const char *sharename, const struct nt_user_token *token, const char *name) @@ -74,7 +75,8 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx, enum lsa_SidType type; if (username != NULL) { - name = talloc_sub_basic(mem_ctx, username, domain, name); + name = talloc_sub_basic(mem_ctx, username, + current_user_info.domain, name); } if (sharename != NULL) { name = talloc_string_sub(mem_ctx, name, "%S", sharename); @@ -150,7 +152,6 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx, */ bool token_contains_name_in_list(const char *username, - const char *domain, const char *sharename, const struct nt_user_token *token, const char **list) @@ -166,8 +167,7 @@ bool token_contains_name_in_list(const char *username, } while (*list != NULL) { - if (token_contains_name(mem_ctx, username, domain, sharename, - token, *list)) { + if (token_contains_name(mem_ctx, username, sharename,token, *list)) { TALLOC_FREE(mem_ctx); return True; } @@ -191,12 +191,10 @@ bool token_contains_name_in_list(const char *username, * The other use is the netgroup check when using @group or &group. */ -bool user_ok_token(const char *username, const char *domain, - struct nt_user_token *token, int snum) +bool user_ok_token(const char *username, struct nt_user_token *token, int snum) { if (lp_invalid_users(snum) != NULL) { - if (token_contains_name_in_list(username, domain, - lp_servicename(snum), + if (token_contains_name_in_list(username, lp_servicename(snum), token, lp_invalid_users(snum))) { DEBUG(10, ("User %s in 'invalid users'\n", username)); @@ -205,7 +203,7 @@ bool user_ok_token(const char *username, const char *domain, } if (lp_valid_users(snum) != NULL) { - if (!token_contains_name_in_list(username, domain, + if (!token_contains_name_in_list(username, lp_servicename(snum), token, lp_valid_users(snum))) { DEBUG(10, ("User %s not in 'valid users'\n", @@ -222,8 +220,7 @@ bool user_ok_token(const char *username, const char *domain, DEBUG(0, ("'only user = yes' and no 'username ='\n")); return False; } - if (!token_contains_name_in_list(NULL, domain, - lp_servicename(snum), + if (!token_contains_name_in_list(NULL, lp_servicename(snum), token, list)) { DEBUG(10, ("%s != 'username'\n", username)); return False; @@ -251,13 +248,12 @@ bool user_ok_token(const char *username, const char *domain, */ bool is_share_read_only_for_token(const char *username, - const char *domain, struct nt_user_token *token, int snum) { bool result = lp_readonly(snum); if (lp_readlist(snum) != NULL) { - if (token_contains_name_in_list(username, domain, + if (token_contains_name_in_list(username, lp_servicename(snum), token, lp_readlist(snum))) { result = True; @@ -265,7 +261,7 @@ bool is_share_read_only_for_token(const char *username, } if (lp_writelist(snum) != NULL) { - if (token_contains_name_in_list(username, domain, + if (token_contains_name_in_list(username, lp_servicename(snum), token, lp_writelist(snum))) { result = False; diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 1e2095a3ea..13105dce0f 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -28,6 +28,7 @@ extern int max_send; extern enum protocol_types Protocol; extern uint32 global_client_caps; +extern struct current_user current_user; #define get_file_size(sbuf) ((sbuf).st_size) #define DIR_ENTRY_SAFETY_MARGIN 4096 @@ -177,7 +178,7 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, char *p; char **names, **tmp; size_t num_names; - ssize_t sizeret = -1; + ssize_t sizeret; if (!lp_ea_support(SNUM(conn))) { *pnames = NULL; @@ -503,7 +504,7 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname, s static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size) { struct ea_list *ea_list_head = NULL; - size_t converted_size, offset = 0; + size_t offset = 0; while (offset + 2 < data_size) { struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list); @@ -521,11 +522,7 @@ static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, siz if (pdata[offset + namelen] != '\0') { return NULL; } - if (!pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset], - &converted_size)) { - DEBUG(0,("read_ea_name_list: pull_ascii_talloc " - "failed: %s", strerror(errno))); - } + pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset]); if (!eal->ea.name) { return NULL; } @@ -547,7 +544,6 @@ struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t da struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list); uint16 val_len; unsigned int namelen; - size_t converted_size; if (!eal) { return NULL; @@ -569,10 +565,7 @@ struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t da if (pdata[namelen + 4] != '\0') { return NULL; } - if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) { - DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s", - strerror(errno))); - } + pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4); if (!eal->ea.name) { return NULL; } @@ -1892,7 +1885,7 @@ static void call_trans2findfirst(connection_struct *conn, bool requires_resume_key; int info_level; char *directory = NULL; - char *mask = NULL; + const char *mask = NULL; char *p; int last_entry_off=0; int dptr_num = -1; @@ -1980,7 +1973,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", return; } - ntstatus = unix_convert(ctx, conn, directory, True, &directory, &mask, &sbuf); + ntstatus = unix_convert(ctx, conn, directory, True, &directory, NULL, &sbuf); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); return; @@ -1996,12 +1989,10 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", if(p == NULL) { /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */ if((directory[0] == '.') && (directory[1] == '\0')) { - mask = talloc_strdup(ctx,"*"); - if (!mask) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } + mask = "*"; mask_contains_wcard = True; + } else { + mask = directory; } directory = talloc_strdup(talloc_tos(), "./"); if (!directory) { @@ -2009,6 +2000,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", return; } } else { + mask = p+1; *p = 0; } @@ -2840,11 +2832,9 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned fsp.fnum = -1; /* access check */ - 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)); + if (current_user.ut.uid != 0) { + DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", + lp_servicename(SNUM(conn)),conn->user)); reply_doserror(req, ERRDOS, ERRnoaccess); return; } @@ -3004,7 +2994,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned * in our list of SIDs. */ if (nt_token_check_sid(&global_sid_Builtin_Guests, - conn->server_info->ptok)) { + current_user.nt_user_token)) { flags |= SMB_WHOAMI_GUEST; } @@ -3012,7 +3002,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned * is in our list of SIDs. */ if (nt_token_check_sid(&global_sid_Authenticated_Users, - conn->server_info->ptok)) { + current_user.nt_user_token)) { flags &= ~SMB_WHOAMI_GUEST; } @@ -3028,18 +3018,16 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned + 4 /* num_sids */ + 4 /* SID bytes */ + 4 /* pad/reserved */ - + (conn->server_info->utok.ngroups * 8) + + (current_user.ut.ngroups * 8) /* groups list */ - + (conn->server_info->ptok->num_sids * + + (current_user.nt_user_token->num_sids * SID_MAX_SIZE) /* SID list */; SIVAL(pdata, 0, flags); SIVAL(pdata, 4, SMB_WHOAMI_MASK); - SBIG_UINT(pdata, 8, - (SMB_BIG_UINT)conn->server_info->utok.uid); - SBIG_UINT(pdata, 16, - (SMB_BIG_UINT)conn->server_info->utok.gid); + SBIG_UINT(pdata, 8, (SMB_BIG_UINT)current_user.ut.uid); + SBIG_UINT(pdata, 16, (SMB_BIG_UINT)current_user.ut.gid); if (data_len >= max_data_bytes) { @@ -3054,18 +3042,18 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned break; } - SIVAL(pdata, 24, conn->server_info->utok.ngroups); - SIVAL(pdata, 28, conn->server_info->num_sids); + SIVAL(pdata, 24, current_user.ut.ngroups); + SIVAL(pdata, 28, + current_user.nt_user_token->num_sids); /* We walk the SID list twice, but this call is fairly * infrequent, and I don't expect that it's performance * sensitive -- jpeach */ for (i = 0, sid_bytes = 0; - i < conn->server_info->ptok->num_sids; ++i) { + i < current_user.nt_user_token->num_sids; ++i) { sid_bytes += ndr_size_dom_sid( - &conn->server_info->ptok->user_sids[i], - 0); + ¤t_user.nt_user_token->user_sids[i], 0); } /* SID list byte count */ @@ -3076,21 +3064,20 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned data_len = 40; /* GID list */ - for (i = 0; i < conn->server_info->utok.ngroups; ++i) { + for (i = 0; i < current_user.ut.ngroups; ++i) { SBIG_UINT(pdata, data_len, - (SMB_BIG_UINT)conn->server_info->utok.groups[i]); + (SMB_BIG_UINT)current_user.ut.groups[i]); data_len += 8; } /* SID list */ for (i = 0; - i < conn->server_info->ptok->num_sids; ++i) { + i < current_user.nt_user_token->num_sids; ++i) { int sid_len = ndr_size_dom_sid( - &conn->server_info->ptok->user_sids[i], - 0); + ¤t_user.nt_user_token->user_sids[i], 0); sid_linearize(pdata + data_len, sid_len, - &conn->server_info->ptok->user_sids[i]); + ¤t_user.nt_user_token->user_sids[i]); data_len += sid_len; } @@ -3285,11 +3272,9 @@ cap_low = 0x%x, cap_high = 0x%x\n", ZERO_STRUCT(quotas); /* access check */ - if ((conn->server_info->utok.uid != 0) - ||!CAN_WRITE(conn)) { + if ((current_user.ut.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)); + lp_servicename(SNUM(conn)),conn->user)); reply_doserror(req, ERRSRV, ERRaccess); return; } @@ -3299,9 +3284,7 @@ cap_low = 0x%x, cap_high = 0x%x\n", * --metze */ fsp = file_fsp(SVAL(params,0)); - - if (!check_fsp_ntquota_handle(conn, req, - fsp)) { + if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); reply_nterror( req, NT_STATUS_INVALID_HANDLE); @@ -3686,10 +3669,10 @@ static NTSTATUS marshall_stream_info(unsigned int num_streams, size_t namelen; smb_ucs2_t *namebuf; - if (!push_ucs2_talloc(talloc_tos(), &namebuf, - streams[i].name, &namelen) || - namelen <= 2) - { + namelen = push_ucs2_talloc(talloc_tos(), &namebuf, + streams[i].name); + + if ((namelen == (size_t)-1) || (namelen <= 2)) { return NT_STATUS_INVALID_PARAMETER; } @@ -3884,7 +3867,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, } /* Initial check for valid fsp ptr. */ - if (!check_fsp_open(conn, req, fsp)) { + if (!check_fsp_open(conn, req, fsp, ¤t_user)) { return; } @@ -3927,7 +3910,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, /* * Original code - this is an open file. */ - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { return; } @@ -5107,8 +5090,7 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn, } /* The set is across all open files on this dev/inode pair. */ - if (!set_delete_on_close(fsp, delete_on_close, - &conn->server_info->utok)) { + if (!set_delete_on_close(fsp, delete_on_close, ¤t_user.ut)) { return NT_STATUS_ACCESS_DENIED; } return NT_STATUS_OK; @@ -5895,7 +5877,7 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, */ if (lp_inherit_perms(SNUM(conn))) { - inherit_access_posix_acl( + inherit_access_acl( conn, parent_dirname(fname), fname, unixmode); } @@ -6584,7 +6566,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, fsp = file_fsp(SVAL(params,0)); /* Basic check for non-null fsp. */ - if (!check_fsp_open(conn, req, fsp)) { + if (!check_fsp_open(conn, req, fsp, ¤t_user)) { return; } info_level = SVAL(params,2); @@ -6637,7 +6619,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, /* * Original code - this is an open file. */ - if (!check_fsp(conn, req, fsp)) { + if (!check_fsp(conn, req, fsp, ¤t_user)) { return; } @@ -7569,7 +7551,7 @@ void reply_trans2(struct smb_request *req) } } - if ((state = TALLOC_P(conn, struct trans_state)) == NULL) { + if ((state = TALLOC_P(conn->mem_ctx, struct trans_state)) == NULL) { DEBUG(0, ("talloc failed\n")); reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBtrans2); diff --git a/source/smbd/uid.c b/source/smbd/uid.c index 8998f6a371..ffa643a8f5 100644 --- a/source/smbd/uid.c +++ b/source/smbd/uid.c @@ -2,17 +2,17 @@ Unix SMB/CIFS implementation. uid/user handling Copyright (C) Andrew Tridgell 1992-1998 - + 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/>. */ @@ -23,6 +23,29 @@ extern struct current_user current_user; /**************************************************************************** + Iterator functions for getting all gid's from current_user. +****************************************************************************/ + +gid_t get_current_user_gid_first(int *piterator) +{ + *piterator = 0; + return current_user.ut.gid; +} + +gid_t get_current_user_gid_next(int *piterator) +{ + gid_t ret; + + if (!current_user.ut.groups || *piterator >= current_user.ut.ngroups) { + return (gid_t)-1; + } + + ret = current_user.ut.groups[*piterator]; + (*piterator) += 1; + return ret; +} + +/**************************************************************************** Become the guest user without changing the security context stack. ****************************************************************************/ @@ -36,62 +59,56 @@ bool change_to_guest(void) if (!pass) return(False); } - + #ifdef AIX /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before setting IDs */ initgroups(pass->pw_name, pass->pw_gid); #endif - + set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL); - + current_user.conn = NULL; current_user.vuid = UID_FIELD_INVALID; TALLOC_FREE(pass); pass = NULL; - + return True; } /******************************************************************* Check if a username is OK. - - This sets up conn->server_info with a copy related to this vuser that - later code can then mess with. ********************************************************************/ -static bool check_user_ok(connection_struct *conn, uint16_t vuid, - struct auth_serversupplied_info *server_info, - int snum) +static bool check_user_ok(connection_struct *conn, user_struct *vuser,int snum) { unsigned int i; struct vuid_cache_entry *ent = NULL; bool readonly_share; - bool admin_user; + NT_USER_TOKEN *token; - for (i=0; i<VUID_CACHE_SIZE; i++) { - ent = &conn->vuid_cache.array[i]; - if (ent->vuid == vuid) { - conn->server_info = ent->server_info; + for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) { + if (conn->vuid_cache.array[i].vuid == vuser->vuid) { + ent = &conn->vuid_cache.array[i]; conn->read_only = ent->read_only; conn->admin_user = ent->admin_user; return(True); } } - if (!user_ok_token(server_info->unix_name, - pdb_get_domain(server_info->sam_account), - server_info->ptok, snum)) + if (!user_ok_token(vuser->user.unix_name, vuser->nt_user_token, snum)) return(False); - readonly_share = is_share_read_only_for_token( - server_info->unix_name, - pdb_get_domain(server_info->sam_account), - server_info->ptok, snum); + readonly_share = is_share_read_only_for_token(vuser->user.unix_name, + vuser->nt_user_token, + SNUM(conn)); + + token = conn->nt_user_token ? + conn->nt_user_token : vuser->nt_user_token; if (!readonly_share && - !share_access_check(server_info->ptok, lp_servicename(snum), + !share_access_check(token, lp_servicename(snum), FILE_WRITE_DATA)) { /* smb.conf allows r/w, but the security descriptor denies * write. Fall back to looking at readonly. */ @@ -100,71 +117,31 @@ static bool check_user_ok(connection_struct *conn, uint16_t vuid, "security descriptor\n")); } - if (!share_access_check(server_info->ptok, lp_servicename(snum), + if (!share_access_check(token, lp_servicename(snum), readonly_share ? FILE_READ_DATA : FILE_WRITE_DATA)) { return False; } - admin_user = token_contains_name_in_list( - server_info->unix_name, - pdb_get_domain(server_info->sam_account), - NULL, server_info->ptok, lp_admin_users(snum)); - - ent = &conn->vuid_cache.array[conn->vuid_cache.next_entry]; - - conn->vuid_cache.next_entry = - (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE; - - TALLOC_FREE(ent->server_info); + i = conn->vuid_cache.entries % VUID_CACHE_SIZE; + if (conn->vuid_cache.entries < VUID_CACHE_SIZE) + conn->vuid_cache.entries++; - /* - * If force_user was set, all server_info's are based on the same - * username-based faked one. - */ - - ent->server_info = copy_serverinfo( - conn, conn->force_user ? conn->server_info : server_info); - - if (ent->server_info == NULL) { - ent->vuid = UID_FIELD_INVALID; - return false; - } - - ent->vuid = vuid; + ent = &conn->vuid_cache.array[i]; + ent->vuid = vuser->vuid; ent->read_only = readonly_share; - ent->admin_user = admin_user; + + ent->admin_user = token_contains_name_in_list( + vuser->user.unix_name, NULL, vuser->nt_user_token, + lp_admin_users(SNUM(conn))); conn->read_only = ent->read_only; conn->admin_user = ent->admin_user; - conn->server_info = ent->server_info; return(True); } /**************************************************************************** - Clear a vuid out of the connection's vuid cache -****************************************************************************/ - -void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid) -{ - int i; - - for (i=0; i<VUID_CACHE_SIZE; i++) { - struct vuid_cache_entry *ent; - - ent = &conn->vuid_cache.array[i]; - - if (ent->vuid == vuid) { - ent->vuid = UID_FIELD_INVALID; - TALLOC_FREE(ent->server_info); - ent->read_only = False; - ent->admin_user = False; - } - } -} - -/**************************************************************************** Become the user of a connection number without changing the security context stack, but modify the current_user entries. ****************************************************************************/ @@ -176,9 +153,11 @@ bool change_to_user(connection_struct *conn, uint16 vuid) gid_t gid; uid_t uid; char group_c; + bool must_free_token = False; + NT_USER_TOKEN *token = NULL; int num_groups = 0; gid_t *group_list = NULL; - + if (!conn) { DEBUG(2,("change_to_user: Connection not open\n")); return(False); @@ -192,13 +171,13 @@ bool change_to_user(connection_struct *conn, uint16 vuid) */ if((lp_security() == SEC_SHARE) && (current_user.conn == conn) && - (current_user.ut.uid == conn->server_info->utok.uid)) { + (current_user.ut.uid == conn->uid)) { DEBUG(4,("change_to_user: Skipping user change - already " "user\n")); return(True); } else if ((current_user.conn == conn) && - (vuser != NULL) && (current_user.vuid == vuid) && - (current_user.ut.uid == vuser->server_info->utok.uid)) { + (vuser != 0) && (current_user.vuid == vuid) && + (current_user.ut.uid == vuser->uid)) { DEBUG(4,("change_to_user: Skipping user change - already " "user\n")); return(True); @@ -206,30 +185,26 @@ bool change_to_user(connection_struct *conn, uint16 vuid) snum = SNUM(conn); - if ((vuser) && !check_user_ok(conn, vuid, vuser->server_info, snum)) { + if ((vuser) && !check_user_ok(conn, vuser, snum)) { DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) " "not permitted access to share %s.\n", - vuser->server_info->sanitized_username, - vuser->server_info->unix_name, vuid, + vuser->user.smb_name, vuser->user.unix_name, vuid, lp_servicename(snum))); return False; } - /* - * conn->server_info is now correctly set up with a copy we can mess - * with for force_group etc. - */ - if (conn->force_user) /* security = share sets this too */ { - uid = conn->server_info->utok.uid; - gid = conn->server_info->utok.gid; - group_list = conn->server_info->utok.groups; - num_groups = conn->server_info->utok.ngroups; + uid = conn->uid; + gid = conn->gid; + group_list = conn->groups; + num_groups = conn->ngroups; + token = conn->nt_user_token; } else if (vuser) { - uid = conn->admin_user ? 0 : vuser->server_info->utok.uid; - gid = conn->server_info->utok.gid; - num_groups = conn->server_info->utok.ngroups; - group_list = conn->server_info->utok.groups; + uid = conn->admin_user ? 0 : vuser->uid; + gid = vuser->gid; + num_groups = vuser->n_groups; + group_list = vuser->groups; + token = vuser->nt_user_token; } else { DEBUG(2,("change_to_user: Invalid vuid used %d in accessing " "share %s.\n",vuid, lp_servicename(snum) )); @@ -244,6 +219,13 @@ bool change_to_user(connection_struct *conn, uint16 vuid) if((group_c = *lp_force_group(snum))) { + token = dup_nt_token(NULL, token); + if (token == NULL) { + DEBUG(0, ("dup_nt_token failed\n")); + return False; + } + must_free_token = True; + if(group_c == '+') { /* @@ -255,21 +237,18 @@ bool change_to_user(connection_struct *conn, uint16 vuid) int i; for (i = 0; i < num_groups; i++) { - if (group_list[i] - == conn->server_info->utok.gid) { - gid = conn->server_info->utok.gid; - gid_to_sid(&conn->server_info->ptok - ->user_sids[1], gid); + if (group_list[i] == conn->gid) { + gid = conn->gid; + gid_to_sid(&token->user_sids[1], gid); break; } } } else { - gid = conn->server_info->utok.gid; - gid_to_sid(&conn->server_info->ptok->user_sids[1], - gid); + gid = conn->gid; + gid_to_sid(&token->user_sids[1], gid); } } - + /* Now set current_user since we will immediately also call set_sec_ctx() */ @@ -277,14 +256,21 @@ bool change_to_user(connection_struct *conn, uint16 vuid) current_user.ut.groups = group_list; set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups, - conn->server_info->ptok); + token); + + /* + * Free the new token (as set_sec_ctx copies it). + */ + + if (must_free_token) + TALLOC_FREE(token); current_user.conn = conn; current_user.vuid = vuid; DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n", (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid())); - + return(True); } @@ -344,29 +330,29 @@ struct conn_ctx { connection_struct *conn; uint16 vuid; }; - + /* A stack of current_user connection contexts. */ - + static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH]; static int conn_ctx_stack_ndx; static void push_conn_ctx(void) { struct conn_ctx *ctx_p; - + /* Check we don't overflow our stack */ - + if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) { DEBUG(0, ("Connection context stack overflow!\n")); smb_panic("Connection context stack overflow!\n"); } - + /* Store previous user context */ ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx]; - + ctx_p->conn = current_user.conn; ctx_p->vuid = current_user.vuid; - + DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n", (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx )); @@ -376,7 +362,7 @@ static void push_conn_ctx(void) static void pop_conn_ctx(void) { struct conn_ctx *ctx_p; - + /* Check for stack underflow. */ if (conn_ctx_stack_ndx == 0) { diff --git a/source/smbd/utmp.c b/source/smbd/utmp.c index af947ef462..de6d707eaf 100644 --- a/source/smbd/utmp.c +++ b/source/smbd/utmp.c @@ -189,7 +189,7 @@ static const char *wt_pathname = # endif /* BSD-like systems might want "lastlog" support. */ -#if 0 /* *** Not yet implemented */ +/* *** Not yet implemented */ #ifndef HAVE_PUTUTLINE /* see "pututline_my()" */ static const char *ll_pathname = # if defined (_PATH_LASTLOG) /* what other names (if any?) */ @@ -198,7 +198,6 @@ static const char *ll_pathname = "" ; # endif /* _PATH_LASTLOG */ #endif /* HAVE_PUTUTLINE */ -#endif /* * Get name of {u,w}tmp{,x} file. diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c index 1e137dd908..33a3a43aa4 100644 --- a/source/smbd/vfs.c +++ b/source/smbd/vfs.c @@ -177,7 +177,7 @@ bool vfs_init_custom(connection_struct *conn, const char *vfs_object) goto fail; } - handle = TALLOC_ZERO_P(conn, vfs_handle_struct); + handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct); if (!handle) { DEBUG(0,("TALLOC_ZERO() failed!\n")); goto fail; @@ -185,7 +185,7 @@ bool vfs_init_custom(connection_struct *conn, const char *vfs_object) memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops)); handle->conn = conn; if (module_param) { - handle->param = talloc_strdup(conn, module_param); + handle->param = talloc_strdup(conn->mem_ctx, module_param); } DLIST_ADD(conn->vfs_handles, handle); @@ -232,7 +232,7 @@ void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, } ext = (struct vfs_fsp_data *)TALLOC_ZERO( - handle->conn, sizeof(struct vfs_fsp_data) + ext_size); + handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size); if (ext == NULL) { return NULL; } |