diff options
author | Gerald Carter <jerry@samba.org> | 2002-09-25 15:19:00 +0000 |
---|---|---|
committer | Gerald Carter <jerry@samba.org> | 2002-09-25 15:19:00 +0000 |
commit | a834a73e341059be154426390304a42e4a011f72 (patch) | |
tree | 7f53b0f7819238e0ee0396daccf5d924cb9b8d29 /source3/smbd | |
parent | 115a39775cb923d026dde58633b6ba6aef3a1943 (diff) | |
download | samba-a834a73e341059be154426390304a42e4a011f72.tar.gz samba-a834a73e341059be154426390304a42e4a011f72.tar.bz2 samba-a834a73e341059be154426390304a42e4a011f72.zip |
sync'ing up for 3.0alpha20 release
(This used to be commit 65e7b5273bb58802bf0c389b77f7fcae0a1f6139)
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/blocking.c | 34 | ||||
-rw-r--r-- | source3/smbd/conn.c | 24 | ||||
-rw-r--r-- | source3/smbd/connection.c | 84 | ||||
-rw-r--r-- | source3/smbd/dir.c | 121 | ||||
-rw-r--r-- | source3/smbd/filename.c | 2 | ||||
-rw-r--r-- | source3/smbd/mangle_hash.c | 2 | ||||
-rw-r--r-- | source3/smbd/mangle_hash2.c | 16 | ||||
-rw-r--r-- | source3/smbd/negprot.c | 14 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 108 | ||||
-rw-r--r-- | source3/smbd/open.c | 65 | ||||
-rw-r--r-- | source3/smbd/password.c | 162 | ||||
-rw-r--r-- | source3/smbd/posix_acls.c | 30 | ||||
-rw-r--r-- | source3/smbd/process.c | 288 | ||||
-rw-r--r-- | source3/smbd/reply.c | 547 | ||||
-rw-r--r-- | source3/smbd/sec_ctx.c | 13 | ||||
-rw-r--r-- | source3/smbd/server.c | 10 | ||||
-rw-r--r-- | source3/smbd/service.c | 39 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 40 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 69 | ||||
-rw-r--r-- | source3/smbd/uid.c | 42 | ||||
-rw-r--r-- | source3/smbd/vfs-wrap.c | 15 | ||||
-rw-r--r-- | source3/smbd/vfs.c | 9 |
22 files changed, 1049 insertions, 685 deletions
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 6623c6df64..9d411711cb 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -531,13 +531,33 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum )); } /**************************************************************************** - Return True if the blocking lock queue has entries. + Return the number of seconds to the next blocking locks timeout, or default_timeout *****************************************************************************/ - -BOOL blocking_locks_pending(void) +unsigned blocking_locks_timeout(unsigned default_timeout) { - blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue ); - return (blr == NULL ? False : True); + unsigned timeout = default_timeout; + time_t t; + blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst(&blocking_lock_queue); + + /* note that we avoid the time() syscall if there are no blocking locks */ + if (!blr) { + return timeout; + } + + t = time(NULL); + + while (blr) { + if (timeout > (blr->expire_time - t)) { + timeout = blr->expire_time - t; + } + blr = (blocking_lock_record *)ubi_slNext(blr); + } + + if (timeout < 1) { + timeout = 1; + } + + return timeout; } /**************************************************************************** @@ -576,7 +596,7 @@ void process_blocking_lock_queue(time_t t) DEBUG(5,("process_blocking_lock_queue: examining pending lock fnum = %d for file %s\n", fsp->fnum, fsp->fsp_name )); - if((blr->expire_time != -1) && (blr->expire_time > t)) { + if((blr->expire_time != -1) && (blr->expire_time <= t)) { /* * Lock expired - throw away all previously * obtained locks and return lock error. @@ -584,7 +604,7 @@ void process_blocking_lock_queue(time_t t) DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n", fsp->fnum, fsp->fsp_name )); - blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED); + blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue)); continue; diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c index d70e50f899..22407348e8 100644 --- a/source3/smbd/conn.c +++ b/source3/smbd/conn.c @@ -131,7 +131,7 @@ void conn_close_all(void) connection_struct *conn, *next; for (conn=Connections;conn;conn=next) { next=conn->next; - close_cnum(conn, (uint16)-1); + close_cnum(conn, conn->vuid); } } @@ -158,6 +158,27 @@ BOOL conn_idle_all(time_t t, int deadtime) } /**************************************************************************** +clear a vuid out of the validity cache, and as the 'owner' of a connection. +****************************************************************************/ +void conn_clear_vuid_cache(uint16 vuid) +{ + connection_struct *conn; + int i; + + for (conn=Connections;conn;conn=conn->next) { + if (conn->vuid == vuid) { + conn->vuid = UID_FIELD_INVALID; + } + + for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) { + if (conn->vuid_cache.list[i] == vuid) { + conn->vuid_cache.list[i] = UID_FIELD_INVALID; + } + } + } +} + +/**************************************************************************** Free a conn structure. ****************************************************************************/ @@ -191,7 +212,6 @@ void conn_free(connection_struct *conn) conn->ngroups = 0; } - delete_nt_token(&conn->nt_user_token); free_namearray(conn->veto_list); free_namearray(conn->hide_list); free_namearray(conn->veto_oplock_list); diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c index 5609c2963d..ad394a01ca 100644 --- a/source3/smbd/connection.c +++ b/source3/smbd/connection.c @@ -28,14 +28,24 @@ static TDB_CONTEXT *tdb; TDB_CONTEXT *conn_tdb_ctx(void) { - if (!tdb) { + if (!tdb) tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, O_RDWR | O_CREAT, 0644); - } return tdb; } +static void make_conn_key(connection_struct *conn,char *name, TDB_DATA *pkbuf, struct connections_key *pkey) +{ + ZERO_STRUCTP(pkey); + pkey->pid = sys_getpid(); + pkey->cnum = conn?conn->cnum:-1; + fstrcpy(pkey->name, name); + + pkbuf->dptr = (char *)pkey; + pkbuf->dsize = sizeof(*pkey); +} + /**************************************************************************** Delete a connection record. ****************************************************************************/ @@ -45,17 +55,12 @@ BOOL yield_connection(connection_struct *conn,char *name) struct connections_key key; TDB_DATA kbuf; - if (!tdb) return False; + if (!tdb) + return False; DEBUG(3,("Yielding connection to %s\n",name)); - ZERO_STRUCT(key); - key.pid = sys_getpid(); - key.cnum = conn?conn->cnum:-1; - fstrcpy(key.name, name); - - kbuf.dptr = (char *)&key; - kbuf.dsize = sizeof(key); + make_conn_key(conn, name, &kbuf, &key); if (tdb_delete(tdb, kbuf) != 0) { int dbg_lvl = (!conn && (tdb_error(tdb) == TDB_ERR_NOEXIST)) ? 3 : 0; @@ -88,7 +93,7 @@ static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *u memcpy(&crec, dbuf.dptr, sizeof(crec)); - if (crec.cnum == -1) + if (crec.cnum == -1) return 0; /* If the pid was not found delete the entry from connections.tdb */ @@ -111,16 +116,16 @@ static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *u Claim an entry in the connections database. ****************************************************************************/ -BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear) +BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear, uint32 msg_flags) { struct connections_key key; struct connections_data crec; TDB_DATA kbuf, dbuf; - if (!tdb) { + if (!tdb) tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, O_RDWR | O_CREAT, 0644); - } + if (!tdb) return False; @@ -156,13 +161,7 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO DEBUG(5,("claiming %s %d\n",name,max_connections)); - ZERO_STRUCT(key); - key.pid = sys_getpid(); - key.cnum = conn?conn->cnum:-1; - fstrcpy(key.name, name); - - kbuf.dptr = (char *)&key; - kbuf.dsize = sizeof(key); + make_conn_key(conn, name, &kbuf, &key); /* fill in the crec */ ZERO_STRUCT(crec); @@ -176,6 +175,7 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO lp_servicename(SNUM(conn)),sizeof(crec.name)-1); } crec.start = time(NULL); + crec.bcast_msg_flags = msg_flags; StrnCpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine)-1); StrnCpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1); @@ -191,3 +191,45 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO return True; } + +BOOL register_message_flags(BOOL doreg, uint32 msg_flags) +{ + struct connections_key key; + struct connections_data *pcrec; + TDB_DATA kbuf, dbuf; + + if (!tdb) + return False; + + DEBUG(10,("register_message_flags: %s flags 0x%x\n", + doreg ? "adding" : "removing", + (unsigned int)msg_flags )); + + make_conn_key(NULL, "", &kbuf, &key); + + dbuf = tdb_fetch(tdb, kbuf); + if (!dbuf.dptr) { + DEBUG(0,("register_message_flags: tdb_fetch failed\n")); + return False; + } + + pcrec = (struct connections_data *)dbuf.dptr; + pcrec->bcast_msg_flags = msg_flags; + if (doreg) + pcrec->bcast_msg_flags |= msg_flags; + else + pcrec->bcast_msg_flags &= ~msg_flags; + + if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) { + DEBUG(0,("register_message_flags: tdb_store failed with error %s.\n", + tdb_errorstr(tdb) )); + SAFE_FREE(dbuf.dptr); + return False; + } + + DEBUG(10,("register_message_flags: new flags 0x%x\n", + (unsigned int)pcrec->bcast_msg_flags )); + + SAFE_FREE(dbuf.dptr); + return True; +} diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 1a18476b75..396ecd98c4 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -553,9 +553,24 @@ void *dptr_fetch_lanman2(int dptr_num) BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype) { - if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0) - return False; - return True; + int mask; + + /* Check the "may have" search bits. */ + if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0) + return False; + + /* Check the "must have" bits, which are the may have bits shifted eight */ + /* If must have bit is set, the file/dir can not be returned in search unless the matching + file attribute is set */ + mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */ + if(mask) { + if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */ + return True; + else + return False; + } + + return True; } static BOOL mangle_mask_match(connection_struct *conn, char *filename, char *mask) @@ -663,18 +678,15 @@ typedef struct char *current; } Dir; - - /******************************************************************* -check to see if a user can read a file. This is only approximate, -it is used as part of the "hide unreadable" option. Don't -use it for anything security sensitive + Check to see if a user can read a file. This is only approximate, + it is used as part of the "hide unreadable" option. Don't + 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) { extern struct current_user current_user; - SMB_STRUCT_STAT ste; SEC_DESC *psd = NULL; size_t sd_size; files_struct *fsp; @@ -683,8 +695,6 @@ static BOOL user_can_read_file(connection_struct *conn, char *name) NTSTATUS status; uint32 access_granted; - ZERO_STRUCT(ste); - /* * If user is a member of the Admin group * we never hide files from them. @@ -694,16 +704,16 @@ static BOOL user_can_read_file(connection_struct *conn, char *name) return True; /* If we can't stat it does not show it */ - if (vfs_stat(conn, name, &ste) != 0) + if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0)) return False; /* Pseudo-open the file (note - no fd's created). */ - if(S_ISDIR(ste.st_mode)) - fsp = open_directory(conn, name, &ste, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), + if(S_ISDIR(pst->st_mode)) + fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), unix_mode(conn,aRONLY|aDIR, name), &smb_action); else - fsp = open_file_shared1(conn, name, &ste, FILE_READ_ATTRIBUTES, SET_DENY_MODE(DENY_NONE), + fsp = open_file_shared1(conn, name, pst, FILE_READ_ATTRIBUTES, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action); if (!fsp) @@ -722,16 +732,15 @@ static BOOL user_can_read_file(connection_struct *conn, char *name) } /******************************************************************* -check to see if a user can write a file (and only files, we do not -check dirs on this one). This is only approximate, -it is used as part of the "hide unwriteable" option. Don't -use it for anything security sensitive + Check to see if a user can write a file (and only files, we do not + check dirs on this one). This is only approximate, + it is used as part of the "hide unwriteable" option. Don't + use it for anything security sensitive. ********************************************************************/ -static BOOL user_can_write_file(connection_struct *conn, char *name) +static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst) { extern struct current_user current_user; - SMB_STRUCT_STAT ste; SEC_DESC *psd = NULL; size_t sd_size; files_struct *fsp; @@ -740,8 +749,6 @@ static BOOL user_can_write_file(connection_struct *conn, char *name) NTSTATUS status; uint32 access_granted; - ZERO_STRUCT(ste); - /* * If user is a member of the Admin group * we never hide files from them. @@ -751,15 +758,15 @@ static BOOL user_can_write_file(connection_struct *conn, char *name) return True; /* If we can't stat it does not show it */ - if (vfs_stat(conn, name, &ste) != 0) + if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0)) return False; /* Pseudo-open the file (note - no fd's created). */ - if(S_ISDIR(ste.st_mode)) + if(S_ISDIR(pst->st_mode)) return True; else - fsp = open_file_shared1(conn, name, &ste, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE), + fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action); if (!fsp) @@ -778,6 +785,30 @@ static BOOL user_can_write_file(connection_struct *conn, char *name) } /******************************************************************* + Is a file a "special" type ? +********************************************************************/ + +static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst) +{ + /* + * If user is a member of the Admin group + * we never hide files from them. + */ + + if (conn->admin_user) + return True; + + /* If we can't stat it does not show it */ + if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0)) + return True; + + if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode)) + return False; + + return True; +} + +/******************************************************************* Open a directory. ********************************************************************/ @@ -802,6 +833,8 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto) while (True) { int l; BOOL normal_entry = True; + SMB_STRUCT_STAT st; + char *entry = NULL; if (used == 0) { n = "."; @@ -818,6 +851,7 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto) normal_entry = True; } + ZERO_STRUCT(st); l = strlen(n)+1; /* If it's a vetoed file, pretend it doesn't even exist */ @@ -826,30 +860,45 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto) /* Honour _hide unreadable_ option */ if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) { - char *entry; int ret=0; - if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { - ret = user_can_read_file(conn, entry); - SAFE_FREE(entry); + if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { + ret = user_can_read_file(conn, entry, &st); } - if (!ret) + if (!ret) { + SAFE_FREE(entry); continue; + } } /* Honour _hide unwriteable_ option */ if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) { - char *entry; int ret=0; - if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { - ret = user_can_write_file(conn, entry); + if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { + ret = user_can_write_file(conn, entry, &st); + } + if (!ret) { SAFE_FREE(entry); + continue; + } + } + + /* Honour _hide_special_ option */ + if (normal_entry && conn && lp_hide_special_files(SNUM(conn))) { + int ret=0; + + if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { + ret = file_is_special(conn, entry, &st); } - if (!ret) + if (ret) { + SAFE_FREE(entry); continue; + } } + SAFE_FREE(entry); + if (used + l > dirp->mallocsize) { int s = MAX(used+l,used+2000); char *r; diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index ce98af4ace..d343db26f6 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -168,7 +168,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen pstrcpy(orig_path, name); - if(stat_cache_lookup(conn, name, dirpath, &start, &st)) { + if(!case_sensitive && stat_cache_lookup(conn, name, dirpath, &start, &st)) { *pst = st; return True; } diff --git a/source3/smbd/mangle_hash.c b/source3/smbd/mangle_hash.c index 1d4697474c..0446a953ff 100644 --- a/source3/smbd/mangle_hash.c +++ b/source3/smbd/mangle_hash.c @@ -730,7 +730,7 @@ static void name_map(char *OutName, BOOL need83, BOOL cache83) DEBUG(5,("name_map( %s, need83 = %s, cache83 = %s)\n", OutName, need83 ? "True" : "False", cache83 ? "True" : "False")); - if (push_ucs2_allocate((void **)&OutName_ucs2, OutName) < 0) { + if (push_ucs2_allocate(&OutName_ucs2, OutName) < 0) { DEBUG(0, ("push_ucs2_allocate failed!\n")); return; } diff --git a/source3/smbd/mangle_hash2.c b/source3/smbd/mangle_hash2.c index 6b53cc72aa..a0a3d51139 100644 --- a/source3/smbd/mangle_hash2.c +++ b/source3/smbd/mangle_hash2.c @@ -200,7 +200,7 @@ static BOOL is_mangled_component(const char *name) { int len, i; - M_DEBUG(0,("is_mangled_component %s ?\n", name)); + M_DEBUG(10,("is_mangled_component %s ?\n", name)); /* check the length */ len = strlen(name); @@ -234,7 +234,7 @@ static BOOL is_mangled_component(const char *name) } } - M_DEBUG(0,("is_mangled %s -> yes\n", name)); + M_DEBUG(10,("is_mangled %s -> yes\n", name)); return True; } @@ -257,7 +257,7 @@ static BOOL is_mangled(const char *name) const char *p; const char *s; - M_DEBUG(0,("is_mangled %s ?\n", name)); + M_DEBUG(10,("is_mangled %s ?\n", name)); for (s=name; (p=strchr(s, '/')); s=p+1) { char *component = strndup(s, PTR_DIFF(p, s)); @@ -367,7 +367,7 @@ static BOOL check_cache(char *name) /* make sure that this is a mangled name from this cache */ if (!is_mangled(name)) { - M_DEBUG(0,("check_cache: %s -> not mangled\n", name)); + M_DEBUG(10,("check_cache: %s -> not mangled\n", name)); return False; } @@ -382,7 +382,7 @@ static BOOL check_cache(char *name) /* now look in the prefix cache for that hash */ prefix = cache_lookup(hash); if (!prefix) { - M_DEBUG(0,("check_cache: %s -> %08X -> not found\n", name, hash)); + M_DEBUG(10,("check_cache: %s -> %08X -> not found\n", name, hash)); return False; } @@ -395,10 +395,10 @@ static BOOL check_cache(char *name) } if (extension[0]) { - M_DEBUG(0,("check_cache: %s -> %s.%s\n", name, prefix, extension)); + M_DEBUG(10,("check_cache: %s -> %s.%s\n", name, prefix, extension)); slprintf(name, sizeof(fstring), "%s.%s", prefix, extension); } else { - M_DEBUG(0,("check_cache: %s -> %s\n", name, prefix)); + M_DEBUG(10,("check_cache: %s -> %s\n", name, prefix)); fstrcpy(name, prefix); } @@ -573,7 +573,7 @@ static void name_map(char *name, BOOL need83, BOOL cache83) cache_insert(name, prefix_len, hash); } - M_DEBUG(0,("name_map: %s -> %08X -> %s (cache=%d)\n", + M_DEBUG(10,("name_map: %s -> %08X -> %s (cache=%d)\n", name, hash, new_name, cache83)); /* and overwrite the old name */ diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index 2be04fd686..16427b00d7 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -170,9 +170,9 @@ static int negprot_spnego(char *p) DATA_BLOB blob; extern pstring global_myname; uint8 guid[16]; - const char *OIDs_krb5[] = {OID_NTLMSSP, - OID_KERBEROS5, + const char *OIDs_krb5[] = {OID_KERBEROS5, OID_KERBEROS5_OLD, + OID_NTLMSSP, NULL}; const char *OIDs_plain[] = {OID_NTLMSSP, NULL}; char *principal; @@ -199,9 +199,7 @@ static int negprot_spnego(char *p) if (lp_security() != SEC_ADS) { blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE"); } else { - /* win2000 uses host$@REALM, which we will probably use eventually, - but for now this works */ - asprintf(&principal, "HOST/%s@%s", guid, lp_realm()); + asprintf(&principal, "%s$@%s", guid, lp_realm()); blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal); free(principal); } @@ -239,7 +237,11 @@ static int reply_nt1(char *inbuf, char *outbuf) capabilities |= CAP_EXTENDED_SECURITY; } - capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNIX; + capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS; + + if (lp_unix_extensions()) { + capabilities |= CAP_UNIX; + } if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS; diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index cf69dfddb0..1f3bbd488e 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -371,7 +371,7 @@ static int map_share_mode( char *fname, uint32 create_options, if (smb_open_mode == -1) { - if(*desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS| + if(*desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS| FILE_EXECUTE|FILE_READ_ATTRIBUTES| FILE_READ_EA|FILE_WRITE_EA|SYSTEM_SECURITY_ACCESS| FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS)) { @@ -548,6 +548,7 @@ int reply_ntcreate_and_X(connection_struct *conn, uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition); uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions); uint16 root_dir_fid = (uint16)IVAL(inbuf,smb_ntcreate_RootDirectoryFid); + SMB_OFF_T allocation_size = 0; int smb_ofun; int smb_open_mode; int smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK); @@ -563,8 +564,16 @@ int reply_ntcreate_and_X(connection_struct *conn, files_struct *fsp=NULL; char *p = NULL; time_t c_time; + BOOL extended_oplock_granted = False; + START_PROFILE(SMBntcreateX); + DEBUG(10,("reply_ntcreateX: flags = 0x%x, desired_access = 0x%x \ +file_attributes = 0x%x, share_access = 0x%x, create_disposition = 0x%x \ +create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attributes, + share_access, create_disposition, + create_options, root_dir_fid )); + /* If it's an IPC, use the pipe handler. */ if (IS_IPC(conn)) { @@ -573,10 +582,14 @@ int reply_ntcreate_and_X(connection_struct *conn, return do_ntcreate_pipe_open(conn,inbuf,outbuf,length,bufsize); } else { END_PROFILE(SMBntcreateX); - return(ERROR_DOS(ERRDOS,ERRbadaccess)); + return(ERROR_DOS(ERRDOS,ERRnoaccess)); } } + if (create_options & FILE_OPEN_BY_FILE_ID) { + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_NOT_SUPPORTED); + } /* * We need to construct the open_and_X ofun value from the @@ -585,7 +598,7 @@ int reply_ntcreate_and_X(connection_struct *conn, if((smb_ofun = map_create_disposition( create_disposition )) == -1) { END_PROFILE(SMBntcreateX); - return(ERROR_DOS(ERRDOS,ERRbadaccess)); + return(ERROR_DOS(ERRDOS,ERRnoaccess)); } /* @@ -660,7 +673,7 @@ int reply_ntcreate_and_X(connection_struct *conn, share_access, file_attributes)) == -1) { END_PROFILE(SMBntcreateX); - return ERROR_DOS(ERRDOS,ERRbadaccess); + return ERROR_DOS(ERRDOS,ERRnoaccess); } oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; @@ -689,6 +702,12 @@ int reply_ntcreate_and_X(connection_struct *conn, if(create_options & FILE_DIRECTORY_FILE) { oplock_request = 0; + /* Can't open a temp directory. IFS kit test. */ + if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) { + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); + } + fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action); restore_case_semantics(file_attributes); @@ -787,6 +806,22 @@ int reply_ntcreate_and_X(connection_struct *conn, return ERROR_DOS(ERRDOS,ERRnoaccess); } + /* Save the requested allocation size. */ + allocation_size = IVAL(inbuf,smb_ntcreate_AllocationSize); +#ifdef LARGE_SMB_OFF_T + allocation_size |= (((SMB_OFF_T)IVAL(inbuf,smb_ntcreate_AllocationSize + 4)) << 32); +#endif + if (allocation_size && (allocation_size > file_len)) { + fsp->initial_allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE); + if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { + close_file(fsp,False); + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_DISK_FULL); + } + } else { + fsp->initial_allocation_size = SMB_ROUNDUP(file_len,SMB_ROUNDUP_ALLOCATION_SIZE); + } + /* * If the caller set the extended oplock request bit * and we granted one (by whatever means) - set the @@ -794,10 +829,10 @@ int reply_ntcreate_and_X(connection_struct *conn, */ if (oplock_request && lp_fake_oplocks(SNUM(conn))) - smb_action |= EXTENDED_OPLOCK_GRANTED; + extended_oplock_granted = True; if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - smb_action |= EXTENDED_OPLOCK_GRANTED; + extended_oplock_granted = True; #if 0 /* W2K sends back 42 words here ! If we do the same it breaks offline sync. Go figure... ? JRA. */ @@ -813,7 +848,7 @@ int reply_ntcreate_and_X(connection_struct *conn, * exclusive & batch here. */ - if (smb_action & EXTENDED_OPLOCK_GRANTED) { + if (extended_oplock_granted) { if (flags & REQUEST_BATCH_OPLOCK) { SCVAL(p,0, BATCH_OPLOCK_RETURN); } else { @@ -828,7 +863,10 @@ int reply_ntcreate_and_X(connection_struct *conn, p++; SSVAL(p,0,fsp->fnum); p += 2; - SIVAL(p,0,smb_action); + if ((create_disposition == FILE_SUPERSEDE) && (smb_action == FILE_WAS_OVERWRITTEN)) + SIVAL(p,0,FILE_WAS_SUPERSEDED); + else + SIVAL(p,0,smb_action); p += 4; /* Create time. */ @@ -851,7 +889,7 @@ int reply_ntcreate_and_X(connection_struct *conn, p += 8; SIVAL(p,0,fmode); /* File Attributes. */ p += 4; - SOFF_T(p, 0, get_allocation_size(&sbuf)); + SOFF_T(p, 0, get_allocation_size(fsp,&sbuf)); p += 8; SOFF_T(p,0,file_len); p += 12; @@ -886,7 +924,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn, if(total_parameter_count < 54) { DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)total_parameter_count)); - return ERROR_DOS(ERRDOS,ERRbadaccess); + return ERROR_DOS(ERRDOS,ERRnoaccess); } srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE); @@ -1018,6 +1056,7 @@ static int call_nt_transact_create(connection_struct *conn, BOOL bad_path = False; files_struct *fsp = NULL; char *p = NULL; + BOOL extended_oplock_granted = False; uint32 flags; uint32 desired_access; uint32 file_attributes; @@ -1026,6 +1065,7 @@ static int call_nt_transact_create(connection_struct *conn, uint32 create_options; uint32 sd_len; uint16 root_dir_fid; + SMB_OFF_T allocation_size = 0; int smb_ofun; int smb_open_mode; int smb_attr; @@ -1043,7 +1083,7 @@ static int call_nt_transact_create(connection_struct *conn, return do_nt_transact_create_pipe(conn, inbuf, outbuf, length, bufsize, ppsetup, ppparams, ppdata); else - return ERROR_DOS(ERRDOS,ERRbadaccess); + return ERROR_DOS(ERRDOS,ERRnoaccess); } /* @@ -1052,7 +1092,7 @@ static int call_nt_transact_create(connection_struct *conn, if(total_parameter_count < 54) { DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)total_parameter_count)); - return ERROR_DOS(ERRDOS,ERRbadaccess); + return ERROR_DOS(ERRDOS,ERRnoaccess); } flags = IVAL(params,0); @@ -1065,6 +1105,11 @@ static int call_nt_transact_create(connection_struct *conn, root_dir_fid = (uint16)IVAL(params,4); smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK); + if (create_options & FILE_OPEN_BY_FILE_ID) { + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_NOT_SUPPORTED); + } + /* * We need to construct the open_and_X ofun value from the * NT values, as that's what our code is structured to accept. @@ -1138,7 +1183,7 @@ static int call_nt_transact_create(connection_struct *conn, if((smb_open_mode = map_share_mode( fname, create_options, &desired_access, share_access, file_attributes)) == -1) - return ERROR_DOS(ERRDOS,ERRbadaccess); + return ERROR_DOS(ERRDOS,ERRnoaccess); oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; @@ -1161,6 +1206,12 @@ static int call_nt_transact_create(connection_struct *conn, if(create_options & FILE_DIRECTORY_FILE) { + /* Can't open a temp directory. IFS kit test. */ + if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) { + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); + } + oplock_request = 0; /* @@ -1234,10 +1285,10 @@ static int call_nt_transact_create(connection_struct *conn, */ if (oplock_request && lp_fake_oplocks(SNUM(conn))) - smb_action |= EXTENDED_OPLOCK_GRANTED; + extended_oplock_granted = True; if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - smb_action |= EXTENDED_OPLOCK_GRANTED; + extended_oplock_granted = True; } /* @@ -1252,6 +1303,22 @@ static int call_nt_transact_create(connection_struct *conn, restore_case_semantics(file_attributes); + /* Save the requested allocation size. */ + allocation_size = IVAL(params,12); +#ifdef LARGE_SMB_OFF_T + allocation_size |= (((SMB_OFF_T)IVAL(params,16)) << 32); +#endif + if (allocation_size && (allocation_size > file_len)) { + fsp->initial_allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE); + if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { + close_file(fsp,False); + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_DISK_FULL); + } + } else { + fsp->initial_allocation_size = SMB_ROUNDUP(file_len,SMB_ROUNDUP_ALLOCATION_SIZE); + } + /* Realloc the size of parameters and data we will return */ params = Realloc(*ppparams, 69); if(params == NULL) @@ -1262,7 +1329,7 @@ static int call_nt_transact_create(connection_struct *conn, memset((char *)params,'\0',69); p = params; - if (smb_action & EXTENDED_OPLOCK_GRANTED) + if (extended_oplock_granted) SCVAL(p,0, BATCH_OPLOCK_RETURN); else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) SCVAL(p,0, LEVEL_II_OPLOCK_RETURN); @@ -1272,7 +1339,10 @@ static int call_nt_transact_create(connection_struct *conn, p += 2; SSVAL(p,0,fsp->fnum); p += 2; - SIVAL(p,0,smb_action); + if ((create_disposition == FILE_SUPERSEDE) && (smb_action == FILE_WAS_OVERWRITTEN)) + SIVAL(p,0,FILE_WAS_SUPERSEDED); + else + SIVAL(p,0,smb_action); p += 8; /* Create time. */ @@ -1295,7 +1365,7 @@ static int call_nt_transact_create(connection_struct *conn, p += 8; SIVAL(p,0,fmode); /* File Attributes. */ p += 4; - SOFF_T(p, 0, get_allocation_size(&sbuf)); + SOFF_T(p, 0, get_allocation_size(fsp,&sbuf)); p += 8; SOFF_T(p,0,file_len); @@ -1582,7 +1652,7 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, (unsigned int)security_info_sent )); if (total_data_count == 0) - return ERROR_DOS(ERRDOS, ERRbadaccess); + return ERROR_DOS(ERRDOS, ERRnoaccess); if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, total_data_count, security_info_sent))) return ERROR_NT(nt_status); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 8c6e8ed805..a95793a050 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -139,18 +139,31 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, * as we always opened files read-write in that release. JRA. */ - if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) + if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) { + DEBUG(10,("open_file: truncate requested on read-only open for file %s\n",fname )); local_flags = (flags & ~O_ACCMODE)|O_RDWR; + } - /* - * We can't actually truncate here as the file may be locked. - * open_file_shared will take care of the truncate later. JRA. - */ + if ((desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || + (local_flags & O_CREAT) || ((local_flags & O_TRUNC) == O_TRUNC) ) { - local_flags &= ~O_TRUNC; + /* + * We can't actually truncate here as the file may be locked. + * open_file_shared will take care of the truncate later. JRA. + */ - if ((desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || - (local_flags & O_CREAT)) { + local_flags &= ~O_TRUNC; + +#if defined(O_NONBLOCK) && defined(S_ISFIFO) + /* + * We would block on opening a FIFO with no one else on the + * other end. Do what we used to do and add O_NONBLOCK to the + * open flags. JRA. + */ + + if (VALID_STAT(*psbuf) && S_ISFIFO(psbuf->st_mode)) + local_flags |= O_NONBLOCK; +#endif /* actually do the open */ fsp->fd = fd_open(conn, fname, local_flags, mode); @@ -679,6 +692,31 @@ static void kernel_flock(files_struct *fsp, int deny_mode) } +static BOOL open_match_attributes(connection_struct *conn, char *path, mode_t existing_mode, mode_t new_mode) +{ + uint32 old_dos_mode, new_dos_mode; + SMB_STRUCT_STAT sbuf; + + ZERO_STRUCT(sbuf); + + sbuf.st_mode = existing_mode; + old_dos_mode = dos_mode(conn, path, &sbuf); + + sbuf.st_mode = new_mode; + new_dos_mode = dos_mode(conn, path, &sbuf); + + /* If we're mapping SYSTEM and HIDDEN ensure they match. */ + if (lp_map_system(SNUM(conn))) { + if ((old_dos_mode & FILE_ATTRIBUTE_SYSTEM) != (new_dos_mode & FILE_ATTRIBUTE_SYSTEM)) + return False; + } + if (lp_map_hidden(SNUM(conn))) { + if ((old_dos_mode & FILE_ATTRIBUTE_HIDDEN) != (new_dos_mode & FILE_ATTRIBUTE_HIDDEN)) + return False; + } + return True; +} + /**************************************************************************** Open a file with a share mode. On output from this open we are guarenteeing that @@ -773,6 +811,17 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ if (CAN_WRITE(conn) && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)) flags2 |= O_TRUNC; + /* We only care about matching attributes on file exists and truncate. */ + if (file_existed && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)) { + if (!open_match_attributes(conn, fname, psbuf->st_mode, mode)) { + DEBUG(5,("open_file_shared: attributes missmatch for file %s (0%o, 0%o)\n", + fname, psbuf->st_mode, mode )); + file_free(fsp); + errno = EACCES; + return NULL; + } + } + if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL) flags2 |= O_EXCL; diff --git a/source3/smbd/password.c b/source3/smbd/password.c index cfac7cf695..f2956237dd 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -69,6 +69,10 @@ void invalidate_vuid(uint16 vuid) DLIST_REMOVE(validated_users, vuser); + /* clear the vuid from the 'cache' on each connection, and + from the vuid 'owner' of connections */ + conn_clear_vuid_cache(vuid); + SAFE_FREE(vuser->groups); delete_nt_token(&vuser->nt_user_token); SAFE_FREE(vuser); @@ -90,95 +94,6 @@ void invalidate_all_vuids(void) } /**************************************************************************** - Create the SID list for this user. -****************************************************************************/ - -NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, BOOL is_guest, NT_USER_TOKEN *sup_tok) -{ - extern DOM_SID global_sid_World; - extern DOM_SID global_sid_Network; - extern DOM_SID global_sid_Builtin_Guests; - extern DOM_SID global_sid_Authenticated_Users; - NT_USER_TOKEN *token; - DOM_SID *psids; - int i, psid_ndx = 0; - size_t num_sids = 0; - fstring sid_str; - - if ((token = (NT_USER_TOKEN *)malloc( sizeof(NT_USER_TOKEN) ) ) == NULL) - return NULL; - - ZERO_STRUCTP(token); - - /* We always have uid/gid plus World and Network and Authenticated Users or Guest SIDs. */ - num_sids = 5 + ngroups; - - if (sup_tok && sup_tok->num_sids) - num_sids += sup_tok->num_sids; - - if ((token->user_sids = (DOM_SID *)malloc( num_sids*sizeof(DOM_SID))) == NULL) { - SAFE_FREE(token); - return NULL; - } - - psids = token->user_sids; - - /* - * Note - user SID *MUST* be first in token ! - * se_access_check depends on this. - */ - - uid_to_sid( &psids[PRIMARY_USER_SID_INDEX], uid); - psid_ndx++; - - /* - * Primary group SID is second in token. Convention. - */ - - gid_to_sid( &psids[PRIMARY_GROUP_SID_INDEX], gid); - psid_ndx++; - - /* Now add the group SIDs. */ - - for (i = 0; i < ngroups; i++) { - if (groups[i] != gid) { - gid_to_sid( &psids[psid_ndx++], groups[i]); - } - } - - if (sup_tok) { - /* Now add the additional SIDs from the supplimentary token. */ - for (i = 0; i < sup_tok->num_sids; i++) - sid_copy( &psids[psid_ndx++], &sup_tok->user_sids[i] ); - } - - /* - * Finally add the "standard" SIDs. - * The only difference between guest and "anonymous" (which we - * don't really support) is the addition of Authenticated_Users. - */ - - sid_copy( &psids[psid_ndx++], &global_sid_World); - sid_copy( &psids[psid_ndx++], &global_sid_Network); - - if (is_guest) - sid_copy( &psids[psid_ndx++], &global_sid_Builtin_Guests); - else - sid_copy( &psids[psid_ndx++], &global_sid_Authenticated_Users); - - token->num_sids = psid_ndx; - - /* Dump list of sids in token */ - - for (i = 0; i < token->num_sids; i++) { - DEBUG(5, ("user token sid %s\n", - sid_to_string(sid_str, &token->user_sids[i]))); - } - - return token; -} - -/**************************************************************************** register a uid/name pair as being valid and that a valid password has been given. vuid is biased by an offset. This allows us to tell random client vuid's (normally zero) from valid vuids. @@ -187,8 +102,6 @@ tell random client vuid's (normally zero) from valid vuids. int register_vuid(auth_serversupplied_info *server_info, const char *smb_name) { user_struct *vuser = NULL; - uid_t uid; - gid_t gid; /* Ensure no vuid gets registered in share level security. */ if(lp_security() == SEC_SHARE) @@ -205,15 +118,6 @@ int register_vuid(auth_serversupplied_info *server_info, const char *smb_name) ZERO_STRUCTP(vuser); - if (!IS_SAM_UNIX_USER(server_info->sam_account)) { - DEBUG(0,("Attempted session setup with invalid user. No uid/gid in SAM_ACCOUNT (flags:%x)\n", pdb_get_init_flag(server_info->sam_account))); - free(vuser); - return UID_FIELD_INVALID; - } - - uid = pdb_get_uid(server_info->sam_account); - gid = pdb_get_gid(server_info->sam_account); - /* Allocate a free vuid. Yes this is a linear search... :-) */ while( get_valid_user_struct(next_vuid) != NULL ) { next_vuid++; @@ -225,18 +129,38 @@ int register_vuid(auth_serversupplied_info *server_info, const char *smb_name) DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid )); vuser->vuid = next_vuid; - vuser->uid = uid; - vuser->gid = gid; + + /* 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 + */ + if (!IS_SAM_UNIX_USER(server_info->sam_account)) { + DEBUG(0,("Attempted session setup with invalid user. No uid/gid in SAM_ACCOUNT (flags:%x)\n", pdb_get_init_flag(server_info->sam_account))); + free(vuser); + return UID_FIELD_INVALID; + } + + vuser->uid = pdb_get_uid(server_info->sam_account); + vuser->gid = pdb_get_gid(server_info->sam_account); + + vuser->n_groups = server_info->n_groups; + if (vuser->n_groups) { + if (!(vuser->groups = memdup(server_info->groups, sizeof(gid_t) * vuser->n_groups))) { + DEBUG(0,("register_vuid: failed to memdup vuser->groups\n")); + free(vuser); + return UID_FIELD_INVALID; + } + } + vuser->guest = server_info->guest; - fstrcpy(vuser->user.unix_name, pdb_get_username(server_info->sam_account)); - fstrcpy(vuser->user.smb_name, smb_name); + fstrcpy(vuser->user.unix_name, pdb_get_username(server_info->sam_account)); + fstrcpy(vuser->user.smb_name, 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 *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); + const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); /* should be optained by SMS */ const char *logon_script = pdb_get_logon_script(server_info->sam_account); if (homedir) { vuser->homedir = smb_xstrdup(homedir); @@ -260,19 +184,13 @@ int register_vuid(auth_serversupplied_info *server_info, const char *smb_name) DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->user.unix_name,vuser->user.full_name)); - vuser->n_groups = 0; - vuser->groups = NULL; - - /* Find all the groups this uid is in and store them. - Used by change_to_user() */ - initialise_groups(vuser->user.unix_name, vuser->uid, vuser->gid); - get_current_groups(vuser->gid, &vuser->n_groups, &vuser->groups); - - if (server_info->ptok) - add_supplementary_nt_login_groups(&vuser->n_groups, &vuser->groups, &server_info->ptok); - - /* Create an NT_USER_TOKEN struct for this user. */ - vuser->nt_user_token = create_nt_token(vuser->uid, vuser->gid, vuser->n_groups, vuser->groups, vuser->guest, server_info->ptok); + if (server_info->ptok) { + vuser->nt_user_token = dup_nt_token(server_info->ptok); + } else { + DEBUG(1, ("server_info does not contain a user_token - cannot continue\n")); + free(vuser); + return UID_FIELD_INVALID; + } DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n",(int)vuser->uid,vuser->user.unix_name, vuser->vuid)); @@ -306,9 +224,11 @@ add a name to the session users list void add_session_user(const char *user) { fstring suser; - StrnCpy(suser,user,sizeof(suser)-1); + struct passwd *passwd; + + if (!(passwd = Get_Pwnam(user))) return; - if (!Get_Pwnam_Modify(suser)) return; + StrnCpy(suser,passwd->pw_name,sizeof(suser)-1); if (suser && *suser && !in_list(suser,session_users,False)) { @@ -451,7 +371,7 @@ static char *validate_group(char *group, DATA_BLOB password,int snum) Note this is *NOT* used when logging on using sessionsetup_and_X. ****************************************************************************/ -BOOL authorise_login(int snum,char *user, DATA_BLOB password, +BOOL authorise_login(int snum, fstring user, DATA_BLOB password, BOOL *guest) { BOOL ok = False; diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 043e33e836..e6ae1c7d79 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -1881,6 +1881,8 @@ static int nt_ace_comp( SEC_ACE *a1, SEC_ACE *a2) size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) { + extern DOM_SID global_sid_Builtin_Administrators; + extern DOM_SID global_sid_Builtin_Users; connection_struct *conn = fsp->conn; SMB_STRUCT_STAT sbuf; SEC_ACE *nt_ace_list = NULL; @@ -1895,6 +1897,7 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) SMB_ACL_T dir_acl = NULL; canon_ace *file_ace = NULL; canon_ace *dir_ace = NULL; + size_t num_profile_acls = 0; *ppdesc = NULL; @@ -1939,7 +1942,14 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) * Get the owner, group and world SIDs. */ - create_file_sids(&sbuf, &owner_sid, &group_sid); + if (lp_profile_acls(SNUM(fsp->conn))) { + /* For WXP SP1 the owner must be administrators. */ + sid_copy(&owner_sid, &global_sid_Builtin_Administrators); + sid_copy(&group_sid, &global_sid_Builtin_Users); + num_profile_acls = 2; + } else { + create_file_sids(&sbuf, &owner_sid, &group_sid); + } /* Create the canon_ace lists. */ file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid); @@ -1963,7 +1973,7 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) } /* Allocate the ace list. */ - if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) { + if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) { DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n")); goto done; } @@ -1986,6 +1996,13 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, 0); } + /* The User must have access to a profile share - even if we can't map the SID. */ + if (lp_profile_acls(SNUM(fsp->conn))) { + SEC_ACCESS acc; + init_sec_access(&acc,FILE_GENERIC_ALL); + init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc, 0); + } + ace = dir_ace; for (i = 0; i < num_dir_acls; i++, ace = ace->next) { @@ -1994,6 +2011,15 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); } + /* The User must have access to a profile share - even if we can't map the SID. */ + if (lp_profile_acls(SNUM(fsp->conn))) { + SEC_ACCESS acc; + init_sec_access(&acc,FILE_GENERIC_ALL); + init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc, + SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY); + } + /* * Sort to force deny entries to the front. */ diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 55234ec896..0f7cfd0e9c 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -42,8 +42,8 @@ extern int last_message; extern int global_oplock_break; extern userdom_struct current_user_info; extern int smb_read_error; -SIG_ATOMIC_T reload_after_sighup; -SIG_ATOMIC_T got_sig_term; +SIG_ATOMIC_T reload_after_sighup = 0; +SIG_ATOMIC_T got_sig_term = 0; extern BOOL global_machine_password_needs_changing; extern fstring global_myworkgroup; extern pstring global_myname; @@ -609,8 +609,9 @@ const static struct smb_message_struct }; /******************************************************************* -dump a prs to a file - ********************************************************************/ + Dump a packet to a file. +********************************************************************/ + static void smb_dump(const char *name, int type, char *data, ssize_t len) { int fd, i; @@ -635,178 +636,171 @@ static void smb_dump(const char *name, int type, char *data, ssize_t len) /**************************************************************************** -do a switch on the message type, and return the response size + Do a switch on the message type, and return the response size ****************************************************************************/ + static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize) { - static pid_t pid= (pid_t)-1; - int outsize = 0; - extern uint16 global_smbpid; - - type &= 0xff; + static pid_t pid= (pid_t)-1; + int outsize = 0; + extern uint16 global_smbpid; - if (pid == (pid_t)-1) - pid = sys_getpid(); + type &= 0xff; - errno = 0; - last_message = type; - - /* make sure this is an SMB packet */ - if (strncmp(smb_base(inbuf),"\377SMB",4) != 0) - { - DEBUG(2,("Non-SMB packet of length %d\n",smb_len(inbuf))); - return(-1); - } + if (pid == (pid_t)-1) + pid = sys_getpid(); - /* yuck! this is an interim measure before we get rid of our - current inbuf/outbuf system */ - global_smbpid = SVAL(inbuf,smb_pid); + errno = 0; + last_message = type; - if (smb_messages[type].fn == NULL) - { - DEBUG(0,("Unknown message type %d!\n",type)); - smb_dump("Unknown", 1, inbuf, size); - outsize = reply_unknown(inbuf,outbuf); - } - else - { - int flags = smb_messages[type].flags; - static uint16 last_session_tag = UID_FIELD_INVALID; - /* In share mode security we must ignore the vuid. */ - uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid); - connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); + /* Make sure this is an SMB packet. smb_size contains NetBIOS header so subtract 4 from it. */ + if ((strncmp(smb_base(inbuf),"\377SMB",4) != 0) || (size < (smb_size - 4))) { + DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",smb_len(inbuf))); + exit_server("Non-SMB packet"); + return(-1); + } - DEBUG(3,("switch message %s (pid %d)\n",smb_fn_name(type),(int)pid)); + /* yuck! this is an interim measure before we get rid of our + current inbuf/outbuf system */ + global_smbpid = SVAL(inbuf,smb_pid); + + if (smb_messages[type].fn == NULL) { + DEBUG(0,("Unknown message type %d!\n",type)); + smb_dump("Unknown", 1, inbuf, size); + outsize = reply_unknown(inbuf,outbuf); + } else { + int flags = smb_messages[type].flags; + static uint16 last_session_tag = UID_FIELD_INVALID; + /* In share mode security we must ignore the vuid. */ + uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid); + connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); + + DEBUG(3,("switch message %s (pid %d)\n",smb_fn_name(type),(int)pid)); + + smb_dump(smb_fn_name(type), 1, inbuf, size); + if(global_oplock_break) { + if(flags & QUEUE_IN_OPLOCK) { + /* + * Queue this message as we are the process of an oplock break. + */ + + DEBUG( 2, ( "switch_message: queueing message due to being in " ) ); + DEBUGADD( 2, ( "oplock break state.\n" ) ); + + push_oplock_pending_smb_message( inbuf, size ); + return -1; + } + } - smb_dump(smb_fn_name(type), 1, inbuf, size); - if(global_oplock_break) - { - if(flags & QUEUE_IN_OPLOCK) - { - /* - * Queue this message as we are the process of an oplock break. - */ - - DEBUG( 2, ( "switch_message: queueing message due to being in " ) ); - DEBUGADD( 2, ( "oplock break state.\n" ) ); - - push_oplock_pending_smb_message( inbuf, size ); - return -1; - } - } + /* Ensure this value is replaced in the incoming packet. */ + SSVAL(inbuf,smb_uid,session_tag); - /* Ensure this value is replaced in the incoming packet. */ - SSVAL(inbuf,smb_uid,session_tag); + /* + * Ensure the correct username is in current_user_info. + * This is a really ugly bugfix for problems with + * multiple session_setup_and_X's being done and + * allowing %U and %G substitutions to work correctly. + * There is a reason this code is done here, don't + * move it unless you know what you're doing... :-). + * JRA. + */ - /* - * Ensure the correct username is in current_user_info. - * This is a really ugly bugfix for problems with - * multiple session_setup_and_X's being done and - * allowing %U and %G substitutions to work correctly. - * There is a reason this code is done here, don't - * move it unless you know what you're doing... :-). - * JRA. - */ + if (session_tag != last_session_tag) { + user_struct *vuser = NULL; - if (session_tag != last_session_tag) { - user_struct *vuser = NULL; + last_session_tag = session_tag; + if(session_tag != UID_FIELD_INVALID) + vuser = get_valid_user_struct(session_tag); + if(vuser != NULL) + current_user_info = vuser->user; + } - last_session_tag = session_tag; - if(session_tag != UID_FIELD_INVALID) - vuser = get_valid_user_struct(session_tag); - if(vuser != NULL) - current_user_info = vuser->user; - } + /* does this protocol need to be run as root? */ + if (!(flags & AS_USER)) + change_to_root_user(); - /* does this protocol need to be run as root? */ - if (!(flags & AS_USER)) - change_to_root_user(); + /* does this protocol need a valid tree connection? */ + if ((flags & AS_USER) && !conn) + return ERROR_DOS(ERRSRV, ERRinvnid); - /* does this protocol need a valid tree connection? */ - if ((flags & AS_USER) && !conn) { - return ERROR_DOS(ERRSRV, ERRinvnid); - } + /* does this protocol need to be run as the connected user? */ + if ((flags & AS_USER) && !change_to_user(conn,session_tag)) { + if (flags & AS_GUEST) + flags &= ~AS_USER; + else + return(ERROR_DOS(ERRSRV,ERRaccess)); + } - /* does this protocol need to be run as the connected user? */ - if ((flags & AS_USER) && !change_to_user(conn,session_tag)) { - if (flags & AS_GUEST) - flags &= ~AS_USER; - else - return(ERROR_DOS(ERRSRV,ERRaccess)); - } - - /* this code is to work around a bug is MS client 3 without - introducing a security hole - it needs to be able to do - print queue checks as guest if it isn't logged in properly */ - if (flags & AS_USER) - flags &= ~AS_GUEST; + /* this code is to work around a bug is MS client 3 without + introducing a security hole - it needs to be able to do + print queue checks as guest if it isn't logged in properly */ + if (flags & AS_USER) + flags &= ~AS_GUEST; - /* does it need write permission? */ - if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) - return(ERROR_DOS(ERRSRV,ERRaccess)); + /* does it need write permission? */ + if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) + return(ERROR_DOS(ERRSRV,ERRaccess)); - /* ipc services are limited */ - if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC)) { - return(ERROR_DOS(ERRSRV,ERRaccess)); - } + /* ipc services are limited */ + if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC)) + return(ERROR_DOS(ERRSRV,ERRaccess)); - /* load service specific parameters */ - if (conn && !set_current_service(conn,(flags & AS_USER)?True:False)) { - return(ERROR_DOS(ERRSRV,ERRaccess)); - } + /* load service specific parameters */ + if (conn && !set_current_service(conn,(flags & AS_USER)?True:False)) + return(ERROR_DOS(ERRSRV,ERRaccess)); - /* does this protocol need to be run as guest? */ - if ((flags & AS_GUEST) && - (!change_to_guest() || - !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) { - return(ERROR_DOS(ERRSRV,ERRaccess)); - } + /* does this protocol need to be run as guest? */ + if ((flags & AS_GUEST) && (!change_to_guest() || + !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) + return(ERROR_DOS(ERRSRV,ERRaccess)); - last_inbuf = inbuf; + last_inbuf = inbuf; - outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize); - } + outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize); + } - smb_dump(smb_fn_name(type), 0, outbuf, outsize); + smb_dump(smb_fn_name(type), 0, outbuf, outsize); - return(outsize); + return(outsize); } /**************************************************************************** - construct a reply to the incoming packet + Construct a reply to the incoming packet. ****************************************************************************/ + static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize) { - int type = CVAL(inbuf,smb_com); - int outsize = 0; - int msg_type = CVAL(inbuf,0); + int type = CVAL(inbuf,smb_com); + int outsize = 0; + int msg_type = CVAL(inbuf,0); - GetTimeOfDay(&smb_last_time); + GetTimeOfDay(&smb_last_time); - chain_size = 0; - file_chain_reset(); - reset_chain_p(); + chain_size = 0; + file_chain_reset(); + reset_chain_p(); - if (msg_type != 0) - return(reply_special(inbuf,outbuf)); + if (msg_type != 0) + return(reply_special(inbuf,outbuf)); - construct_reply_common(inbuf, outbuf); + construct_reply_common(inbuf, outbuf); - outsize = switch_message(type,inbuf,outbuf,size,bufsize); + outsize = switch_message(type,inbuf,outbuf,size,bufsize); - outsize += chain_size; + outsize += chain_size; - if(outsize > 4) - smb_setlen(outbuf,outsize - 4); - return(outsize); + if(outsize > 4) + smb_setlen(outbuf,outsize - 4); + return(outsize); } /**************************************************************************** - Keep track of the number of running smbd's. This functionality is used to - 'hard' limit Samba overhead on resource constrained systems. + Keep track of the number of running smbd's. This functionality is used to + 'hard' limit Samba overhead on resource constrained systems. ****************************************************************************/ + static BOOL smbd_process_limit(void) { int32 total_smbds; @@ -1032,16 +1026,15 @@ static int setup_select_timeout(void) int select_timeout; int t; - /* - * Increase the select timeout back to SMBD_SELECT_TIMEOUT if we - * have removed any blocking locks. JRA. - */ - - select_timeout = blocking_locks_pending() ? SMBD_SELECT_TIMEOUT_WITH_PENDING_LOCKS*1000 : - SMBD_SELECT_TIMEOUT*1000; + select_timeout = blocking_locks_timeout(SMBD_SELECT_TIMEOUT); + select_timeout *= 1000; t = change_notify_timeout(); - if (t != -1) select_timeout = MIN(select_timeout, t*1000); + if (t != -1) + select_timeout = MIN(select_timeout, t*1000); + + if (print_notify_messages_pending()) + select_timeout = MIN(select_timeout, 1000); return select_timeout; } @@ -1161,9 +1154,16 @@ static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_t * First, open the machine password file with an exclusive lock. */ + if (secrets_lock_trust_account_password(global_myworkgroup, True) == False) { + DEBUG(0,("process: unable to lock the machine account password for \ +machine %s in domain %s.\n", global_myname, global_myworkgroup )); + return True; + } + if(!secrets_fetch_trust_account_password(global_myworkgroup, trust_passwd_hash, &lct)) { DEBUG(0,("process: unable to read the machine account password for \ machine %s in domain %s.\n", global_myname, global_myworkgroup )); + secrets_lock_trust_account_password(global_myworkgroup, False); return True; } @@ -1173,6 +1173,7 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup )); if(t < lct + lp_machine_password_timeout()) { global_machine_password_needs_changing = False; + secrets_lock_trust_account_password(global_myworkgroup, False); return True; } @@ -1180,6 +1181,7 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup )); change_trust_account_password( global_myworkgroup, remote_machine_list); global_machine_password_needs_changing = False; + secrets_lock_trust_account_password(global_myworkgroup, False); } /* @@ -1201,6 +1203,10 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup )); force_check_log_size(); check_log_size(); + /* Send any queued printer notify message to interested smbd's. */ + + print_notify_send_messages(); + /* * Modify the select timeout depending upon * what we have remaining in our queues. diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index c6a082d7d8..a881e135c0 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -23,7 +23,6 @@ makes to handle specific protocols */ - #include "includes.h" /* look in server.c for some explanation of these variables */ @@ -40,9 +39,8 @@ unsigned int smb_echo_count = 0; extern BOOL global_encrypted_passwords_negotiated; - /**************************************************************************** - reply to an special message + Reply to an special message. ****************************************************************************/ int reply_special(char *inbuf,char *outbuf) @@ -113,7 +111,7 @@ int reply_special(char *inbuf,char *outbuf) reload_services(True); reopen_logs(); - claim_connection(NULL,"",MAXSTATUS,True); + claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD); already_got_session = True; break; @@ -141,7 +139,6 @@ int reply_special(char *inbuf,char *outbuf) return(outsize); } - /**************************************************************************** Reply to a tcon. ****************************************************************************/ @@ -307,10 +304,10 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt return chain_reply(inbuf,outbuf,length,bufsize); } - /**************************************************************************** - reply to an unknown type + Reply to an unknown type. ****************************************************************************/ + int reply_unknown(char *inbuf,char *outbuf) { int type; @@ -322,10 +319,10 @@ int reply_unknown(char *inbuf,char *outbuf) return(ERROR_DOS(ERRSRV,ERRunknownsmb)); } - /**************************************************************************** - reply to an ioctl + Reply to an ioctl. ****************************************************************************/ + int reply_ioctl(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -339,8 +336,7 @@ int reply_ioctl(connection_struct *conn, DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code)); - switch (ioctl_code) - { + switch (ioctl_code) { case IOCTL_QUERY_JOB_INFO: replysize = 32; break; @@ -355,16 +351,15 @@ int reply_ioctl(connection_struct *conn, SSVAL(outbuf,smb_vwv6,52); /* Offset to data */ p = smb_buf(outbuf) + 1; /* Allow for alignment */ - switch (ioctl_code) - { - case IOCTL_QUERY_JOB_INFO: - { - uint16 rap_jobid = pjobid_to_rap(SNUM(fsp->conn), fsp->print_jobid); - SSVAL(p,0,rap_jobid); /* Job number */ - srvstr_push(outbuf, p+2, global_myname, 15, STR_TERMINATE|STR_ASCII); - srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII); - break; - } + switch (ioctl_code) { + case IOCTL_QUERY_JOB_INFO: + { + uint16 rap_jobid = pjobid_to_rap(SNUM(fsp->conn), fsp->print_jobid); + SSVAL(p,0,rap_jobid); /* Job number */ + srvstr_push(outbuf, p+2, global_myname, 15, STR_TERMINATE|STR_ASCII); + srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII); + break; + } } END_PROFILE(SMBioctl); @@ -372,56 +367,56 @@ int reply_ioctl(connection_struct *conn, } /**************************************************************************** - reply to a chkpth + Reply to a chkpth. ****************************************************************************/ + int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - int outsize = 0; - int mode; - pstring name; - BOOL ok = False; - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - START_PROFILE(SMBchkpth); + int outsize = 0; + int mode; + pstring name; + BOOL ok = False; + BOOL bad_path = False; + SMB_STRUCT_STAT sbuf; + START_PROFILE(SMBchkpth); - srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE); + srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE); - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); + RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - unix_convert(name,conn,0,&bad_path,&sbuf); + unix_convert(name,conn,0,&bad_path,&sbuf); - mode = SVAL(inbuf,smb_vwv0); + mode = SVAL(inbuf,smb_vwv0); - if (check_name(name,conn)) { - if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0) - ok = S_ISDIR(sbuf.st_mode); - } + if (check_name(name,conn)) { + if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0) + ok = S_ISDIR(sbuf.st_mode); + } - if (!ok) { - /* We special case this - as when a Windows machine - is parsing a path is steps through the components - one at a time - if a component fails it expects - ERRbadpath, not ERRbadfile. - */ - if(errno == ENOENT) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - } + if (!ok) { + /* We special case this - as when a Windows machine + is parsing a path is steps through the components + one at a time - if a component fails it expects + ERRbadpath, not ERRbadfile. + */ + if(errno == ENOENT) + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - return(UNIXERROR(ERRDOS,ERRbadpath)); - } + return(UNIXERROR(ERRDOS,ERRbadpath)); + } - outsize = set_message(outbuf,0,0,True); + outsize = set_message(outbuf,0,0,True); - DEBUG(3,("chkpth %s mode=%d\n", name, mode)); + DEBUG(3,("chkpth %s mode=%d\n", name, mode)); - END_PROFILE(SMBchkpth); - return(outsize); + END_PROFILE(SMBchkpth); + return(outsize); } - /**************************************************************************** - reply to a getatr + Reply to a getatr. ****************************************************************************/ + int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring fname; @@ -494,10 +489,10 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return(outsize); } - /**************************************************************************** - reply to a setatr + Reply to a setatr. ****************************************************************************/ + int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring fname; @@ -543,10 +538,10 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return(outsize); } - /**************************************************************************** - reply to a dskattr + Reply to a dskattr. ****************************************************************************/ + int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { int outsize = 0; @@ -591,11 +586,11 @@ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz return(outsize); } - /**************************************************************************** - reply to a search - Can be called from SMBsearch, SMBffirst or SMBfunique. + Reply to a search. + Can be called from SMBsearch, SMBffirst or SMBfunique. ****************************************************************************/ + int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring mask; @@ -673,12 +668,16 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (strlen(directory) == 0) pstrcpy(directory,"./"); memset((char *)status,'\0',21); - SCVAL(status,0,dirtype); + SCVAL(status,0,(dirtype & 0x1F)); } else { + int status_dirtype; memcpy(status,p,21); - dirtype = CVAL(status,0) & 0x1F; + status_dirtype = CVAL(status,0) & 0x1F; + if (status_dirtype != (dirtype & 0x1F)) + dirtype = status_dirtype; + conn->dirptr = dptr_fetch(status+12,&dptr_num); if (!conn->dirptr) goto SearchEmpty; @@ -796,10 +795,10 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return(outsize); } - /**************************************************************************** - reply to a fclose (stop directory search) + Reply to a fclose (stop directory search). ****************************************************************************/ + int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { int outsize = 0; @@ -838,9 +837,8 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return(outsize); } - /**************************************************************************** - reply to an open + Reply to an open. ****************************************************************************/ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) @@ -910,10 +908,10 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return(outsize); } - /**************************************************************************** - reply to an open and X + Reply to an open and X. ****************************************************************************/ + int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { pstring fname; @@ -1019,10 +1017,10 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt return chain_reply(inbuf,outbuf,length,bufsize); } - /**************************************************************************** - reply to a SMBulogoffX + Reply to a SMBulogoffX. ****************************************************************************/ + int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { uint16 vuid = SVAL(inbuf,smb_uid); @@ -1049,10 +1047,10 @@ int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length, return chain_reply(inbuf,outbuf,length,bufsize); } - /**************************************************************************** - reply to a mknew or a create + Reply to a mknew or a create. ****************************************************************************/ + int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring fname; @@ -1122,10 +1120,10 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return(outsize); } - /**************************************************************************** - reply to a create temporary file + Reply to a create temporary file. ****************************************************************************/ + int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { pstring fname; @@ -1434,6 +1432,59 @@ void fail_readraw(void) } /**************************************************************************** + Use sendfile in readbraw. +****************************************************************************/ + +void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T startpos, size_t nread, + ssize_t mincount, char *outbuf) +{ + ssize_t ret=0; + +#if defined(WITH_SENDFILE) + /* + * We can only use sendfile on a non-chained packet and on a file + * that is exclusively oplocked. reply_readbraw has already checked the length. + */ + + if ((nread > 0) && (lp_write_cache_size(SNUM(conn)) == 0) && + EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && lp_use_sendfile(SNUM(conn)) ) { + DATA_BLOB header; + + _smb_setlen(outbuf,nread); + header.data = outbuf; + header.length = 4; + header.free = NULL; + + if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) { + /* + * Special hack for broken Linux with no 64 bit clean sendfile. If we + * return ENOSYS then pretend we just got a normal read. + */ + if (errno == ENOSYS) + goto normal_read; + + DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n", + fsp->fsp_name, strerror(errno) )); + exit_server("send_file_readbraw sendfile failed"); + } + + } + + normal_read: +#endif + + if (nread > 0) { + ret = read_file(fsp,outbuf+4,startpos,nread); + if (ret < mincount) + ret = 0; + } + + _smb_setlen(outbuf,ret); + if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret) + fail_readraw(); +} + +/**************************************************************************** Reply to a readbraw (core+ protocol). ****************************************************************************/ @@ -1443,7 +1494,6 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s size_t nread = 0; SMB_OFF_T startpos; char *header = outbuf; - ssize_t ret=0; files_struct *fsp; START_PROFILE(SMBreadbraw); @@ -1547,15 +1597,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos, (int)maxcount, (int)mincount, (int)nread ) ); - if (nread > 0) { - ret = read_file(fsp,header+4,startpos,nread); - if (ret < mincount) - ret = 0; - } - - _smb_setlen(header,ret); - if (write_data(smbd_server_fd(),header,4+ret) != 4+ret) - fail_readraw(); + send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf); DEBUG(5,("readbraw finished\n")); END_PROFILE(SMBreadbraw); @@ -1563,8 +1605,9 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s } /**************************************************************************** - reply to a lockread (core+ protocol) + Reply to a lockread (core+ protocol). ****************************************************************************/ + int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz) { ssize_t nread = -1; @@ -1599,15 +1642,16 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK); if (NT_STATUS_V(status)) { - if (lp_blocking_locks(SNUM(conn))) { + if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) { /* * A blocking lock was requested. Package up * this smb into a queued request and push it * onto the blocking lock queue. */ - if(push_blocking_lock_request(inbuf, length, -1, 0)) + if(push_blocking_lock_request(inbuf, length, -1, 0)) { END_PROFILE(SMBlockread); - return -1; + return -1; + } } END_PROFILE(SMBlockread); return ERROR_NT(status); @@ -1632,132 +1676,209 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length return(outsize); } - /**************************************************************************** - reply to a read + Reply to a read. ****************************************************************************/ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { - size_t numtoread; - ssize_t nread = 0; - char *data; - SMB_OFF_T startpos; - int outsize = 0; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBread); - - CHECK_FSP(fsp,conn); - CHECK_READ(fsp); + size_t numtoread; + ssize_t nread = 0; + char *data; + SMB_OFF_T startpos; + int outsize = 0; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBread); - numtoread = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); + CHECK_FSP(fsp,conn); + CHECK_READ(fsp); + numtoread = SVAL(inbuf,smb_vwv1); + startpos = IVAL(inbuf,smb_vwv2); - outsize = set_message(outbuf,5,3,True); - numtoread = MIN(BUFFER_SIZE-outsize,numtoread); - data = smb_buf(outbuf) + 3; + outsize = set_message(outbuf,5,3,True); + numtoread = MIN(BUFFER_SIZE-outsize,numtoread); + data = smb_buf(outbuf) + 3; - if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { - END_PROFILE(SMBread); - return ERROR_DOS(ERRDOS,ERRlock); - } + if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { + END_PROFILE(SMBread); + return ERROR_DOS(ERRDOS,ERRlock); + } - if (numtoread > 0) - nread = read_file(fsp,data,startpos,numtoread); + if (numtoread > 0) + nread = read_file(fsp,data,startpos,numtoread); - if (nread < 0) { - END_PROFILE(SMBread); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + if (nread < 0) { + END_PROFILE(SMBread); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - outsize += nread; - SSVAL(outbuf,smb_vwv0,nread); - SSVAL(outbuf,smb_vwv5,nread+3); - SCVAL(smb_buf(outbuf),0,1); - SSVAL(smb_buf(outbuf),1,nread); + outsize += nread; + SSVAL(outbuf,smb_vwv0,nread); + SSVAL(outbuf,smb_vwv5,nread+3); + SCVAL(smb_buf(outbuf),0,1); + SSVAL(smb_buf(outbuf),1,nread); - DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n", - fsp->fnum, (int)numtoread, (int)nread ) ); + DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n", + fsp->fnum, (int)numtoread, (int)nread ) ); - END_PROFILE(SMBread); - return(outsize); + END_PROFILE(SMBread); + return(outsize); } +/**************************************************************************** + Reply to a read and X - possibly using sendfile. +****************************************************************************/ + +int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, + files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt) +{ + ssize_t nread = -1; + char *data = smb_buf(outbuf); + +#if defined(WITH_SENDFILE) + /* + * We can only use sendfile on a non-chained packet and on a file + * that is exclusively oplocked. + */ + + if ((CVAL(inbuf,smb_vwv0) == 0xFF) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && + lp_use_sendfile(SNUM(conn)) && (lp_write_cache_size(SNUM(conn)) == 0) ) { + SMB_STRUCT_STAT sbuf; + DATA_BLOB header; + + if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + + if (startpos > sbuf.st_size) + goto normal_read; + + if (smb_maxcnt > (sbuf.st_size - startpos)) + smb_maxcnt = (sbuf.st_size - startpos); + + if (smb_maxcnt == 0) + goto normal_read; + + /* + * Set up the packet header before send. We + * assume here the sendfile will work (get the + * correct amount of data). + */ + + SSVAL(outbuf,smb_vwv5,smb_maxcnt); + SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); + SSVAL(smb_buf(outbuf),-2,smb_maxcnt); + SCVAL(outbuf,smb_vwv0,0xFF); + set_message(outbuf,12,smb_maxcnt,False); + header.data = outbuf; + header.length = data - outbuf; + header.free = NULL; + + if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) { + /* + * Special hack for broken Linux with no 64 bit clean sendfile. If we + * return ENOSYS then pretend we just got a normal read. + */ + if (errno == ENOSYS) + goto normal_read; + + DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n", + fsp->fsp_name, strerror(errno) )); + exit_server("send_file_readX sendfile failed"); + } + + DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n", + fsp->fnum, (int)smb_maxcnt, (int)nread ) ); + return -1; + } + + normal_read: + +#endif + + nread = read_file(fsp,data,startpos,smb_maxcnt); + + if (nread < 0) { + END_PROFILE(SMBreadX); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + SSVAL(outbuf,smb_vwv5,nread); + SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); + SSVAL(smb_buf(outbuf),-2,nread); + + DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n", + fsp->fnum, (int)smb_maxcnt, (int)nread ) ); + + return nread; +} /**************************************************************************** - reply to a read and X + Reply to a read and X. ****************************************************************************/ + int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3); - size_t smb_maxcnt = SVAL(inbuf,smb_vwv5); - size_t smb_mincnt = SVAL(inbuf,smb_vwv6); - ssize_t nread = -1; - char *data; - START_PROFILE(SMBreadX); + files_struct *fsp = file_fsp(inbuf,smb_vwv2); + SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3); + ssize_t nread = -1; + size_t smb_maxcnt = SVAL(inbuf,smb_vwv5); +#if 0 + size_t smb_mincnt = SVAL(inbuf,smb_vwv6); +#endif - /* If it's an IPC, pass off the pipe handler. */ - if (IS_IPC(conn)) { - END_PROFILE(SMBreadX); - return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize); - } + START_PROFILE(SMBreadX); - CHECK_FSP(fsp,conn); - CHECK_READ(fsp); + /* If it's an IPC, pass off the pipe handler. */ + if (IS_IPC(conn)) { + END_PROFILE(SMBreadX); + return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize); + } + + CHECK_FSP(fsp,conn); + CHECK_READ(fsp); - set_message(outbuf,12,0,True); - data = smb_buf(outbuf); + set_message(outbuf,12,0,True); - if(CVAL(inbuf,smb_wct) == 12) { + if(CVAL(inbuf,smb_wct) == 12) { #ifdef LARGE_SMB_OFF_T - /* - * This is a large offset (64 bit) read. - */ - startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32); + /* + * This is a large offset (64 bit) read. + */ + startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32); #else /* !LARGE_SMB_OFF_T */ - /* - * Ensure we haven't been sent a >32 bit offset. - */ + /* + * Ensure we haven't been sent a >32 bit offset. + */ - if(IVAL(inbuf,smb_vwv10) != 0) { - DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \ + if(IVAL(inbuf,smb_vwv10) != 0) { + DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \ 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) )); - END_PROFILE(SMBreadX); - return ERROR_DOS(ERRDOS,ERRbadaccess); - } + END_PROFILE(SMBreadX); + return ERROR_DOS(ERRDOS,ERRbadaccess); + } #endif /* LARGE_SMB_OFF_T */ - } + } - if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { - END_PROFILE(SMBreadX); - return ERROR_DOS(ERRDOS,ERRlock); - } - nread = read_file(fsp,data,startpos,smb_maxcnt); + if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { + END_PROFILE(SMBreadX); + return ERROR_DOS(ERRDOS,ERRlock); + } - if (nread < 0) { - END_PROFILE(SMBreadX); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - SSVAL(outbuf,smb_vwv5,nread); - SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); - SSVAL(smb_buf(outbuf),-2,nread); - - DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n", - fsp->fnum, (int)smb_mincnt, (int)smb_maxcnt, (int)nread ) ); + nread = send_file_readX(conn, inbuf, outbuf, length, fsp, startpos, smb_maxcnt); + if (nread != -1) + nread = chain_reply(inbuf,outbuf,length,bufsize); - END_PROFILE(SMBreadX); - return chain_reply(inbuf,outbuf,length,bufsize); + END_PROFILE(SMBreadX); + return nread; } /**************************************************************************** - reply to a writebraw (core+ or LANMAN1.0 protocol) + Reply to a writebraw (core+ or LANMAN1.0 protocol). ****************************************************************************/ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) @@ -1888,7 +2009,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, } /**************************************************************************** - reply to a writeunlock (core+) + Reply to a writeunlock (core+). ****************************************************************************/ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, @@ -1950,7 +2071,6 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, return outsize; } - /**************************************************************************** Reply to a write. ****************************************************************************/ @@ -2029,10 +2149,10 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d return(outsize); } - /**************************************************************************** - reply to a write and X + Reply to a write and X. ****************************************************************************/ + int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { files_struct *fsp = file_fsp(inbuf,smb_vwv2); @@ -2129,9 +2249,8 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng return chain_reply(inbuf,outbuf,length,bufsize); } - /**************************************************************************** - reply to a lseek + Reply to a lseek. ****************************************************************************/ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) @@ -2212,7 +2331,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int } /**************************************************************************** - reply to a flush + Reply to a flush. ****************************************************************************/ int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) @@ -2234,10 +2353,10 @@ int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int return(outsize); } - /**************************************************************************** - reply to a exit + Reply to a exit. ****************************************************************************/ + int reply_exit(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -2251,10 +2370,10 @@ int reply_exit(connection_struct *conn, return(outsize); } - /**************************************************************************** Reply to a close - has to deal with closing a directory opened by NT SMB's. ****************************************************************************/ + int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { @@ -2336,9 +2455,8 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, return(outsize); } - /**************************************************************************** - reply to a writeclose (Core+ protocol) + Reply to a writeclose (Core+ protocol). ****************************************************************************/ int reply_writeclose(connection_struct *conn, @@ -2395,10 +2513,10 @@ int reply_writeclose(connection_struct *conn, return(outsize); } - /**************************************************************************** - reply to a lock + Reply to a lock. ****************************************************************************/ + int reply_lock(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsize) { @@ -2420,7 +2538,7 @@ int reply_lock(connection_struct *conn, status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK); if (NT_STATUS_V(status)) { - if (lp_blocking_locks(SNUM(conn))) { + if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) { /* * A blocking lock was requested. Package up * this smb into a queued request and push it @@ -2439,10 +2557,10 @@ int reply_lock(connection_struct *conn, return(outsize); } - /**************************************************************************** - reply to a unlock + Reply to a unlock. ****************************************************************************/ + int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { @@ -2470,10 +2588,10 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, return(outsize); } - /**************************************************************************** - reply to a tdis + Reply to a tdis. ****************************************************************************/ + int reply_tdis(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -2497,11 +2615,10 @@ int reply_tdis(connection_struct *conn, return outsize; } - - /**************************************************************************** - reply to a echo + Reply to a echo. ****************************************************************************/ + int reply_echo(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -2539,10 +2656,10 @@ int reply_echo(connection_struct *conn, return -1; } - /**************************************************************************** - reply to a printopen + Reply to a printopen. ****************************************************************************/ + int reply_printopen(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -2573,9 +2690,8 @@ int reply_printopen(connection_struct *conn, return(outsize); } - /**************************************************************************** - reply to a printclose + Reply to a printclose. ****************************************************************************/ int reply_printclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) @@ -2607,10 +2723,10 @@ int reply_printclose(connection_struct *conn, return(outsize); } - /**************************************************************************** - reply to a printqueue + Reply to a printqueue. ****************************************************************************/ + int reply_printqueue(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { @@ -2678,10 +2794,10 @@ int reply_printqueue(connection_struct *conn, return(outsize); } - /**************************************************************************** - reply to a printwrite + Reply to a printwrite. ****************************************************************************/ + int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { int numtowrite; @@ -2712,11 +2828,11 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_ return(outsize); } - /**************************************************************************** The guts of the mkdir command, split out so it may be called by the NT SMB code. ****************************************************************************/ + NTSTATUS mkdir_internal(connection_struct *conn, pstring directory) { BOOL bad_path = False; @@ -2939,10 +3055,10 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return(outsize); } - /******************************************************************* -resolve wildcards in a filename rename + Resolve wildcards in a filename rename. ********************************************************************/ + static BOOL resolve_wildcards(char *name1,char *name2) { fstring root1,root2; @@ -3378,8 +3494,9 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, } /**************************************************************************** - reply to a file copy. - ****************************************************************************/ + Reply to a file copy. +****************************************************************************/ + int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { int outsize = 0; @@ -3542,8 +3659,9 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, } /**************************************************************************** - reply to a setdir + Reply to a setdir. ****************************************************************************/ + int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { int snum; @@ -3637,6 +3755,7 @@ SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format /**************************************************************************** Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-). ****************************************************************************/ + static uint32 map_lock_offset(uint32 high, uint32 low) { unsigned int i; @@ -3716,7 +3835,7 @@ SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_forma } /**************************************************************************** - reply to a lockingX request + Reply to a lockingX request. ****************************************************************************/ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) @@ -3827,7 +3946,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); /* Setup the timeout in seconds. */ - lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000); + lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000); /* Now do any requested locks */ data += ((large_file_format ? 20 : 10)*num_ulocks); @@ -3855,7 +3974,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); status = do_lock_spin(fsp,conn,lock_pid, count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK)); if (NT_STATUS_V(status)) { - if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) { + if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) { /* * A blocking lock was requested. Package up * this smb into a queued request and push it diff --git a/source3/smbd/sec_ctx.c b/source3/smbd/sec_ctx.c index bdcdce6e14..411ece5249 100644 --- a/source3/smbd/sec_ctx.c +++ b/source3/smbd/sec_ctx.c @@ -287,17 +287,8 @@ void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN DEBUG(3, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", (unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx)); - if (ngroups) { - int i; - - DEBUG(3, ("%d user groups: \n", ngroups)); - for (i = 0; i < ngroups; i++) { - DEBUGADD(3, ("%u ", (unsigned int)groups[i])); - } - - DEBUG(3, ("\n")); - } - + debug_nt_user_token(DBGC_CLASS, 5, token); + debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups); gain_root(); diff --git a/source3/smbd/server.c b/source3/smbd/server.c index b2b905cec3..39d5e3bcd3 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -33,6 +33,8 @@ int last_message = -1; #define LAST_MESSAGE() smb_fn_name(last_message) extern pstring user_socket_options; +extern SIG_ATOMIC_T got_sig_term; +extern SIG_ATOMIC_T reload_after_sighup; #ifdef WITH_DFS extern int dcelogin_atmost_once; @@ -61,8 +63,6 @@ static void smbd_set_server_fd(int fd) Terminate signal. ****************************************************************************/ -SIG_ATOMIC_T got_sig_term = 0; - static void sig_term(void) { got_sig_term = 1; @@ -73,8 +73,6 @@ static void sig_term(void) Catch a sighup. ****************************************************************************/ -SIG_ATOMIC_T reload_after_sighup = 0; - static void sig_hup(int sig) { reload_after_sighup = 1; @@ -542,6 +540,8 @@ void exit_server(char *reason) invalidate_all_vuids(); + print_notify_send_messages(); + /* delete our entry in the connections database. */ yield_connection(NULL,""); @@ -860,7 +860,7 @@ static void usage(char *pname) register_dmalloc_msgs(); /* Setup the main smbd so that we can get messages. */ - claim_connection(NULL,"",0,True); + claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD); /* DO NOT ENABLE THIS TILL YOU COPE WITH KILLING THESE TASKS AND INETD diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 6f83a2d3b7..a8a590da80 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -305,6 +305,7 @@ static void set_admin_user(connection_struct *conn) #endif ) { conn->admin_user = True; + conn->force_user = True; /* Admin users are effectivly 'forced' */ DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user)); } else { conn->admin_user = False; @@ -329,7 +330,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, { struct passwd *pass = NULL; BOOL guest = False; - BOOL force = False; connection_struct *conn; struct stat st; fstring user; @@ -349,7 +349,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, if (lp_guest_only(snum)) { const char *guestname = lp_guestaccount(); guest = True; - force = True; pass = getpwnam_alloc(guestname); if (!pass) { DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname)); @@ -397,7 +396,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, return NULL; } pass = Get_Pwnam(user); - conn->force_user = force; + conn->force_user = True; conn->uid = pass->pw_uid; conn->gid = pass->pw_gid; string_set(&conn->user, pass->pw_name); @@ -434,7 +433,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, /* * If force user is true, then store the - * given userid and also the primary groupid + * given userid and also the groups * of the user we're forcing. */ @@ -492,6 +491,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, gid = nametogid(gname); if (gid != (gid_t)-1) { + /* * If the user has been forced and the forced group starts * with a '+', then we only set the group to be the forced @@ -507,6 +507,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->gid = gid; DEBUG(3,("Forced group %s\n",gname)); } + conn->force_group = True; } else { DEBUG(1,("Couldn't find group %s\n",gname)); conn_free(conn); @@ -524,23 +525,27 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum))); } - /* groups stuff added by ih */ - conn->ngroups = 0; - conn->groups = NULL; - - /* Find all the groups this uid is in and - store them. Used by change_to_user() */ - initialise_groups(conn->user, conn->uid, conn->gid); - get_current_groups(conn->gid, &conn->ngroups,&conn->groups); + if (conn->force_user || conn->force_group) { + + /* groups stuff added by ih */ + conn->ngroups = 0; + conn->groups = NULL; + + /* Find all the groups this uid is in and + store them. Used by change_to_user() */ + initialise_groups(conn->user, conn->uid, conn->gid); + get_current_groups(conn->gid, &conn->ngroups,&conn->groups); - conn->nt_user_token = create_nt_token(conn->uid, conn->gid, - conn->ngroups, conn->groups, - guest, NULL); + conn->nt_user_token = create_nt_token(conn->uid, conn->gid, + conn->ngroups, conn->groups, + guest); + } /* * New code to check if there's a share security descripter * added from NT server manager. This is done after the * smb.conf checks are done as we need a uid and token. JRA. + * */ { @@ -573,7 +578,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, if (!claim_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)), - False)) { + False,0)) { DEBUG(1,("too many connections - rejected\n")); conn_free(conn); *status = NT_STATUS_INSUFFICIENT_RESOURCES; @@ -803,7 +808,7 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1) && strequal(service_in, lp_servicename(vuser->homes_snum))) { DATA_BLOB no_pw = data_blob(NULL, 0); - DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service)); + DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in)); return make_connection_snum(vuser->homes_snum, vuser, no_pw, dev, status); diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 77f93812dd..b9af720008 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -160,12 +160,12 @@ static int reply_spnego_kerberos(connection_struct *conn, ads_destroy(&ads); /* the password is good - let them in */ - pw = smb_getpwnam(user,False); + pw = Get_Pwnam(user); if (!pw && !strstr(user, lp_winbind_separator())) { char *user2; /* try it with a winbind domain prefix */ asprintf(&user2, "%s%s%s", lp_workgroup(), lp_winbind_separator(), user); - pw = smb_getpwnam(user2,False); + pw = Get_Pwnam(user2); if (pw) { free(user); user = user2; @@ -177,9 +177,9 @@ static int reply_spnego_kerberos(connection_struct *conn, return ERROR_NT(NT_STATUS_NO_SUCH_USER); } - if (!make_server_info_pw(&server_info,pw)) { + if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) { DEBUG(1,("make_server_info_from_pw failed!\n")); - return ERROR_NT(NT_STATUS_NO_MEMORY); + return ERROR_NT(ret); } sess_vuid = register_vuid(server_info, user); @@ -294,8 +294,6 @@ static int reply_spnego_negotiate(connection_struct *conn, return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - DEBUG(3,("Got neg_flags=0x%08x\n", neg_flags)); - debug_ntlmssp_flags(neg_flags); if (ntlmssp_auth_context) { @@ -324,12 +322,12 @@ static int reply_spnego_negotiate(connection_struct *conn, "U", lp_workgroup()); - fstrcpy(dnsdomname, lp_realm()); + fstrcpy(dnsdomname, (SEC_ADS == lp_security())?lp_realm():""); strlower(dnsdomname); fstrcpy(dnsname, global_myname); fstrcat(dnsname, "."); - fstrcat(dnsname, lp_realm()); + fstrcat(dnsname, dnsdomname); strlower(dnsname); msrpc_gen(&struct_blob, "aaaaa", @@ -441,14 +439,14 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, auth_flags |= AUTH_FLAG_NTLM_RESP; } else if (nthash.length > 24) { auth_flags |= AUTH_FLAG_NTLMv2_RESP; - } + }; + + nt_status = make_user_info_map(&user_info, user, workgroup, machine, + lmhash, nthash, plaintext_password, + auth_flags, True); - if (!make_user_info_map(&user_info, - user, workgroup, - machine, - lmhash, nthash, - plaintext_password, - auth_flags, True)) { + /* it looks a bit weird, but this function returns int type... */ + if (!NT_STATUS_IS_OK(nt_status)) { return ERROR_NT(NT_STATUS_NO_MEMORY); } @@ -623,7 +621,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, NTSTATUS nt_status; BOOL doencrypt = global_encrypted_passwords_negotiated; - + START_PROFILE(SMBsesssetupX); ZERO_STRUCT(lm_resp); @@ -736,7 +734,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, /* don't allow for weird usernames or domains */ alpha_strcpy(user, user, ". _-$", sizeof(user)); - alpha_strcpy(domain, domain, ". _-", sizeof(domain)); + alpha_strcpy(domain, domain, ". _-@", sizeof(domain)); if (strstr(user, "..") || strstr(domain,"..")) { return ERROR_NT(NT_STATUS_LOGON_FAILURE); } @@ -778,11 +776,9 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, nt_status = check_guest_password(&server_info); } else if (doencrypt) { - if (!make_user_info_for_reply_enc(&user_info, - user, domain, - lm_resp, nt_resp)) { - nt_status = NT_STATUS_NO_MEMORY; - } else { + nt_status = make_user_info_for_reply_enc(&user_info, user, domain, + lm_resp, nt_resp); + if (NT_STATUS_IS_OK(nt_status)) { nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, user_info, &server_info); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index a66c029286..de65cda2d0 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -30,19 +30,26 @@ extern int global_oplock_break; extern uint32 global_client_caps; extern pstring global_myname; +#define get_file_size(sbuf) (sbuf.st_size) + /* given a stat buffer return the allocated size on disk, taking into account sparse files */ -SMB_OFF_T get_allocation_size(SMB_STRUCT_STAT *sbuf) +SMB_OFF_T get_allocation_size(files_struct *fsp, SMB_STRUCT_STAT *sbuf) { SMB_OFF_T ret; +#if defined(HAVE_STAT_ST_BLKSIZE) && defined(HAVE_STAT_ST_BLOCKS) ret = sbuf->st_blksize * (SMB_OFF_T)sbuf->st_blocks; - ret = SMB_ROUNDUP_ALLOCATION(ret); +#elif defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) + ret = (SMB_OFF_T)STAT_ST_BLOCKSIZE * (SMB_OFF_T)sbuf->st_blocks; +#else + ret = get_file_size(*sbuf); +#endif + if (!ret && fsp && fsp->initial_allocation_size) + ret = fsp->initial_allocation_size; + ret = SMB_ROUNDUP(ret,SMB_ROUNDUP_ALLOCATION_SIZE); return ret; } -#define get_file_size(sbuf) (sbuf.st_size) - - /**************************************************************************** Send the required number of replies back. We assume all fields other than the data fields are @@ -579,7 +586,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, } file_size = get_file_size(sbuf); - allocation_size = get_allocation_size(&sbuf); + allocation_size = get_allocation_size(NULL,&sbuf); mdate = sbuf.st_mtime; adate = sbuf.st_atime; cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); @@ -660,6 +667,11 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, SIVAL(p,0,nt_extmode); p += 4; q = p; p += 4; SIVAL(p,0,0); p += 4; + /* Clear the short name buffer. This is + * IMPORTANT as not doing so will trigger + * a Win2k client bug. JRA. + */ + memset(p,'\0',26); if (!was_8_3) { pstring mangled_name; pstrcpy(mangled_name, fname); @@ -751,12 +763,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, SOFF_T(p,0,get_file_size(sbuf)); /* File size 64 Bit */ p+= 8; -#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) - SOFF_T(p,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */ -#else - /* Can't get the value - fake it using size. */ - SOFF_T(p,0,get_file_size(sbuf)); /* Number of bytes used on disk - 64 Bit */ -#endif + SOFF_T(p,0,get_allocation_size(NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */ p+= 8; put_long_date(p,sbuf.st_ctime); /* Creation Time 64 Bit */ @@ -899,7 +906,11 @@ close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n", p = strrchr_m(directory,'/'); if(p == NULL) { - pstrcpy(mask,directory); + /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */ + if((directory[0] == '.') && (directory[1] == '\0')) + pstrcpy(mask,"*"); + else + pstrcpy(mask,directory); pstrcpy(directory,"./"); } else { pstrcpy(mask,p+1); @@ -1554,12 +1565,16 @@ static int call_trans2qfilepathinfo(connection_struct *conn, BOOL delete_pending = False; int len; time_t c_time; + files_struct *fsp = NULL; if (!params) return ERROR_NT(NT_STATUS_INVALID_PARAMETER); if (tran_call == TRANSACT2_QFILEINFO) { - files_struct *fsp = file_fsp(params,0); + if (total_params < 4) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + fsp = file_fsp(params,0); info_level = SVAL(params,2); DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); @@ -1657,7 +1672,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, mode = dos_mode(conn,fname,&sbuf); fullpathname = fname; file_size = get_file_size(sbuf); - allocation_size = get_allocation_size(&sbuf); + allocation_size = get_allocation_size(fsp,&sbuf); if (mode & aDIR) file_size = 0; @@ -1842,7 +1857,12 @@ static int call_trans2qfilepathinfo(connection_struct *conn, break; case SMB_FILE_INTERNAL_INFORMATION: - /* This should be an index number - looks like dev/ino to me :-) */ + /* This should be an index number - looks like + dev/ino to me :-) + + I think this causes us to fail the IFSKIT + BasicFileInformationTest. -tpot */ + SIVAL(pdata,0,sbuf.st_dev); SIVAL(pdata,4,sbuf.st_ino); data_size = 8; @@ -1972,12 +1992,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, SOFF_T(pdata,0,get_file_size(sbuf)); /* File size 64 Bit */ pdata += 8; -#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) - SOFF_T(pdata,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */ -#else - /* Can't get the value - fake it using size. */ - SOFF_T(pdata,0,get_file_size(sbuf)); /* Number of bytes used on disk - 64 Bit */ -#endif + SOFF_T(pdata,0,get_allocation_size(fsp,&sbuf)); /* Number of bytes used on disk - 64 Bit */ pdata += 8; put_long_date(pdata,sbuf.st_ctime); /* Creation Time 64 Bit */ @@ -2334,7 +2349,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, switch (info_level) { case SMB_INFO_STANDARD: - case SMB_INFO_QUERY_EA_SIZE: { if (total_data < l1_cbFile+4) return(ERROR_DOS(ERRDOS,ERRinvalidparam)); @@ -2351,6 +2365,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, break; } + case SMB_INFO_SET_EA: + return(ERROR_DOS(ERRDOS,ERReasnotsupported)); + /* XXXX um, i don't think this is right. it's also not in the cifs6.txt spec. */ @@ -2412,11 +2429,12 @@ static int call_trans2setfilepathinfo(connection_struct *conn, case SMB_SET_FILE_ALLOCATION_INFO: { int ret = -1; - SMB_OFF_T allocation_size = IVAL(pdata,0); + SMB_OFF_T allocation_size; if (total_data < 8) return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + allocation_size = IVAL(pdata,0); #ifdef LARGE_SMB_OFF_T allocation_size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); #else /* LARGE_SMB_OFF_T */ @@ -2426,6 +2444,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n", fname, (double)allocation_size )); + if (allocation_size) + allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE); + if(allocation_size != get_file_size(sbuf)) { SMB_STRUCT_STAT new_sbuf; diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index c0bacf8f91..2bda26aa51 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -59,18 +59,26 @@ BOOL change_to_guest(void) static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum) { int i; - for (i=0;i<conn->uid_cache.entries;i++) - if (conn->uid_cache.list[i] == vuser->uid) + for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) + if (conn->vuid_cache.list[i] == vuser->vuid) return(True); + if ((conn->force_user || conn->force_group) + && (conn->vuid != vuser->vuid)) { + return False; + } + if (!user_ok(vuser->user.unix_name,snum)) return(False); - i = conn->uid_cache.entries % UID_CACHE_SIZE; - conn->uid_cache.list[i] = vuser->uid; + if (!share_access_check(conn, snum, vuser, conn->read_only ? FILE_READ_DATA : FILE_WRITE_DATA)) { + return False; + } + + i = conn->vuid_cache.entries % VUID_CACHE_SIZE; + conn->vuid_cache.list[i] = vuser->vuid; - if (conn->uid_cache.entries < UID_CACHE_SIZE) - conn->uid_cache.entries++; + conn->vuid_cache.entries++; return(True); } @@ -115,27 +123,21 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) snum = SNUM(conn); - if((vuser != NULL) && !check_user_ok(conn, vuser, snum)) - return False; - - if (conn->force_user || - conn->admin_user || - (lp_security() == SEC_SHARE)) { + if (conn->force_user) /* security = share sets this too */ { uid = conn->uid; gid = conn->gid; current_user.groups = conn->groups; current_user.ngroups = conn->ngroups; token = conn->nt_user_token; - } else { - if (!vuser) { - DEBUG(2,("change_to_user: Invalid vuid used %d\n",vuid)); - return(False); - } + } else if ((vuser) && check_user_ok(conn, vuser, snum)) { uid = vuser->uid; gid = vuser->gid; current_user.ngroups = vuser->n_groups; current_user.groups = vuser->groups; token = vuser->nt_user_token; + } else { + DEBUG(2,("change_to_user: Invalid vuid used %d or vuid not permitted access to share.\n",vuid)); + return False; } /* @@ -175,7 +177,11 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) if (vuser && vuser->guest) is_guest = True; - token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest, NULL); + token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest); + if (!token) { + DEBUG(1, ("change_to_user: create_nt_token failed!\n")); + return False; + } must_free_token = True; } diff --git a/source3/smbd/vfs-wrap.c b/source3/smbd/vfs-wrap.c index 394086dc07..bae304096c 100644 --- a/source3/smbd/vfs-wrap.c +++ b/source3/smbd/vfs-wrap.c @@ -20,6 +20,10 @@ #include "includes.h" +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + + /* Check for NULL pointer parameters in vfswrap_* functions */ /* We don't want to have NULL function pointers lying around. Someone @@ -188,6 +192,17 @@ SMB_OFF_T vfswrap_lseek(files_struct *fsp, int filedes, SMB_OFF_T offset, int wh return result; } +ssize_t vfswrap_sendfile(int tofd, struct files_struct *fsp, int fromfd, const DATA_BLOB *hdr, + SMB_OFF_T offset, size_t n) +{ + ssize_t result; + + START_PROFILE_BYTES(syscall_sendfile, n); + result = sys_sendfile(tofd, fromfd, hdr, offset, n); + END_PROFILE(syscall_sendfile); + return result; +} + int vfswrap_rename(connection_struct *conn, const char *old, const char *new) { int result; diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index a2291eba08..a0a7b920b8 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -24,6 +24,10 @@ #include "includes.h" +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + + /* Some structures to help us initialise the vfs operations table */ struct vfs_syminfo { @@ -64,6 +68,7 @@ static struct vfs_ops default_vfs_ops = { vfswrap_read, vfswrap_write, vfswrap_lseek, + vfswrap_sendfile, vfswrap_rename, vfswrap_fsync, vfswrap_stat, @@ -138,7 +143,7 @@ static void vfs_init_default(connection_struct *conn) initialise custom vfs hooks ****************************************************************************/ -static BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object) +BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object) { int vfs_version = -1; vfs_op_tuple *ops, *(*init_fptr)(int *, const struct vfs_ops *, struct smb_vfs_handle_struct *); @@ -259,6 +264,7 @@ BOOL smbd_vfs_init(connection_struct *conn) /******************************************************************* Create vfs_ops reflecting current vfs_opaque_ops *******************************************************************/ + struct vfs_ops *smb_vfs_get_opaque_ops(void) { int i; @@ -297,6 +303,7 @@ BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_ /******************************************************************* vfs getwd wrapper ********************************************************************/ + static char *vfs_getwd(connection_struct *conn, char *path) { return conn->vfs_ops.getwd(conn,path); |