diff options
author | Gerald Carter <jerry@samba.org> | 2003-07-16 05:34:56 +0000 |
---|---|---|
committer | Gerald Carter <jerry@samba.org> | 2003-07-16 05:34:56 +0000 |
commit | 4a090ba06a54f5da179ac02bb307cc03d08831bf (patch) | |
tree | ed652ef36be7f16682c358816334f969a22f1c27 /source3/smbd | |
parent | 95fe82670032a3a43571b46d7bbf2c26bc8cdcd9 (diff) | |
download | samba-4a090ba06a54f5da179ac02bb307cc03d08831bf.tar.gz samba-4a090ba06a54f5da179ac02bb307cc03d08831bf.tar.bz2 samba-4a090ba06a54f5da179ac02bb307cc03d08831bf.zip |
trying to get HEAD building again. If you want the code
prior to this merge, checkout HEAD_PRE_3_0_0_BETA_3_MERGE
(This used to be commit adb98e7b7cd0f025b52c570e4034eebf4047b1ad)
Diffstat (limited to 'source3/smbd')
32 files changed, 2952 insertions, 1344 deletions
diff --git a/source3/smbd/.cvsignore b/source3/smbd/.cvsignore index 5f2a5c4cf7..d2b1fd5b2e 100644 --- a/source3/smbd/.cvsignore +++ b/source3/smbd/.cvsignore @@ -1,2 +1,3 @@ *.po *.po32 +build_options.c diff --git a/source3/smbd/change_trust_pw.c b/source3/smbd/change_trust_pw.c index 8aff96d0d6..4993e285ca 100644 --- a/source3/smbd/change_trust_pw.c +++ b/source3/smbd/change_trust_pw.c @@ -43,7 +43,7 @@ NTSTATUS change_trust_account_password( const char *domain, const char *remote_m goto failed; } - if ( !lookup_dc_name(global_myname(), domain, &pdc_ip, dc_name) ) + if ( !name_status_find( domain, 0x1b, 0x20, pdc_ip, dc_name) ) goto failed; } /* supoport old deprecated "smbpasswd -j DOMAIN -r MACHINE" behavior */ diff --git a/source3/smbd/close.c b/source3/smbd/close.c index 5cca85500f..1be13270ba 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -185,7 +185,7 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) if (normal_close && delete_on_close) { DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n", fsp->fsp_name)); - if(fsp->conn->vfs_ops.unlink(conn,fsp->fsp_name) != 0) { + if(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) { /* * This call can potentially fail as another smbd may have * had the file open with delete on close set and deleted diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c index b6c7aa1076..eb2d2bbcbf 100644 --- a/source3/smbd/conn.c +++ b/source3/smbd/conn.c @@ -93,6 +93,7 @@ thinking the server is still available. ****************************************************************************/ connection_struct *conn_new(void) { + TALLOC_CTX *mem_ctx; connection_struct *conn; int i; @@ -103,10 +104,16 @@ connection_struct *conn_new(void) return NULL; } - conn = (connection_struct *)malloc(sizeof(*conn)); - if (!conn) return NULL; + if ((mem_ctx=talloc_init("connection_struct"))==NULL) { + DEBUG(0,("talloc_init(connection_struct) failed!\n")); + return NULL; + } - ZERO_STRUCTP(conn); + if ((conn=(connection_struct *)talloc_zero(mem_ctx, sizeof(*conn)))==NULL) { + DEBUG(0,("talloc_zero() failed!\n")); + return NULL; + } + conn->mem_ctx = mem_ctx; conn->cnum = i; bitmap_set(bmap, i); @@ -195,27 +202,16 @@ void conn_clear_vuid_cache(uint16 vuid) void conn_free(connection_struct *conn) { - smb_vfs_handle_struct *handle, *thandle; - void (*done_fptr)(connection_struct *the_conn); + vfs_handle_struct *handle = NULL, *thandle = NULL; + TALLOC_CTX *mem_ctx = NULL; /* Free vfs_connection_struct */ - handle = conn->vfs_private; + handle = conn->vfs_handles; while(handle) { - /* Only call dlclose for the old modules */ - if (handle->handle) { - /* Close dlopen() handle */ - done_fptr = (void (*)(connection_struct *))sys_dlsym(handle->handle, "vfs_done"); - - if (done_fptr == NULL) { - DEBUG(3, ("No vfs_done() symbol found in module with handle %p, ignoring\n", handle->handle)); - } else { - done_fptr(conn); - } - sys_dlclose(handle->handle); - } - DLIST_REMOVE(conn->vfs_private, handle); + DLIST_REMOVE(conn->vfs_handles, handle); thandle = handle->next; - SAFE_FREE(handle); + if (handle->free_data) + handle->free_data(&handle->data); handle = thandle; } @@ -238,8 +234,9 @@ void conn_free(connection_struct *conn) bitmap_clear(bmap, conn->cnum); num_open--; + mem_ctx = conn->mem_ctx; ZERO_STRUCTP(conn); - SAFE_FREE(conn); + talloc_destroy(mem_ctx); } diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c index c2718d4d70..5bb76eb3bd 100644 --- a/source3/smbd/connection.c +++ b/source3/smbd/connection.c @@ -38,10 +38,17 @@ TDB_CONTEXT *conn_tdb_ctx(void) static void make_conn_key(connection_struct *conn, const char *name, TDB_DATA *pkbuf, struct connections_key *pkey) { ZERO_STRUCTP(pkey); - ZERO_STRUCTP(pkbuf); pkey->pid = sys_getpid(); pkey->cnum = conn?conn->cnum:-1; fstrcpy(pkey->name, name); +#ifdef DEVELOPER + /* valgrind fixer... */ + { + size_t sl = strlen(pkey->name); + if (sizeof(fstring)-sl) + memset(&pkey->name[sl], '\0', sizeof(fstring)-sl); + } +#endif pkbuf->dptr = (char *)pkey; pkbuf->dsize = sizeof(*pkey); diff --git a/source3/smbd/dfree.c b/source3/smbd/dfree.c index 71b3f2bf77..f93cdf3791 100644 --- a/source3/smbd/dfree.c +++ b/source3/smbd/dfree.c @@ -80,7 +80,7 @@ static SMB_BIG_UINT disk_free(const char *path, BOOL small_query, dfree_command = lp_dfree_command(); if (dfree_command && *dfree_command) { - char *p; + const char *p; char **lines; pstring syscmd; @@ -93,15 +93,15 @@ static SMB_BIG_UINT disk_free(const char *path, BOOL small_query, DEBUG (3, ("Read input from dfree, \"%s\"\n", line)); - *dsize = (SMB_BIG_UINT)strtoul(line, &p, 10); - while (p && *p & isspace(*p)) + *dsize = STR_TO_SMB_BIG_UINT(line, &p); + while (p && *p && isspace(*p)) p++; if (p && *p) - *dfree = (SMB_BIG_UINT)strtoul(p, &p, 10); - while (p && *p & isspace(*p)) + *dfree = STR_TO_SMB_BIG_UINT(p, &p); + while (p && *p && isspace(*p)) p++; if (p && *p) - *bsize = (SMB_BIG_UINT)strtoul(p, NULL, 10); + *bsize = STR_TO_SMB_BIG_UINT(p, NULL); else *bsize = 1024; file_lines_free(lines); diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 6cf56fd373..94b605ee8f 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -643,7 +643,7 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname pstrcpy(pathreal,path); pstrcat(path,fname); pstrcat(pathreal,dname); - if (conn->vfs_ops.stat(conn, pathreal, &sbuf) != 0) { + if (SMB_VFS_STAT(conn, pathreal, &sbuf) != 0) { DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) )); continue; } @@ -700,7 +700,7 @@ static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_S return True; /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0)) + if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) return False; /* Pseudo-open the file (note - no fd's created). */ @@ -715,7 +715,8 @@ static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_S return False; /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ - sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); + sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd, + (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd); close_file(fsp, True); /* No access if SD get failed. */ @@ -753,7 +754,7 @@ static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_ return True; /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0)) + if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) return False; /* Pseudo-open the file (note - no fd's created). */ @@ -768,7 +769,8 @@ static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_ return False; /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ - sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); + sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd, + (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd); close_file(fsp, False); /* No access if SD get failed. */ @@ -794,7 +796,7 @@ static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT return True; /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (vfs_stat(conn, name, pst) != 0)) + if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) return True; if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode)) @@ -811,7 +813,7 @@ void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto) { Dir *dirp; const char *n; - DIR *p = conn->vfs_ops.opendir(conn,name); + DIR *p = SMB_VFS_OPENDIR(conn,name); int used=0; if (!p) @@ -819,7 +821,7 @@ void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto) dirp = (Dir *)malloc(sizeof(Dir)); if (!dirp) { DEBUG(0,("Out of memory in OpenDir\n")); - conn->vfs_ops.closedir(conn,p); + SMB_VFS_CLOSEDIR(conn,p); return(NULL); } dirp->pos = dirp->numentries = dirp->mallocsize = 0; @@ -912,7 +914,7 @@ void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto) dirp->numentries++; } - conn->vfs_ops.closedir(conn,p); + SMB_VFS_CLOSEDIR(conn,p); return((void *)dirp); } diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index 6c21dc04d0..aaee41b546 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -56,7 +56,7 @@ mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname) dname = parent_dirname(fname); DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname)); - if (vfs_stat(conn,dname,&sbuf) != 0) { + if (SMB_VFS_STAT(conn,dname,&sbuf) != 0) { DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno))); return(0); /* *** shouldn't happen! *** */ } @@ -191,7 +191,7 @@ int file_chmod(connection_struct *conn,char *fname, uint32 dosmode,SMB_STRUCT_ST if (!st) { st = &st1; - if (vfs_stat(conn,fname,st)) + if (SMB_VFS_STAT(conn,fname,st)) return(-1); } @@ -235,7 +235,7 @@ int file_chmod(connection_struct *conn,char *fname, uint32 dosmode,SMB_STRUCT_ST unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); } - if ((ret = vfs_chmod(conn,fname,unixmode)) == 0) + if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) return 0; if((errno != EPERM) && (errno != EACCES)) @@ -262,7 +262,7 @@ int file_chmod(connection_struct *conn,char *fname, uint32 dosmode,SMB_STRUCT_ST if (!fsp) return -1; become_root(); - ret = conn->vfs_ops.fchmod(fsp, fsp->fd, unixmode); + ret = SMB_VFS_FCHMOD(fsp, fsp->fd, unixmode); unbecome_root(); close_file_fchmod(fsp); } @@ -283,7 +283,7 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times) errno = 0; - if(conn->vfs_ops.utime(conn,fname, times) == 0) + if(SMB_VFS_UTIME(conn,fname, times) == 0) return 0; if((errno != EPERM) && (errno != EACCES)) @@ -298,7 +298,7 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times) (as DOS does). */ - if(vfs_stat(conn,fname,&sb) != 0) + if(SMB_VFS_STAT(conn,fname,&sb) != 0) return -1; /* Check if we have write access. */ @@ -311,7 +311,7 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times) current_user.ngroups,current_user.groups)))) { /* We are allowed to become root and change the filetime. */ become_root(); - ret = conn->vfs_ops.utime(conn,fname, times); + ret = SMB_VFS_UTIME(conn,fname, times); unbecome_root(); } } diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index b612b1a451..6be5f6af7d 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -32,7 +32,7 @@ static SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos) { SMB_OFF_T seek_ret; - seek_ret = fsp->conn->vfs_ops.lseek(fsp,fsp->fd,pos,SEEK_SET); + seek_ret = SMB_VFS_LSEEK(fsp,fsp->fd,pos,SEEK_SET); if(seek_ret == -1) { DEBUG(0,("seek_file: (%s) sys_lseek failed. Error was %s\n", @@ -101,7 +101,7 @@ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) #ifdef DMF_FIX int numretries = 3; tryagain: - readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n); + readret = SMB_VFS_READ(fsp,fsp->fd,data,n); if (readret == -1) { if ((errno == EAGAIN) && numretries) { DEBUG(3,("read_file EAGAIN retry in 10 seconds\n")); @@ -112,7 +112,7 @@ tryagain: return -1; } #else /* NO DMF fix. */ - readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n); + readret = SMB_VFS_READ(fsp,fsp->fd,data,n); if (readret == -1) return -1; #endif @@ -181,7 +181,7 @@ ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n) SMB_STRUCT_STAT st; fsp->modified = True; - if (fsp->conn->vfs_ops.fstat(fsp,fsp->fd,&st) == 0) { + if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0) { int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); fsp->size = (SMB_BIG_UINT)st.st_size; if (MAP_ARCHIVE(fsp->conn) && !IS_DOS_ARCHIVE(dosmode)) @@ -760,7 +760,7 @@ void sync_file(connection_struct *conn, files_struct *fsp) { if(lp_strict_sync(SNUM(conn)) && fsp->fd != -1) { flush_write_cache(fsp, SYNC_FLUSH); - conn->vfs_ops.fsync(fsp,fsp->fd); + SMB_VFS_FSYNC(fsp,fsp->fd); } } @@ -772,7 +772,7 @@ void sync_file(connection_struct *conn, files_struct *fsp) int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst) { if (fsp->fd == -1) - return vfs_stat(fsp->conn, fsp->fsp_name, pst); + return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst); else - return vfs_fstat(fsp,fsp->fd, pst); + return SMB_VFS_FSTAT(fsp,fsp->fd, pst); } diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index b9e33e8f93..ad107f9c3e 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -178,7 +178,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * stat the name - if it exists then we are all done! */ - if (vfs_stat(conn,name,&st) == 0) { + if (SMB_VFS_STAT(conn,name,&st) == 0) { stat_cache_add(orig_path, name); DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); *pst = st; @@ -234,7 +234,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * Check if the name exists up to this point. */ - if (vfs_stat(conn,name, &st) == 0) { + if (SMB_VFS_STAT(conn,name, &st) == 0) { /* * It exists. it must either be a directory or this must be * the last part of the path for it to be OK. @@ -342,7 +342,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * JRA. */ - if (vfs_stat(conn,name, &st) == 0) { + if (SMB_VFS_STAT(conn,name, &st) == 0) { *pst = st; } else { ZERO_STRUCT(st); @@ -418,7 +418,7 @@ BOOL check_name(pstring name,connection_struct *conn) #ifdef S_ISLNK if (!lp_symlinks(SNUM(conn))) { SMB_STRUCT_STAT statbuf; - if ( (conn->vfs_ops.lstat(conn,name,&statbuf) != -1) && + if ( (SMB_VFS_LSTAT(conn,name,&statbuf) != -1) && (S_ISLNK(statbuf.st_mode)) ) { DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name)); ret=0; diff --git a/source3/smbd/files.c b/source3/smbd/files.c index b9b27ad5ff..f0fd6b7a73 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -346,6 +346,10 @@ void file_free(files_struct *fsp) string_free(&fsp->fsp_name); + if (fsp->fake_file_handle) { + destroy_fake_file_handle(&fsp->fake_file_handle); + } + bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET); files_used--; diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index 98857c6d32..04d6a9a8a8 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -1649,7 +1649,7 @@ static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,c return False; /* get list of domain groups SID_DOMAIN_GRP=2 */ - if(!pdb_enum_group_mapping(SID_NAME_DOM_GRP , &group_list, &num_entries, False, False)) { + if(!pdb_enum_group_mapping(SID_NAME_DOM_GRP , &group_list, &num_entries, False)) { DEBUG(3,("api_RNetGroupEnum:failed to get group list")); return False; } @@ -2367,7 +2367,7 @@ static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */ pstrcpy(p2,local_machine); - strupper(p2); + strupper_m(p2); p2 = skip_string(p2,1); p += 4; @@ -2378,7 +2378,7 @@ static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */ pstrcpy(p2,lp_workgroup()); - strupper(p2); + strupper_m(p2); p2 = skip_string(p2,1); p += 4; @@ -2788,7 +2788,7 @@ static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param fstring mypath; fstrcpy(mypath,"\\\\"); fstrcat(mypath,local_machine); - strupper(mypath); + strupper_m(mypath); PACKS(&desc,"z",mypath); /* computer */ } PACKS(&desc,"z",lp_workgroup());/* domain */ @@ -3007,7 +3007,7 @@ static void fill_printdest_info(connection_struct *conn, int snum, int uLevel, char buf[100]; strncpy(buf,SERVICE(snum),sizeof(buf)-1); buf[sizeof(buf)-1] = 0; - strupper(buf); + strupper_m(buf); if (uLevel <= 1) { PACKS(desc,"B9",buf); /* szName */ if (uLevel == 1) { diff --git a/source3/smbd/mangle_hash.c b/source3/smbd/mangle_hash.c index e220d2f6d2..ac8e425fd3 100644 --- a/source3/smbd/mangle_hash.c +++ b/source3/smbd/mangle_hash.c @@ -217,7 +217,7 @@ static NTSTATUS is_valid_name(const smb_ucs2_t *fname, BOOL allow_wildcards) return NT_STATUS_UNSUCCESSFUL; ret = has_valid_chars(fname, allow_wildcards); - if (NT_STATUS_IS_ERR(ret)) + if (!NT_STATUS_IS_OK(ret)) return ret; str = strdup_w(fname); @@ -227,7 +227,8 @@ static NTSTATUS is_valid_name(const smb_ucs2_t *fname, BOOL allow_wildcards) SAFE_FREE(str); return NT_STATUS_UNSUCCESSFUL; } - if (p) *p = 0; + if (p) + *p = 0; strupper_w(str); p = &(str[1]); @@ -285,10 +286,10 @@ static NTSTATUS is_8_3_w(const smb_ucs2_t *fname, BOOL allow_wildcards) if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0) return NT_STATUS_OK; - if (NT_STATUS_IS_ERR(is_valid_name(fname, allow_wildcards))) + if (!NT_STATUS_IS_OK(is_valid_name(fname, allow_wildcards))) goto done; - if (NT_STATUS_IS_ERR(mangle_get_prefix(fname, &pref, &ext, allow_wildcards))) + if (!NT_STATUS_IS_OK(mangle_get_prefix(fname, &pref, &ext, allow_wildcards))) goto done; plen = strlen_w(pref); @@ -556,8 +557,8 @@ static void cache_mangled_name( char *mangled_name, char *raw_name ) /* Fill the new cache entry, and add it to the cache. */ s1 = (char *)(new_entry + 1); s2 = (char *)&(s1[mangled_len + 1]); - (void)StrnCpy( s1, mangled_name, mangled_len ); - (void)StrnCpy( s2, raw_name, raw_len ); + safe_strcpy( s1, mangled_name, mangled_len ); + safe_strcpy( s2, raw_name, raw_len ); ubi_cachePut( mangled_cache, i, new_entry, s1 ); } @@ -660,7 +661,7 @@ static void to_8_3(char *s) } else csum = str_checksum(s); - strupper( s ); + strupper_m( s ); if( p ) { if( p == s ) @@ -735,7 +736,7 @@ static void name_map(char *OutName, BOOL need83, BOOL cache83) return; } - if( !need83 && NT_STATUS_IS_ERR(is_valid_name(OutName_ucs2, False))) + if( !need83 && !NT_STATUS_IS_OK(is_valid_name(OutName_ucs2, False))) need83 = True; /* check if it's already in 8.3 format */ diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index 66cd835240..f452dd845b 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -100,8 +100,8 @@ static int reply_lanman1(char *inbuf, char *outbuf) SSVAL(outbuf,smb_vwv1,secword); /* Create a token value and add it to the outgoing packet. */ if (global_encrypted_passwords_negotiated) { - SSVAL(outbuf,smb_vwv11, 8); get_challenge(smb_buf(outbuf)); + SSVAL(outbuf,smb_vwv11, 8); } Protocol = PROTOCOL_LANMAN1; @@ -144,8 +144,8 @@ static int reply_lanman2(char *inbuf, char *outbuf) /* Create a token value and add it to the outgoing packet. */ if (global_encrypted_passwords_negotiated) { - SSVAL(outbuf,smb_vwv11, 8); get_challenge(smb_buf(outbuf)); + SSVAL(outbuf,smb_vwv11, 8); } Protocol = PROTOCOL_LANMAN2; @@ -182,7 +182,17 @@ static int negprot_spnego(char *p) ZERO_STRUCT(guid); safe_strcpy((char *)guid, global_myname(), sizeof(guid)-1); - strlower((char *)guid); + +#ifdef DEVELOPER + /* valgrind fixer... */ + { + size_t sl = strlen(guid); + if (sizeof(guid)-sl) + memset(&guid[sl], '\0', sizeof(guid)-sl); + } +#endif + + strlower_m((char *)guid); #if 0 /* strangely enough, NT does not sent the single OID NTLMSSP when diff --git a/source3/smbd/notify_hash.c b/source3/smbd/notify_hash.c index d8b35462ac..810e5079ba 100644 --- a/source3/smbd/notify_hash.c +++ b/source3/smbd/notify_hash.c @@ -48,7 +48,7 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, ZERO_STRUCTP(data); - if(vfs_stat(conn,path, &st) == -1) + if(SMB_VFS_STAT(conn,path, &st) == -1) return False; data->modify_time = st.st_mtime; @@ -100,7 +100,7 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, /* * Do the stat - but ignore errors. */ - vfs_stat(conn,full_name, &st); + SMB_VFS_STAT(conn,full_name, &st); /* * Always sum the times. diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 9f7fabb75e..c574d9d563 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1,7 +1,8 @@ /* Unix SMB/CIFS implementation. SMB NT transaction handling - Copyright (C) Jeremy Allison 1994-1998 + Copyright (C) Jeremy Allison 1994-1998 + Copyright (C) Stefan (metze) Metzmacher 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,6 +27,7 @@ extern int global_oplock_break; extern BOOL case_sensitive; extern BOOL case_preserve; extern BOOL short_case_preserve; +extern struct current_user current_user; static const char *known_nt_pipes[] = { "\\LANMAN", @@ -53,6 +55,24 @@ struct generic_mapping file_generic_mapping = { FILE_GENERIC_ALL }; +char *nttrans_realloc(char **ptr, size_t size) +{ + char *tptr = NULL; + if (ptr==NULL) + smb_panic("nttrans_realloc() called with NULL ptr\n"); + + tptr = Realloc_zero(*ptr, size); + if(tptr == NULL) { + *ptr = NULL; + return NULL; + } + + *ptr = tptr; + + return tptr; +} + + /**************************************************************************** Send the required number of replies back. We assume all fields other than the data fields are @@ -542,6 +562,7 @@ int reply_ntcreate_and_X(connection_struct *conn, { int result; pstring fname; + enum FAKE_FILE_TYPE fake_file_type = FAKE_FILE_TYPE_NONE; uint32 flags = IVAL(inbuf,smb_ntcreate_Flags); uint32 desired_access = IVAL(inbuf,smb_ntcreate_DesiredAccess); uint32 file_attributes = IVAL(inbuf,smb_ntcreate_FileAttributes); @@ -669,8 +690,25 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib */ if( strchr_m(fname, ':')) { - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + +#ifdef HAVE_SYS_QUOTAS + if ((fake_file_type=is_fake_file(fname))!=FAKE_FILE_TYPE_NONE) { + /* + * here we go! support for changing the disk quotas --metze + * + * we need to fake up to open this MAGIC QUOTA file + * and return a valid FID + * + * w2k close this file directly after openening + * xp also tries a QUERY_FILE_INFO on the file and then close it + */ + } else { +#endif + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); +#ifdef HAVE_SYS_QUOTAS + } +#endif } } @@ -746,12 +784,21 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib * before issuing an oplock break request to * our client. JRA. */ - fsp = open_file_shared1(conn,fname,&sbuf, + if (fake_file_type==FAKE_FILE_TYPE_NONE) { + fsp = open_file_shared1(conn,fname,&sbuf, desired_access, smb_open_mode, smb_ofun,unixmode, oplock_request, &rmode,&smb_action); - + } else { + /* to open a fake_file --metze */ + fsp = open_fake_file_shared1(fake_file_type,conn,fname,&sbuf, + desired_access, + smb_open_mode, + smb_ofun,unixmode, oplock_request, + &rmode,&smb_action); + } + if (!fsp) { /* We cheat here. There are two cases we * care about. One is a directory rename, @@ -917,13 +964,12 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib Reply to a NT_TRANSACT_CREATE call to open a pipe. ****************************************************************************/ -static int do_nt_transact_create_pipe( connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, char **ppsetup, char **ppparams, - char **ppdata) +static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **ppsetup, uint32 setup_count, + char **ppparams, uint32 parameter_count, + char **ppdata, uint32 data_count) { pstring fname; - int total_parameter_count = (int)IVAL(inbuf, smb_nt_TotalParameterCount); char *params = *ppparams; int ret; int pnum = -1; @@ -933,25 +979,21 @@ static int do_nt_transact_create_pipe( connection_struct *conn, * Ensure minimum number of parameters sent. */ - if(total_parameter_count < 54) { - DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)total_parameter_count)); + if(parameter_count < 54) { + DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)parameter_count)); return ERROR_DOS(ERRDOS,ERRnoaccess); } - srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE); + srvstr_pull(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE); if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) return ret; /* Realloc the size of parameters and data we will return */ - params = Realloc(*ppparams, 69); + params = nttrans_realloc(ppparams, 69); if(params == NULL) return ERROR_DOS(ERRDOS,ERRnomem); - *ppparams = params; - - memset((char *)params,'\0',69); - p = params; SCVAL(p,0,NO_OPLOCK_RETURN); @@ -1032,7 +1074,7 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu if (psd->off_dacl==0) security_info_sent &= ~DACL_SECURITY_INFORMATION; - ret = fsp->conn->vfs_ops.fset_nt_acl( fsp, fsp->fd, security_info_sent, psd); + ret = SMB_VFS_FSET_NT_ACL( fsp, fsp->fd, security_info_sent, psd); if (!ret) { talloc_destroy(mem_ctx); @@ -1048,15 +1090,14 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu Reply to a NT_TRANSACT_CREATE call (needs to process SD's). ****************************************************************************/ -static int call_nt_transact_create(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, char **ppsetup, char **ppparams, - char **ppdata) +static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **ppsetup, uint32 setup_count, + char **ppparams, uint32 parameter_count, + char **ppdata, uint32 data_count) { pstring fname; char *params = *ppparams; char *data = *ppdata; - int total_parameter_count = (int)IVAL(inbuf, smb_nt_TotalParameterCount); /* Breakout the oplock request bits so we can set the reply bits separately. */ int oplock_request = 0; mode_t unixmode; @@ -1092,7 +1133,10 @@ static int call_nt_transact_create(connection_struct *conn, if (IS_IPC(conn)) { if (lp_nt_pipe_support()) return do_nt_transact_create_pipe(conn, inbuf, outbuf, length, - bufsize, ppsetup, ppparams, ppdata); + bufsize, + ppsetup, setup_count, + ppparams, parameter_count, + ppdata, data_count); else return ERROR_DOS(ERRDOS,ERRnoaccess); } @@ -1101,8 +1145,8 @@ static int call_nt_transact_create(connection_struct *conn, * Ensure minimum number of parameters sent. */ - if(total_parameter_count < 54) { - DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)total_parameter_count)); + if(parameter_count < 54) { + DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)parameter_count)); return ERROR_DOS(ERRDOS,ERRnoaccess); } @@ -1146,7 +1190,7 @@ static int call_nt_transact_create(connection_struct *conn, if(!dir_fsp->is_directory) { - srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE); + srvstr_pull(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE); /* * Check to see if this is a mac fork of some kind. @@ -1175,9 +1219,9 @@ static int call_nt_transact_create(connection_struct *conn, } srvstr_pull(inbuf, &fname[dir_name_len], params+53, sizeof(fname)-dir_name_len, - total_parameter_count-53, STR_TERMINATE); + parameter_count-53, STR_TERMINATE); } else { - srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE); + srvstr_pull(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE); /* * Check to see if this is a mac fork of some kind. @@ -1331,14 +1375,10 @@ static int call_nt_transact_create(connection_struct *conn, } /* Realloc the size of parameters and data we will return */ - params = Realloc(*ppparams, 69); + params = nttrans_realloc(ppparams, 69); if(params == NULL) return ERROR_DOS(ERRDOS,ERRnomem); - *ppparams = params; - - memset((char *)params,'\0',69); - p = params; if (extended_oplock_granted) SCVAL(p,0, BATCH_OPLOCK_RETURN); @@ -1428,11 +1468,10 @@ int reply_nttranss(connection_struct *conn, don't allow a directory to be opened. ****************************************************************************/ -static int call_nt_transact_notify_change(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, - char **ppsetup, - char **ppparams, char **ppdata) +static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **ppsetup, uint32 setup_count, + char **ppparams, uint32 parameter_count, + char **ppdata, uint32 data_count) { char *setup = *ppsetup; files_struct *fsp; @@ -1462,17 +1501,22 @@ name = %s\n", fsp->fsp_name )); Reply to an NT transact rename command. ****************************************************************************/ -static int call_nt_transact_rename(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, - char **ppsetup, char **ppparams, char **ppdata) +static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **ppsetup, uint32 setup_count, + char **ppparams, uint32 parameter_count, + char **ppdata, uint32 data_count) { char *params = *ppparams; pstring new_name; - files_struct *fsp = file_fsp(params, 0); - BOOL replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False; + files_struct *fsp = NULL; + BOOL replace_if_exists = False; NTSTATUS status; + if(parameter_count < 4) + return ERROR_DOS(ERRDOS,ERRbadfunc); + + fsp = file_fsp(params, 0); + replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False; CHECK_FSP(fsp, conn); srvstr_pull(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE); @@ -1518,15 +1562,13 @@ static size_t get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd) } /**************************************************************************** - Reply to query a security descriptor - currently this is not implemented (it - is planned to be though). Right now it just returns the same thing NT would - when queried on a FAT filesystem. JRA. + Reply to query a security descriptor. ****************************************************************************/ -static int call_nt_transact_query_security_desc(connection_struct *conn, - char *inbuf, char *outbuf, - int length, int bufsize, - char **ppsetup, char **ppparams, char **ppdata) +static int call_nt_transact_query_security_desc(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **ppsetup, uint32 setup_count, + char **ppparams, uint32 parameter_count, + char **ppdata, uint32 data_count) { uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); char *params = *ppparams; @@ -1534,21 +1576,25 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, prs_struct pd; SEC_DESC *psd = NULL; size_t sd_size; + uint32 security_info_wanted; TALLOC_CTX *mem_ctx; + files_struct *fsp = NULL; - files_struct *fsp = file_fsp(params,0); + if(parameter_count < 8) + return ERROR_DOS(ERRDOS,ERRbadfunc); + fsp = file_fsp(params,0); if(!fsp) return ERROR_DOS(ERRDOS,ERRbadfid); + security_info_wanted = IVAL(params,4); + DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name )); - params = Realloc(*ppparams, 4); + params = nttrans_realloc(ppparams, 4); if(params == NULL) return ERROR_DOS(ERRDOS,ERRnomem); - *ppparams = params; - if ((mem_ctx = talloc_init("call_nt_transact_query_security_desc")) == NULL) { DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n")); return ERROR_DOS(ERRDOS,ERRnomem); @@ -1561,7 +1607,7 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, if (!lp_nt_acl_support(SNUM(conn))) sd_size = get_null_nt_acl(mem_ctx, &psd); else - sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); + sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd, security_info_wanted, &psd); if (sd_size == 0) { talloc_destroy(mem_ctx); @@ -1584,16 +1630,12 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, * Allocate the data we will point this at. */ - data = Realloc(*ppdata, sd_size); + data = nttrans_realloc(ppdata, sd_size); if(data == NULL) { talloc_destroy(mem_ctx); return ERROR_DOS(ERRDOS,ERRnomem); } - *ppdata = data; - - memset(data, '\0', sd_size); - /* * Init the parse struct we will marshall into. */ @@ -1632,23 +1674,21 @@ security descriptor.\n")); } /**************************************************************************** - Reply to set a security descriptor. Map to UNIX perms. + Reply to set a security descriptor. Map to UNIX perms or POSIX ACLs. ****************************************************************************/ -static int call_nt_transact_set_security_desc(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, char **ppsetup, - char **ppparams, char **ppdata) +static int call_nt_transact_set_security_desc(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **ppsetup, uint32 setup_count, + char **ppparams, uint32 parameter_count, + char **ppdata, uint32 data_count) { - uint32 total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount); char *params= *ppparams; char *data = *ppdata; - uint32 total_data_count = (uint32)IVAL(inbuf, smb_nts_TotalDataCount); files_struct *fsp = NULL; uint32 security_info_sent = 0; NTSTATUS nt_status; - if(total_parameter_count < 8) + if(parameter_count < 8) return ERROR_DOS(ERRDOS,ERRbadfunc); if((fsp = file_fsp(params,0)) == NULL) @@ -1662,10 +1702,10 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name, (unsigned int)security_info_sent )); - if (total_data_count == 0) + if (data_count == 0) return ERROR_DOS(ERRDOS, ERRnoaccess); - if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, total_data_count, security_info_sent))) + if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, data_count, security_info_sent))) return ERROR_NT(nt_status); done: @@ -1677,15 +1717,15 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, /**************************************************************************** Reply to NT IOCTL ****************************************************************************/ -static int call_nt_transact_ioctl(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, - char **ppsetup, int setup_count, - char **ppparams, int parameter_count, - char **ppdata, int data_count) + +static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **ppsetup, uint32 setup_count, + char **ppparams, uint32 parameter_count, + char **ppdata, uint32 data_count) { unsigned fnum, control; static BOOL logged_message; + char *pdata = *ppdata; if (setup_count != 8) { DEBUG(3,("call_nt_transact_ioctl: invalid setup count %d\n", setup_count)); @@ -1695,28 +1735,475 @@ static int call_nt_transact_ioctl(connection_struct *conn, fnum = SVAL(*ppsetup, 4); control = IVAL(*ppsetup, 0); - DEBUG(6,("call_nt_transact_ioctl: fnum=%d control=0x%x\n", + DEBUG(10,("call_nt_transact_ioctl: fnum=%d control=0x%08x\n", fnum, control)); switch (control) { - case NTIOCTL_SET_SPARSE: + case FSCTL_SET_SPARSE: /* pretend this succeeded - tho strictly we should mark the file sparse (if the local fs supports it) so we can know if we need to pre-allocate or not */ + + DEBUG(10,("FSCTL_SET_SPARSE: fnum=%d control=0x%08x\n",fnum,control)); send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); return -1; + + case FSCTL_0x000900C0: + /* pretend this succeeded - don't know what this really is + but works ok like this --metze + */ + + DEBUG(10,("FSCTL_GET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control)); + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); + return -1; + + case FSCTL_GET_REPARSE_POINT: + /* pretend this fail - my winXP does it like this + * --metze + */ + DEBUG(10,("FSCTL_GET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control)); + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0); + return -1; + + case FSCTL_SET_REPARSE_POINT: + /* pretend this fail - I'm assuming this because of the FSCTL_GET_REPARSE_POINT case. + * --metze + */ + + DEBUG(10,("FSCTL_SET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control)); + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0); + return -1; + + case FSCTL_FIND_FILES_BY_SID: /* I hope this name is right */ + { + /* pretend this succeeded - + * + * we have to send back a list with all files owned by this SID + * + * but I have to check that --metze + */ + + DOM_SID sid; + uid_t uid; + size_t sid_len=SID_MAX_SIZE; + + DEBUG(10,("FSCTL_FIND_FILES_BY_SID: fnum=%d control=0x%08x\n",fnum,control)); + + /* this is not the length of the sid :-( so unknown 4 bytes */ + /*sid_len = IVAL(pdata,0); + DEBUGADD(0,("sid_len: (%u)\n",sid_len));*/ + + sid_parse(pdata+4,sid_len,&sid); + DEBUGADD(10,("SID: %s\n",sid_string_static(&sid))); + + if (!NT_STATUS_IS_OK(sid_to_uid(&sid, &uid))) { + DEBUG(0,("sid_to_uid: failed, sid[%s]\n", + sid_string_static(&sid))); + uid = (-1); + } + + /* we can take a look at the find source :-) + * + * find ./ -uid $uid -name '*' is what we need here + * + * + * and send 4bytes len and then NULL terminated unicode strings + * for each file + * + * but I don't know how to deal with the paged results + * + * we don't send all files at once + * and at the next we should *not* start from the beginning, + * so we have to cache the result + * + * --metze + */ + + /* this works for now... */ + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); + return -1; + } default: if (!logged_message) { logged_message = True; /* Only print this once... */ - DEBUG(3,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n", + DEBUG(0,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n", control)); } } return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } - + + +#ifdef HAVE_SYS_QUOTAS +/**************************************************************************** + Reply to get user quota +****************************************************************************/ + +static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **ppsetup, uint32 setup_count, + char **ppparams, uint32 parameter_count, + char **ppdata, uint32 data_count) +{ + NTSTATUS nt_status = NT_STATUS_OK; + uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); + char *params = *ppparams; + char *pdata = *ppdata; + char *entry; + int data_len=0,param_len=0; + int qt_len=0; + int entry_len = 0; + files_struct *fsp = NULL; + uint16 level = 0; + size_t sid_len; + DOM_SID sid; + BOOL start_enum = True; + SMB_NTQUOTA_STRUCT qt; + SMB_NTQUOTA_LIST *tmp_list; + SMB_NTQUOTA_HANDLE *qt_handle = NULL; + + ZERO_STRUCT(qt); + + /* access check */ + if (conn->admin_user != True) { + DEBUG(1,("set_user_quota: access_denied service [%s] user [%s]\n", + lp_servicename(SNUM(conn)),conn->user)); + return ERROR_DOS(ERRDOS,ERRnoaccess); + } + + /* + * Ensure minimum number of parameters sent. + */ + + if (parameter_count < 4) { + DEBUG(0,("TRANSACT_GET_USER_QUOTA: requires %d >= 4 bytes parameters\n",parameter_count)); + return ERROR_DOS(ERRDOS,ERRinvalidparam); + } + + /* maybe we can check the quota_fnum */ + fsp = file_fsp(params,0); + if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { + DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); + return ERROR_NT(NT_STATUS_INVALID_HANDLE); + } + + /* the NULL pointer cheking for fsp->fake_file_handle->pd + * is done by CHECK_NTQUOTA_HANDLE_OK() + */ + qt_handle = (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->pd; + + level = SVAL(params,2); + + /* unknown 12 bytes leading in params */ + + switch (level) { + case TRANSACT_GET_USER_QUOTA_LIST_CONTINUE: + /* seems that we should continue with the enum here --metze */ + + if (qt_handle->quota_list!=NULL && + qt_handle->tmp_list==NULL) { + + /* free the list */ + free_ntquota_list(&(qt_handle->quota_list)); + + /* Realloc the size of parameters and data we will return */ + param_len = 4; + params = nttrans_realloc(ppparams, param_len); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + + data_len = 0; + SIVAL(params,0,data_len); + + break; + } + + start_enum = False; + + case TRANSACT_GET_USER_QUOTA_LIST_START: + + if (qt_handle->quota_list==NULL && + qt_handle->tmp_list==NULL) { + start_enum = True; + } + + if (start_enum && vfs_get_user_ntquota_list(fsp,&(qt_handle->quota_list))!=0) + return ERROR_DOS(ERRSRV,ERRerror); + + /* Realloc the size of parameters and data we will return */ + param_len = 4; + params = nttrans_realloc(ppparams, param_len); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + + /* we should not trust the value in max_data_count*/ + max_data_count = MIN(max_data_count,2048); + + pdata = nttrans_realloc(ppdata, max_data_count);/* should be max data count from client*/ + if(pdata == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + + entry = pdata; + + + /* set params Size of returned Quota Data 4 bytes*/ + /* but set it later when we know it */ + + /* for each entry push the data */ + + if (start_enum) { + qt_handle->tmp_list = qt_handle->quota_list; + } + + tmp_list = qt_handle->tmp_list; + + for (;((tmp_list!=NULL)&&((qt_len +40+SID_MAX_SIZE)<max_data_count)); + tmp_list=tmp_list->next,entry+=entry_len,qt_len+=entry_len) { + + sid_len = sid_size(&tmp_list->quotas->sid); + entry_len = 40 + sid_len; + + /* nextoffset entry 4 bytes */ + SIVAL(entry,0,entry_len); + + /* then the len of the SID 4 bytes */ + SIVAL(entry,4,sid_len); + + /* unknown data 8 bytes SMB_BIG_UINT */ + SBIG_UINT(entry,8,(SMB_BIG_UINT)0); /* this is not 0 in windows...-metze*/ + + /* the used disk space 8 bytes SMB_BIG_UINT */ + SBIG_UINT(entry,16,tmp_list->quotas->usedspace); + + /* the soft quotas 8 bytes SMB_BIG_UINT */ + SBIG_UINT(entry,24,tmp_list->quotas->softlim); + + /* the hard quotas 8 bytes SMB_BIG_UINT */ + SBIG_UINT(entry,32,tmp_list->quotas->hardlim); + + /* and now the SID */ + sid_linearize(entry+40, sid_len, &tmp_list->quotas->sid); + } + + qt_handle->tmp_list = tmp_list; + + /* overwrite the offset of the last entry */ + SIVAL(entry-entry_len,0,0); + + data_len = 4+qt_len; + /* overwrite the params quota_data_len */ + SIVAL(params,0,data_len); + + break; + + case TRANSACT_GET_USER_QUOTA_FOR_SID: + + /* unknown 4 bytes IVAL(pdata,0) */ + + if (data_count < 8) { + DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %d bytes data\n",data_count,8)); + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + sid_len = IVAL(pdata,4); + + if (data_count < 8+sid_len) { + DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %d bytes data\n",data_count,8+sid_len)); + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + data_len = 4+40+sid_len; + + if (max_data_count < data_len) { + DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: max_data_count(%d) < data_len(%d)\n", + max_data_count, data_len)); + param_len = 4; + SIVAL(params,0,data_len); + data_len = 0; + nt_status = NT_STATUS_BUFFER_TOO_SMALL; + break; + } + + sid_parse(pdata+8,sid_len,&sid); + + + if (vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) { + ZERO_STRUCT(qt); + /* + * we have to return zero's in all fields + * instead of returning an error here + * --metze + */ + } + + /* Realloc the size of parameters and data we will return */ + param_len = 4; + params = nttrans_realloc(ppparams, param_len); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + + pdata = nttrans_realloc(ppdata, data_len); + if(pdata == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + + entry = pdata; + + /* set params Size of returned Quota Data 4 bytes*/ + SIVAL(params,0,data_len); + + /* nextoffset entry 4 bytes */ + SIVAL(entry,0,0); + + /* then the len of the SID 4 bytes */ + SIVAL(entry,4,sid_len); + + /* unknown data 8 bytes SMB_BIG_UINT */ + SBIG_UINT(entry,8,(SMB_BIG_UINT)0); /* this is not 0 in windows...-mezte*/ + + /* the used disk space 8 bytes SMB_BIG_UINT */ + SBIG_UINT(entry,16,qt.usedspace); + + /* the soft quotas 8 bytes SMB_BIG_UINT */ + SBIG_UINT(entry,24,qt.softlim); + + /* the hard quotas 8 bytes SMB_BIG_UINT */ + SBIG_UINT(entry,32,qt.hardlim); + + /* and now the SID */ + sid_linearize(entry+40, sid_len, &sid); + + break; + + default: + DEBUG(0,("do_nt_transact_get_user_quota: fnum %d unknown level 0x%04hX\n",fsp->fnum,level)); + return ERROR_DOS(ERRSRV,ERRerror); + break; + } + + send_nt_replies(inbuf, outbuf, bufsize, nt_status, params, param_len, pdata, data_len); + + return -1; +} + +/**************************************************************************** + Reply to set user quota +****************************************************************************/ + +static int call_nt_transact_set_user_quota(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **ppsetup, uint32 setup_count, + char **ppparams, uint32 parameter_count, + char **ppdata, uint32 data_count) +{ + char *params = *ppparams; + char *pdata = *ppdata; + int data_len=0,param_len=0; + SMB_NTQUOTA_STRUCT qt; + size_t sid_len; + DOM_SID sid; + files_struct *fsp = NULL; + + ZERO_STRUCT(qt); + + /* access check */ + if (conn->admin_user != True) { + DEBUG(1,("set_user_quota: access_denied service [%s] user [%s]\n", + lp_servicename(SNUM(conn)),conn->user)); + return ERROR_DOS(ERRDOS,ERRnoaccess); + } + + /* + * Ensure minimum number of parameters sent. + */ + + if (parameter_count < 2) { + DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= 2 bytes parameters\n",parameter_count)); + return ERROR_DOS(ERRDOS,ERRinvalidparam); + } + + /* maybe we can check the quota_fnum */ + fsp = file_fsp(params,0); + if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { + DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); + return ERROR_NT(NT_STATUS_INVALID_HANDLE); + } + + if (data_count < 40) { + DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %d bytes data\n",data_count,40)); + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + /* offset to next quota record. + * 4 bytes IVAL(pdata,0) + * unused here... + */ + + /* sid len */ + sid_len = IVAL(pdata,4); + + if (data_count < 40+sid_len) { + DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %d bytes data\n",data_count,40+sid_len)); + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + /* unknown 8 bytes in pdata + * maybe its the change time in NTTIME + */ + + /* the used space 8 bytes (SMB_BIG_UINT)*/ + qt.usedspace = (SMB_BIG_UINT)IVAL(pdata,16); +#ifdef LARGE_SMB_OFF_T + qt.usedspace |= (((SMB_BIG_UINT)IVAL(pdata,20)) << 32); +#else /* LARGE_SMB_OFF_T */ + if ((IVAL(pdata,20) != 0)&& + ((qt.usedspace != 0xFFFFFFFF)|| + (IVAL(pdata,20)!=0xFFFFFFFF))) { + /* more than 32 bits? */ + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } +#endif /* LARGE_SMB_OFF_T */ + + /* the soft quotas 8 bytes (SMB_BIG_UINT)*/ + qt.softlim = (SMB_BIG_UINT)IVAL(pdata,24); +#ifdef LARGE_SMB_OFF_T + qt.softlim |= (((SMB_BIG_UINT)IVAL(pdata,28)) << 32); +#else /* LARGE_SMB_OFF_T */ + if ((IVAL(pdata,28) != 0)&& + ((qt.softlim != 0xFFFFFFFF)|| + (IVAL(pdata,28)!=0xFFFFFFFF))) { + /* more than 32 bits? */ + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } +#endif /* LARGE_SMB_OFF_T */ + + /* the hard quotas 8 bytes (SMB_BIG_UINT)*/ + qt.hardlim = (SMB_BIG_UINT)IVAL(pdata,32); +#ifdef LARGE_SMB_OFF_T + qt.hardlim |= (((SMB_BIG_UINT)IVAL(pdata,36)) << 32); +#else /* LARGE_SMB_OFF_T */ + if ((IVAL(pdata,36) != 0)&& + ((qt.hardlim != 0xFFFFFFFF)|| + (IVAL(pdata,36)!=0xFFFFFFFF))) { + /* more than 32 bits? */ + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } +#endif /* LARGE_SMB_OFF_T */ + + sid_parse(pdata+40,sid_len,&sid); + DEBUGADD(8,("SID: %s\n",sid_string_static(&sid))); + + /* 44 unknown bytes left... */ + + if (vfs_set_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) { + return ERROR_DOS(ERRSRV,ERRerror); + } + + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, param_len, pdata, data_len); + + return -1; +} +#endif /* HAVE_SYS_QUOTAS */ + /**************************************************************************** Reply to a SMBNTtrans. ****************************************************************************/ @@ -1918,8 +2405,10 @@ due to being in oplock break state.\n", (unsigned int)function_code )); case NT_TRANSACT_CREATE: START_PROFILE_NESTED(NT_transact_create); outsize = call_nt_transact_create(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); + length, bufsize, + &setup, setup_count, + ¶ms, total_parameter_count, + &data, total_data_count); END_PROFILE_NESTED(NT_transact_create); break; case NT_TRANSACT_IOCTL: @@ -1927,39 +2416,67 @@ due to being in oplock break state.\n", (unsigned int)function_code )); outsize = call_nt_transact_ioctl(conn, inbuf, outbuf, length, bufsize, &setup, setup_count, - ¶ms, parameter_count, - &data, data_count); + ¶ms, total_parameter_count, + &data, total_data_count); END_PROFILE_NESTED(NT_transact_ioctl); break; case NT_TRANSACT_SET_SECURITY_DESC: START_PROFILE_NESTED(NT_transact_set_security_desc); outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); + length, bufsize, + &setup, setup_count, + ¶ms, total_parameter_count, + &data, total_data_count); END_PROFILE_NESTED(NT_transact_set_security_desc); break; case NT_TRANSACT_NOTIFY_CHANGE: START_PROFILE_NESTED(NT_transact_notify_change); outsize = call_nt_transact_notify_change(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); + length, bufsize, + &setup, setup_count, + ¶ms, total_parameter_count, + &data, total_data_count); END_PROFILE_NESTED(NT_transact_notify_change); break; case NT_TRANSACT_RENAME: START_PROFILE_NESTED(NT_transact_rename); outsize = call_nt_transact_rename(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); + length, bufsize, + &setup, setup_count, + ¶ms, total_parameter_count, + &data, total_data_count); END_PROFILE_NESTED(NT_transact_rename); break; case NT_TRANSACT_QUERY_SECURITY_DESC: START_PROFILE_NESTED(NT_transact_query_security_desc); outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf, - length, bufsize, - &setup, ¶ms, &data); + length, bufsize, + &setup, setup_count, + ¶ms, total_parameter_count, + &data, total_data_count); END_PROFILE_NESTED(NT_transact_query_security_desc); break; +#ifdef HAVE_SYS_QUOTAS + case NT_TRANSACT_GET_USER_QUOTA: + START_PROFILE_NESTED(NT_transact_get_user_quota); + outsize = call_nt_transact_get_user_quota(conn, inbuf, outbuf, + length, bufsize, + &setup, setup_count, + ¶ms, total_parameter_count, + &data, total_data_count); + END_PROFILE_NESTED(NT_transact_get_user_quota); + break; + case NT_TRANSACT_SET_USER_QUOTA: + START_PROFILE_NESTED(NT_transact_set_user_quota); + outsize = call_nt_transact_set_user_quota(conn, inbuf, outbuf, + length, bufsize, + &setup, setup_count, + ¶ms, total_parameter_count, + &data, total_data_count); + END_PROFILE_NESTED(NT_transact_set_user_quota); + break; +#endif /* HAVE_SYS_QUOTAS */ default: /* Error in request */ DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code)); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 510b28172d..6d03eaa29a 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -38,13 +38,13 @@ static int fd_open(struct connection_struct *conn, char *fname, flags |= O_NOFOLLOW; #endif - fd = conn->vfs_ops.open(conn,fname,flags,mode); + fd = SMB_VFS_OPEN(conn,fname,flags,mode); /* Fix for files ending in '.' */ if((fd == -1) && (errno == ENOENT) && (strchr_m(fname,'.')==NULL)) { pstrcat(fname,"."); - fd = conn->vfs_ops.open(conn,fname,flags,mode); + fd = SMB_VFS_OPEN(conn,fname,flags,mode); } DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n", fname, @@ -74,7 +74,7 @@ static void check_for_pipe(char *fname) /* special case of pipe opens */ char s[10]; StrnCpy(s,fname,sizeof(s)-1); - strlower(s); + strlower_m(s); if (strstr(s,"pipe/")) { DEBUG(3,("Rejecting named pipe open for %s\n",fname)); unix_ERR_class = ERRSRV; @@ -186,9 +186,9 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, int ret; if (fsp->fd == -1) - ret = vfs_stat(conn, fname, psbuf); + ret = SMB_VFS_STAT(conn, fname, psbuf); else { - ret = vfs_fstat(fsp,fsp->fd,psbuf); + ret = SMB_VFS_FSTAT(fsp,fsp->fd,psbuf); /* If we have an fd, this stat should succeed. */ if (ret == -1) DEBUG(0,("Error doing fstat on open file %s (%s)\n", fname,strerror(errno) )); @@ -259,7 +259,7 @@ static int truncate_unless_locked(struct connection_struct *conn, files_struct * unix_ERR_ntstatus = dos_to_ntstatus(ERRDOS, ERRlock); return -1; } else { - return conn->vfs_ops.ftruncate(fsp,fsp->fd,0); + return SMB_VFS_FTRUNCATE(fsp,fsp->fd,0); } } @@ -1024,6 +1024,16 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", if (!file_existed) { + /* + * Now the file exists and fsp is successfully opened, + * fsp->dev and fsp->inode are valid and should replace the + * dev=0,inode=0 from a non existent file. Spotted by + * Nadav Danieli <nadavd@exanet.com>. JRA. + */ + + dev = fsp->dev; + inode = fsp->inode; + lock_share_entry_fsp(fsp); num_share_modes = open_mode_check(conn, fname, dev, inode, @@ -1073,7 +1083,7 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", /* * We are modifing the file after open - update the stat struct.. */ - if ((truncate_unless_locked(conn,fsp) == -1) || (vfs_fstat(fsp,fsp->fd,psbuf)==-1)) { + if ((truncate_unless_locked(conn,fsp) == -1) || (SMB_VFS_FSTAT(fsp,fsp->fd,psbuf)==-1)) { unlock_share_entry_fsp(fsp); fd_close(conn,fsp); file_free(fsp); @@ -1148,11 +1158,11 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", * selected. */ - if (!file_existed && !def_acl && (conn->vfs_ops.fchmod_acl != NULL)) { + if (!file_existed && !def_acl) { int saved_errno = errno; /* We might get ENOSYS in the next call.. */ - if (conn->vfs_ops.fchmod_acl(fsp, fsp->fd, mode) == -1 && errno == ENOSYS) + if (SMB_VFS_FCHMOD_ACL(fsp, fsp->fd, mode) == -1 && errno == ENOSYS) errno = saved_errno; /* Ignore ENOSYS */ } else if (new_mode) { @@ -1161,9 +1171,9 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", /* Attributes need changing. File already existed. */ - if (conn->vfs_ops.fchmod_acl != NULL) { + { int saved_errno = errno; /* We might get ENOSYS in the next call.. */ - ret = conn->vfs_ops.fchmod_acl(fsp, fsp->fd, new_mode); + ret = SMB_VFS_FCHMOD_ACL(fsp, fsp->fd, new_mode); if (ret == -1 && errno == ENOSYS) { errno = saved_errno; /* Ignore ENOSYS */ @@ -1174,7 +1184,7 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", } } - if ((ret == -1) && (conn->vfs_ops.fchmod(fsp, fsp->fd, new_mode) == -1)) + if ((ret == -1) && (SMB_VFS_FCHMOD(fsp, fsp->fd, new_mode) == -1)) DEBUG(5, ("open_file_shared: failed to reset attributes of file %s to 0%o\n", fname, (int)new_mode)); } @@ -1280,14 +1290,14 @@ files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_ST return NULL; } - if(vfs_mkdir(conn,fname, unix_mode(conn,aDIR, fname)) < 0) { + if(vfs_MkDir(conn,fname, unix_mode(conn,aDIR, fname)) < 0) { DEBUG(2,("open_directory: unable to create %s. Error was %s\n", fname, strerror(errno) )); file_free(fsp); return NULL; } - if(vfs_stat(conn,fname, psbuf) != 0) { + if(SMB_VFS_STAT(conn,fname, psbuf) != 0) { file_free(fsp); return NULL; } diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index 632dfe9e29..8525687793 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -391,7 +391,7 @@ pid %d, port %d, dev = %x, inode = %.0f, file_id = %lu\n", /* * Keep this as a debug case - eventually we can remove it. */ - case (CMD_REPLY | KERNEL_OPLOCK_BREAK_CMD): + case 0x8001: DEBUG(0,("process_local_message: Received unsolicited break \ reply - dumping info.\n")); diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 283eed73ef..e2c143f1e2 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -157,7 +157,7 @@ int register_vuid(auth_serversupplied_info *server_info, const char *smb_name) } vuser->guest = server_info->guest; - fstrcpy(vuser->user.unix_name, pdb_get_username(server_info->sam_account)); + fstrcpy(vuser->user.unix_name, server_info->unix_name); /* This is a potentially untrusted username */ alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$", sizeof(vuser->user.smb_name)); @@ -168,16 +168,24 @@ int register_vuid(auth_serversupplied_info *server_info, const char *smb_name) { /* 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 *logon_script = pdb_get_logon_script(server_info->sam_account); + + if (!IS_SAM_DEFAULT(server_info->sam_account, PDB_UNIXHOMEDIR)) { + const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); + if (unix_homedir) { + vuser->unix_homedir = smb_xstrdup(unix_homedir); + } + } else { + struct passwd *passwd = getpwnam_alloc(vuser->user.unix_name); + if (passwd) { + vuser->unix_homedir = smb_xstrdup(passwd->pw_dir); + passwd_free(&passwd); + } + } + if (homedir) { vuser->homedir = smb_xstrdup(homedir); } - - if (unix_homedir) { - vuser->unix_homedir = smb_xstrdup(unix_homedir); - } - if (logon_script) { vuser->logon_script = smb_xstrdup(logon_script); } diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index a362db7d56..95b45fcc99 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -42,10 +42,448 @@ typedef struct canon_ace { enum ace_owner owner_type; enum ace_attribute attr; posix_id unix_ug; + BOOL inherited; } canon_ace; #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR) +/* + * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance) + * attribute on disk. + * + * | 1 | 1 | 2 | 2 | .... + * +------+------+-------------+---------------------+-------------+--------------------+ + * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... | + * +------+------+-------------+---------------------+-------------+--------------------+ + */ + +#define SAMBA_POSIX_INHERITANCE_EA_NAME "user.SAMBA_PAI" + +#define PAI_VERSION_OFFSET 0 +#define PAI_FLAG_OFFSET 1 +#define PAI_NUM_ENTRIES_OFFSET 2 +#define PAI_NUM_DEFAULT_ENTRIES_OFFSET 4 +#define PAI_ENTRIES_BASE 6 + +#define PAI_VERSION 1 +#define PAI_ACL_FLAG_PROTECTED 0x1 +#define PAI_ENTRY_LENGTH 5 + +/* + * In memory format of user.SAMBA_PAI attribute. + */ + +struct pai_entry { + struct pai_entry *next, *prev; + enum ace_owner owner_type; + posix_id unix_ug; +}; + +struct pai_val { + BOOL protected; + unsigned int num_entries; + struct pai_entry *entry_list; + unsigned int num_def_entries; + struct pai_entry *def_entry_list; +}; + +/************************************************************************ + Return a uint32 of the pai_entry principal. +************************************************************************/ + +static uint32 get_pai_entry_val(struct pai_entry *paie) +{ + switch (paie->owner_type) { + case UID_ACE: + DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid )); + return (uint32)paie->unix_ug.uid; + case GID_ACE: + DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid )); + return (uint32)paie->unix_ug.gid; + case WORLD_ACE: + default: + DEBUG(10,("get_pai_entry_val: world ace\n")); + return (uint32)-1; + } +} + +/************************************************************************ + Return a uint32 of the entry principal. +************************************************************************/ + +static uint32 get_entry_val(canon_ace *ace_entry) +{ + switch (ace_entry->owner_type) { + case UID_ACE: + DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid )); + return (uint32)ace_entry->unix_ug.uid; + case GID_ACE: + DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid )); + return (uint32)ace_entry->unix_ug.gid; + case WORLD_ACE: + default: + DEBUG(10,("get_entry_val: world ace\n")); + return (uint32)-1; + } +} + +/************************************************************************ + Count the inherited entries. +************************************************************************/ + +static unsigned int num_inherited_entries(canon_ace *ace_list) +{ + unsigned int num_entries = 0; + + for (; ace_list; ace_list = ace_list->next) + if (ace_list->inherited) + num_entries++; + return num_entries; +} + +/************************************************************************ + Create the on-disk format. Caller must free. +************************************************************************/ + +static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL protected, size_t *store_size) +{ + char *pai_buf = NULL; + canon_ace *ace_list = NULL; + char *entry_offset = NULL; + unsigned int num_entries = 0; + unsigned int num_def_entries = 0; + + for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) + if (ace_list->inherited) + num_entries++; + + for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) + if (ace_list->inherited) + num_def_entries++; + + DEBUG(10,("create_pai_buf: num_entries = %u, num_def_entries = %u\n", num_entries, num_def_entries )); + + *store_size = PAI_ENTRIES_BASE + ((num_entries + num_def_entries)*PAI_ENTRY_LENGTH); + + pai_buf = malloc(*store_size); + if (!pai_buf) { + return NULL; + } + + /* Set up the header. */ + memset(pai_buf, '\0', PAI_ENTRIES_BASE); + SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_VERSION); + SCVAL(pai_buf,PAI_FLAG_OFFSET,(protected ? PAI_ACL_FLAG_PROTECTED : 0)); + SSVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET,num_entries); + SSVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries); + + entry_offset = pai_buf + PAI_ENTRIES_BASE; + + for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) { + if (ace_list->inherited) { + uint8 type_val = (unsigned char)ace_list->owner_type; + uint32 entry_val = get_entry_val(ace_list); + + SCVAL(entry_offset,0,type_val); + SIVAL(entry_offset,1,entry_val); + entry_offset += PAI_ENTRY_LENGTH; + } + } + + for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) { + if (ace_list->inherited) { + uint8 type_val = (unsigned char)ace_list->owner_type; + uint32 entry_val = get_entry_val(ace_list); + + SCVAL(entry_offset,0,type_val); + SIVAL(entry_offset,1,entry_val); + entry_offset += PAI_ENTRY_LENGTH; + } + } + + return pai_buf; +} + +/************************************************************************ + Store the user.SAMBA_PAI attribute on disk. +************************************************************************/ + +static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list, + canon_ace *dir_ace_list, BOOL protected) +{ + int ret; + size_t store_size; + char *pai_buf; + + if (!lp_map_acl_inherit(SNUM(fsp->conn))) + return; + + /* + * Don't store if this ACL isn't protected and + * none of the entries in it are marked as inherited. + */ + + if (!protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) { + /* Instead just remove the attribute if it exists. */ + if (fsp->fd != -1) + SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME); + else + SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME); + return; + } + + pai_buf = create_pai_buf(file_ace_list, dir_ace_list, protected, &store_size); + + if (fsp->fd != -1) + ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, + pai_buf, store_size, 0); + else + ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME, + pai_buf, store_size, 0); + + SAFE_FREE(pai_buf); + + DEBUG(10,("store_inheritance_attribute:%s for file %s\n", protected ? " (protected)" : "", fsp->fsp_name)); + if (ret == -1 && errno != ENOSYS) + DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) )); +} + +/************************************************************************ + Delete the in memory inheritance info. +************************************************************************/ + +static void free_inherited_info(struct pai_val *pal) +{ + if (pal) { + struct pai_entry *paie, *paie_next; + for (paie = pal->entry_list; paie; paie = paie_next) { + paie_next = paie->next; + SAFE_FREE(paie); + } + for (paie = pal->def_entry_list; paie; paie = paie_next) { + paie_next = paie->next; + SAFE_FREE(paie); + } + SAFE_FREE(pal); + } +} + +/************************************************************************ + Was this ACL protected ? +************************************************************************/ + +static BOOL get_protected_flag(struct pai_val *pal) +{ + if (!pal) + return False; + return pal->protected; +} + +/************************************************************************ + Was this ACE inherited ? +************************************************************************/ + +static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL default_ace) +{ + struct pai_entry *paie; + + if (!pal) + return False; + + /* If the entry exists it is inherited. */ + for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) { + if (ace_entry->owner_type == paie->owner_type && + get_entry_val(ace_entry) == get_pai_entry_val(paie)) + return True; + } + return False; +} + +/************************************************************************ + Ensure an attribute just read is valid. +************************************************************************/ + +static BOOL check_pai_ok(char *pai_buf, size_t pai_buf_data_size) +{ + uint16 num_entries; + uint16 num_def_entries; + + if (pai_buf_data_size < PAI_ENTRIES_BASE) { + /* Corrupted - too small. */ + return False; + } + + if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_VERSION) + return False; + + num_entries = SVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET); + num_def_entries = SVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET); + + /* Check the entry lists match. */ + /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */ + + if (((num_entries + num_def_entries)*PAI_ENTRY_LENGTH) + PAI_ENTRIES_BASE != pai_buf_data_size) + return False; + + return True; +} + + +/************************************************************************ + Convert to in-memory format. +************************************************************************/ + +static struct pai_val *create_pai_val(char *buf, size_t size) +{ + char *entry_offset; + struct pai_val *paiv = NULL; + int i; + + if (!check_pai_ok(buf, size)) + return NULL; + + paiv = malloc(sizeof(struct pai_val)); + if (!paiv) + return NULL; + + memset(paiv, '\0', sizeof(struct pai_val)); + + paiv->protected = (CVAL(buf,PAI_FLAG_OFFSET) == PAI_ACL_FLAG_PROTECTED); + + paiv->num_entries = SVAL(buf,PAI_NUM_ENTRIES_OFFSET); + paiv->num_def_entries = SVAL(buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET); + + entry_offset = buf + PAI_ENTRIES_BASE; + + DEBUG(10,("create_pai_val:%s num_entries = %u, num_def_entries = %u\n", + paiv->protected ? " (protected)" : "", paiv->num_entries, paiv->num_def_entries )); + + for (i = 0; i < paiv->num_entries; i++) { + struct pai_entry *paie; + + paie = malloc(sizeof(struct pai_entry)); + if (!paie) { + free_inherited_info(paiv); + return NULL; + } + + paie->owner_type = (enum ace_owner)CVAL(entry_offset,0); + switch( paie->owner_type) { + case UID_ACE: + paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1); + DEBUG(10,("create_pai_val: uid = %u\n", (unsigned int)paie->unix_ug.uid )); + break; + case GID_ACE: + paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1); + DEBUG(10,("create_pai_val: gid = %u\n", (unsigned int)paie->unix_ug.gid )); + break; + case WORLD_ACE: + paie->unix_ug.world = -1; + DEBUG(10,("create_pai_val: world ace\n")); + break; + default: + free_inherited_info(paiv); + return NULL; + } + entry_offset += PAI_ENTRY_LENGTH; + DLIST_ADD(paiv->entry_list, paie); + } + + for (i = 0; i < paiv->num_def_entries; i++) { + struct pai_entry *paie; + + paie = malloc(sizeof(struct pai_entry)); + if (!paie) { + free_inherited_info(paiv); + return NULL; + } + + paie->owner_type = (enum ace_owner)CVAL(entry_offset,0); + switch( paie->owner_type) { + case UID_ACE: + paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1); + DEBUG(10,("create_pai_val: (def) uid = %u\n", (unsigned int)paie->unix_ug.uid )); + break; + case GID_ACE: + paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1); + DEBUG(10,("create_pai_val: (def) gid = %u\n", (unsigned int)paie->unix_ug.gid )); + break; + case WORLD_ACE: + paie->unix_ug.world = -1; + DEBUG(10,("create_pai_val: (def) world ace\n")); + break; + default: + free_inherited_info(paiv); + return NULL; + } + entry_offset += PAI_ENTRY_LENGTH; + DLIST_ADD(paiv->def_entry_list, paie); + } + + return paiv; +} + +/************************************************************************ + Load the user.SAMBA_PAI attribute. +************************************************************************/ + +static struct pai_val *load_inherited_info(files_struct *fsp) +{ + char *pai_buf; + size_t pai_buf_size = 1024; + struct pai_val *paiv = NULL; + ssize_t ret; + + if (!lp_map_acl_inherit(SNUM(fsp->conn))) + return NULL; + + if ((pai_buf = malloc(pai_buf_size)) == NULL) + return NULL; + + do { + if (fsp->fd != -1) + ret = SMB_VFS_FGETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, + pai_buf, pai_buf_size); + else + ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME, + pai_buf, pai_buf_size); + + if (ret == -1) { + if (errno != ERANGE) { + break; + } + /* Buffer too small - enlarge it. */ + pai_buf_size *= 2; + SAFE_FREE(pai_buf); + if ((pai_buf = malloc(pai_buf_size)) == NULL) + return NULL; + } + } while (ret == -1); + + DEBUG(10,("load_inherited_info: ret = %d for file %s\n", ret, fsp->fsp_name)); + + if (ret == -1) { + /* No attribute or not supported. */ +#if defined(ENOATTR) + if (errno != ENOATTR) + DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) )); +#else + if (errno != ENOSYS) + DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) )); +#endif + SAFE_FREE(pai_buf); + return NULL; + } + + paiv = create_pai_val(pai_buf, ret); + + if (paiv && paiv->protected) + DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fsp->fsp_name)); + + SAFE_FREE(pai_buf); + return paiv; +} + /**************************************************************************** Functions to manipulate the internal ACE format. ****************************************************************************/ @@ -106,10 +544,10 @@ static void print_canon_ace(canon_ace *pace, int num) dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee)); if (pace->owner_type == UID_ACE) { const char *u_name = uidtoname(pace->unix_ug.uid); - dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name); + dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name ); } else if (pace->owner_type == GID_ACE) { char *g_name = gidtoname(pace->unix_ug.gid); - dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name); + dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name ); } else dbgtext( "other "); switch (pace->type) { @@ -129,6 +567,8 @@ static void print_canon_ace(canon_ace *pace, int num) dbgtext( "SMB_ACL_OTHER "); break; } + if (pace->inherited) + dbgtext( "(inherited) "); dbgtext( "perms "); dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-'); dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-'); @@ -158,9 +598,9 @@ static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET { mode_t ret = 0; - ret |= (conn->vfs_ops.sys_acl_get_perm(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0); - ret |= (conn->vfs_ops.sys_acl_get_perm(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0); - ret |= (conn->vfs_ops.sys_acl_get_perm(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0); + ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0); + ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0); + ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0); return ret; } @@ -190,18 +630,18 @@ static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset) { - if (conn->vfs_ops.sys_acl_clear_perms(conn, *p_permset) == -1) + if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1) return -1; if (mode & S_IRUSR) { - if (conn->vfs_ops.sys_acl_add_perm(conn, *p_permset, SMB_ACL_READ) == -1) + if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) return -1; } if (mode & S_IWUSR) { - if (conn->vfs_ops.sys_acl_add_perm(conn, *p_permset, SMB_ACL_WRITE) == -1) + if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) return -1; } if (mode & S_IXUSR) { - if (conn->vfs_ops.sys_acl_add_perm(conn, *p_permset, SMB_ACL_EXECUTE) == -1) + if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) return -1; } return 0; @@ -468,7 +908,7 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, if (security_info_sent & OWNER_SECURITY_INFORMATION) { sid_copy(&owner_sid, psd->owner_sid); - if (NT_STATUS_IS_ERR(sid_to_uid(&owner_sid, puser))) { + if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid, puser))) { #if ACL_FORCE_UNMAPPABLE /* this allows take ownership to work reasonably */ extern struct current_user current_user; @@ -488,7 +928,7 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, if (security_info_sent & GROUP_SECURITY_INFORMATION) { sid_copy(&grp_sid, psd->grp_sid); - if (NT_STATUS_IS_ERR(sid_to_gid( &grp_sid, pgrp))) { + if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid, pgrp))) { #if ACL_FORCE_UNMAPPABLE /* this allows take group ownership to work reasonably */ extern struct current_user current_user; @@ -637,62 +1077,6 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, } } - /* - * When setting ACLs and missing one out of SMB_ACL_USER_OBJ, - * SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER, try to retrieve current - * values. For user and other a simple vfs_stat would do, but - * we would get mask instead of group. Let's do it via ACL. - */ - - if (setting_acl && (!got_user || !got_grp || !got_other)) { - - SMB_ACL_ENTRY_T entry; - int entry_id = SMB_ACL_FIRST_ENTRY; - - if(fsp->is_directory || fsp->fd == -1) { - current_posix_acl = conn->vfs_ops.sys_acl_get_file(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS); - } else { - current_posix_acl = conn->vfs_ops.sys_acl_get_fd(fsp, fsp->fd); - } - - if (current_posix_acl) { - while (conn->vfs_ops.sys_acl_get_entry(conn, current_posix_acl, entry_id, &entry) == 1) { - SMB_ACL_TAG_T tagtype; - SMB_ACL_PERMSET_T permset; - - /* get_next... */ - if (entry_id == SMB_ACL_FIRST_ENTRY) - entry_id = SMB_ACL_NEXT_ENTRY; - - /* Is this a MASK entry ? */ - if (conn->vfs_ops.sys_acl_get_tag_type(conn, entry, &tagtype) == -1) - continue; - - if (conn->vfs_ops.sys_acl_get_permset(conn, entry, &permset) == -1) - continue; - - switch(tagtype) { - case SMB_ACL_USER_OBJ: - current_user_perms = convert_permset_to_mode_t(conn, permset); - got_current_user = True; - break; - case SMB_ACL_GROUP_OBJ: - current_grp_perms = convert_permset_to_mode_t(conn, permset); - got_current_grp = True; - break; - case SMB_ACL_OTHER: - current_other_perms = convert_permset_to_mode_t(conn, permset); - got_current_other = True; - break; - } - } - conn->vfs_ops.sys_acl_free_acl(conn, current_posix_acl); - } else { - DEBUG(10,("ensure_canon_entry_valid: failed to retrieve current ACL of %s\n", - fsp->fsp_name)); - } - } - if (!got_user) { if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) { DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n")); @@ -822,7 +1206,7 @@ static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID Unpack a SEC_DESC into two canonical ace lists. ****************************************************************************/ -static BOOL create_canon_ace_lists(files_struct *fsp, +static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid, canon_ace **ppfile_ace, canon_ace **ppdir_ace, @@ -957,7 +1341,7 @@ static BOOL create_canon_ace_lists(files_struct *fsp, current_ace->type = SMB_ACL_OTHER; } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) { current_ace->owner_type = UID_ACE; - current_ace->unix_ug.world = -1; + current_ace->unix_ug.uid = pst->st_uid; current_ace->type = SMB_ACL_USER_OBJ; /* @@ -970,7 +1354,7 @@ static BOOL create_canon_ace_lists(files_struct *fsp, psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY; } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) { current_ace->owner_type = GID_ACE; - current_ace->unix_ug.world = -1; + current_ace->unix_ug.gid = pst->st_gid; current_ace->type = SMB_ACL_GROUP_OBJ; /* @@ -1005,6 +1389,7 @@ static BOOL create_canon_ace_lists(files_struct *fsp, current_ace->perms |= map_nt_perms( psa->info, S_IRUSR); current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE; + current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False); /* * Now add the created ace to either the file list, the directory @@ -1529,7 +1914,7 @@ static BOOL unpack_canon_ace(files_struct *fsp, * Now go through the DACL and create the canon_ace lists. */ - if (!create_canon_ace_lists( fsp, pfile_owner_sid, pfile_grp_sid, + if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid, &file_ace, &dir_ace, psd->dacl)) return False; @@ -1672,7 +2057,7 @@ static void arrange_posix_perms( char *filename, canon_ace **pp_list_head) ****************************************************************************/ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf, - DOM_SID *powner, DOM_SID *pgroup, SMB_ACL_TYPE_T the_acl_type) + DOM_SID *powner, DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type) { extern DOM_SID global_sid_World; connection_struct *conn = fsp->conn; @@ -1684,7 +2069,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ SMB_ACL_ENTRY_T entry; size_t ace_count; - while ( posix_acl && (conn->vfs_ops.sys_acl_get_entry(conn, posix_acl, entry_id, &entry) == 1)) { + while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) { SMB_ACL_TAG_T tagtype; SMB_ACL_PERMSET_T permset; DOM_SID sid; @@ -1696,10 +2081,10 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ entry_id = SMB_ACL_NEXT_ENTRY; /* Is this a MASK entry ? */ - if (conn->vfs_ops.sys_acl_get_tag_type(conn, entry, &tagtype) == -1) + if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) continue; - if (conn->vfs_ops.sys_acl_get_permset(conn, entry, &permset) == -1) + if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) continue; /* Decide which SID to use based on the ACL type. */ @@ -1712,7 +2097,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ break; case SMB_ACL_USER: { - uid_t *puid = (uid_t *)conn->vfs_ops.sys_acl_get_qualifier(conn, entry); + uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); if (puid == NULL) { DEBUG(0,("canonicalise_acl: Failed to get uid.\n")); continue; @@ -1729,7 +2114,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ uid_to_sid( &sid, *puid); unix_ug.uid = *puid; owner_type = UID_ACE; - conn->vfs_ops.sys_acl_free_qualifier(conn, (void *)puid,tagtype); + SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype); break; } case SMB_ACL_GROUP_OBJ: @@ -1740,7 +2125,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ break; case SMB_ACL_GROUP: { - gid_t *pgid = (gid_t *)conn->vfs_ops.sys_acl_get_qualifier(conn, entry); + gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); if (pgid == NULL) { DEBUG(0,("canonicalise_acl: Failed to get gid.\n")); continue; @@ -1748,7 +2133,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ gid_to_sid( &sid, *pgid); unix_ug.gid = *pgid; owner_type = GID_ACE; - conn->vfs_ops.sys_acl_free_qualifier(conn, (void *)pgid,tagtype); + SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype); break; } case SMB_ACL_MASK: @@ -1779,6 +2164,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ ace->trustee = sid; ace->unix_ug = unix_ug; ace->owner_type = owner_type; + ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT)); DLIST_ADD(list_head, ace); } @@ -1790,14 +2176,12 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False)) goto fail; - arrange_posix_perms(fsp->fsp_name,&list_head ); - /* * Now go through the list, masking the permissions with the * acl_mask. Ensure all DENY Entries are at the start of the list. */ - DEBUG(10,("canonicalise_acl: ace entries before arrange :\n")); + DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" )); for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) { next_ace = ace->next; @@ -1815,6 +2199,8 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ } } + arrange_posix_perms(fsp->fsp_name,&list_head ); + print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head ); return list_head; @@ -1833,7 +2219,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau { connection_struct *conn = fsp->conn; BOOL ret = False; - SMB_ACL_T the_acl = conn->vfs_ops.sys_acl_init(conn, (int)count_canon_ace_list(the_ace) + 1); + SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1); canon_ace *p_ace; int i; SMB_ACL_ENTRY_T mask_entry; @@ -1891,7 +2277,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau * Get the entry for this ACE. */ - if (conn->vfs_ops.sys_acl_create_entry(conn, &the_acl, &the_entry) == -1) { + if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) { DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n", i, strerror(errno) )); goto done; @@ -1917,7 +2303,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau * First tell the entry what type of ACE this is. */ - if (conn->vfs_ops.sys_acl_set_tag_type(conn, the_entry, p_ace->type) == -1) { + if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) { DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n", i, strerror(errno) )); goto done; @@ -1929,7 +2315,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau */ if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) { - if (conn->vfs_ops.sys_acl_set_qualifier(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) { + if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) { DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n", i, strerror(errno) )); goto done; @@ -1940,7 +2326,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau * Convert the mode_t perms in the canon_ace to a POSIX permset. */ - if (conn->vfs_ops.sys_acl_get_permset(conn, the_entry, &the_permset) == -1) { + if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) { DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n", i, strerror(errno) )); goto done; @@ -1956,7 +2342,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau * ..and apply them to the entry. */ - if (conn->vfs_ops.sys_acl_set_permset(conn, the_entry, the_permset) == -1) { + if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) { DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n", i, strerror(errno) )); goto done; @@ -1964,20 +2350,21 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau if( DEBUGLVL( 10 )) print_canon_ace( p_ace, i); + } if (needs_mask && !got_mask_entry) { - if (conn->vfs_ops.sys_acl_create_entry(conn, &the_acl, &mask_entry) == -1) { + if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) { DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) )); goto done; } - if (conn->vfs_ops.sys_acl_set_tag_type(conn, mask_entry, SMB_ACL_MASK) == -1) { + if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) { DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) )); goto done; } - if (conn->vfs_ops.sys_acl_get_permset(conn, mask_entry, &mask_permset) == -1) { + if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) { DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) )); goto done; } @@ -1987,7 +2374,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau goto done; } - if (conn->vfs_ops.sys_acl_set_permset(conn, mask_entry, mask_permset) == -1) { + if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) { DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) )); goto done; } @@ -1997,7 +2384,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau * Check if the ACL is valid. */ - if (conn->vfs_ops.sys_acl_valid(conn, the_acl) == -1) { + if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) { DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n", the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file", strerror(errno) )); @@ -2009,7 +2396,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau */ if(default_ace || fsp->is_directory || fsp->fd == -1) { - if (conn->vfs_ops.sys_acl_set_file(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) { + if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) { /* * Some systems allow all the above calls and only fail with no ACL support * when attempting to apply the acl. HPUX with HFS is an example of this. JRA. @@ -2028,7 +2415,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau goto done; } } else { - if (conn->vfs_ops.sys_acl_set_fd(fsp, fsp->fd, the_acl) == -1) { + if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, the_acl) == -1) { /* * Some systems allow all the above calls and only fail with no ACL support * when attempting to apply the acl. HPUX with HFS is an example of this. JRA. @@ -2052,7 +2439,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau done: if (the_acl != NULL) - conn->vfs_ops.sys_acl_free_acl(conn, the_acl); + SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl); return ret; } @@ -2083,8 +2470,8 @@ SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl) if (!the_acl) return NULL; - if (conn->vfs_ops.sys_acl_get_entry(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) { - conn->vfs_ops.sys_acl_free_acl(conn, the_acl); + if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) { + SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl); return NULL; } return the_acl; @@ -2165,16 +2552,6 @@ posix perms.\n", fsp->fsp_name )); return True; } -static int nt_ace_comp( SEC_ACE *a1, SEC_ACE *a2) -{ - if (a1->type == a2->type) - return 0; - - if (a1->type == SEC_ACE_TYPE_ACCESS_DENIED && a2->type == SEC_ACE_TYPE_ACCESS_ALLOWED) - return -1; - return 1; -} - /**************************************************************************** Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and a normal POSIX acl. Win2k needs these split acls re-merging into one ACL @@ -2188,24 +2565,51 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces) for (i = 0; i < num_aces; i++) { for (j = i+1; j < num_aces; j++) { + uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE); + uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE); + BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False; + BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False; + /* We know the lower number ACE's are file entries. */ if ((nt_ace_list[i].type == nt_ace_list[j].type) && (nt_ace_list[i].size == nt_ace_list[j].size) && (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) && sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) && - (nt_ace_list[i].flags == 0) && - (nt_ace_list[j].flags == (SEC_ACE_FLAG_OBJECT_INHERIT| - SEC_ACE_FLAG_CONTAINER_INHERIT| - SEC_ACE_FLAG_INHERIT_ONLY))) { + (i_inh == j_inh) && + (i_flags_ni == 0) && + (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT| + SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY))) { /* - * These are identical except for the flags. - * Merge the inherited ACE onto the non-inherited ACE. + * W2K wants to have access allowed zero access ACE's + * at the end of the list. If the mask is zero, merge + * the non-inherited ACE onto the inherited ACE. */ - nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT; - if (num_aces - j - 1 > 0) - memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) * - sizeof(SEC_ACE)); + if (nt_ace_list[i].info.mask == 0) { + nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| + (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0); + if (num_aces - i - 1 > 0) + memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) * + sizeof(SEC_ACE)); + + DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n", + (unsigned int)i, (unsigned int)j )); + } else { + /* + * These are identical except for the flags. + * Merge the inherited ACE onto the non-inherited ACE. + */ + + nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| + (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0); + if (num_aces - j - 1 > 0) + memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) * + sizeof(SEC_ACE)); + + DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n", + (unsigned int)j, (unsigned int)i )); + } num_aces--; break; } @@ -2221,7 +2625,7 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces) the UNIX style get ACL. ****************************************************************************/ -size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) +size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) { extern DOM_SID global_sid_Builtin_Administrators; extern DOM_SID global_sid_Builtin_Users; @@ -2242,7 +2646,9 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) canon_ace *file_ace = NULL; canon_ace *dir_ace = NULL; size_t num_profile_acls = 0; - + struct pai_val *pal = NULL; + SEC_DESC *psd = NULL; + *ppdesc = NULL; DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name )); @@ -2250,40 +2656,42 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) if(fsp->is_directory || fsp->fd == -1) { /* Get the stat struct for the owner info. */ - if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) { + if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) { return 0; } /* * Get the ACL from the path. */ - posix_acl = conn->vfs_ops.sys_acl_get_file(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS); + posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS); /* * If it's a directory get the default POSIX ACL. */ if(fsp->is_directory) { - dir_acl = conn->vfs_ops.sys_acl_get_file(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT); + dir_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT); dir_acl = free_empty_sys_acl(conn, dir_acl); } } else { /* Get the stat struct for the owner info. */ - if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) { + if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) { return 0; } /* * Get the ACL from the fd. */ - posix_acl = conn->vfs_ops.sys_acl_get_fd(fsp, fsp->fd); + posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd); } DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n", posix_acl ? "present" : "absent", dir_acl ? "present" : "absent" )); + pal = load_inherited_info(fsp); + /* * Get the owner, group and world SIDs. */ @@ -2297,179 +2705,171 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) create_file_sids(&sbuf, &owner_sid, &group_sid); } - /* - * In the optimum case Creator Owner and Creator Group would be used for - * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this - * would lead to usability problems under Windows: The Creator entries - * are only available in browse lists of directories and not for files; - * additionally the identity of the owning group couldn't be determined. - * We therefore use those identities only for Default ACLs. - */ - - /* Create the canon_ace lists. */ - file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, SMB_ACL_TYPE_ACCESS ); + if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) { - /* We must have *some* ACLS. */ + /* + * In the optimum case Creator Owner and Creator Group would be used for + * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this + * would lead to usability problems under Windows: The Creator entries + * are only available in browse lists of directories and not for files; + * additionally the identity of the owning group couldn't be determined. + * We therefore use those identities only for Default ACLs. + */ - if (count_canon_ace_list(file_ace) == 0) { - DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name )); - return 0; - } + /* Create the canon_ace lists. */ + file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS ); - if (fsp->is_directory && dir_acl) { - dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf, - &global_sid_Creator_Owner, - &global_sid_Creator_Group, SMB_ACL_TYPE_DEFAULT ); - } + /* We must have *some* ACLS. */ + + if (count_canon_ace_list(file_ace) == 0) { + DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name )); + return 0; + } - /* - * Create the NT ACE list from the canonical ace lists. - */ + if (fsp->is_directory && dir_acl) { + dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf, + &global_sid_Creator_Owner, + &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT ); + } - { - canon_ace *ace; - int nt_acl_type; - int i; + /* + * Create the NT ACE list from the canonical ace lists. + */ - if (nt4_compatible_acls() && dir_ace) { - /* - * NT 4 chokes if an ACL contains an INHERIT_ONLY entry - * but no non-INHERIT_ONLY entry for one SID. So we only - * remove entries from the Access ACL if the - * corresponding Default ACL entries have also been - * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP - * are exceptions. We can do nothing - * intelligent if the Default ACL contains entries that - * are not also contained in the Access ACL, so this - * case will still fail under NT 4. - */ + { + canon_ace *ace; + int nt_acl_type; + int i; - ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL); - if (ace && !ace->perms) { - DLIST_REMOVE(dir_ace, ace); - SAFE_FREE(ace); + if (nt4_compatible_acls() && dir_ace) { + /* + * NT 4 chokes if an ACL contains an INHERIT_ONLY entry + * but no non-INHERIT_ONLY entry for one SID. So we only + * remove entries from the Access ACL if the + * corresponding Default ACL entries have also been + * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP + * are exceptions. We can do nothing + * intelligent if the Default ACL contains entries that + * are not also contained in the Access ACL, so this + * case will still fail under NT 4. + */ - ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL); + ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL); if (ace && !ace->perms) { - DLIST_REMOVE(file_ace, ace); + DLIST_REMOVE(dir_ace, ace); SAFE_FREE(ace); + + ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL); + if (ace && !ace->perms) { + DLIST_REMOVE(file_ace, ace); + SAFE_FREE(ace); + } } - } - /* - * WinNT doesn't usually have Creator Group - * in browse lists, so we send this entry to - * WinNT even if it contains no relevant - * permissions. Once we can add - * Creator Group to browse lists we can - * re-enable this. - */ + /* + * WinNT doesn't usually have Creator Group + * in browse lists, so we send this entry to + * WinNT even if it contains no relevant + * permissions. Once we can add + * Creator Group to browse lists we can + * re-enable this. + */ #if 0 - ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL); - if (ace && !ace->perms) { - DLIST_REMOVE(dir_ace, ace); - SAFE_FREE(ace); - } + ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL); + if (ace && !ace->perms) { + DLIST_REMOVE(dir_ace, ace); + SAFE_FREE(ace); + } #endif - ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL); - if (ace && !ace->perms) { - DLIST_REMOVE(file_ace, ace); - SAFE_FREE(ace); - } - } else { - - ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL); - if (ace && !ace->perms) { - DLIST_REMOVE(dir_ace, ace); - SAFE_FREE(ace); - } - ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL); - if (ace && !ace->perms) { - DLIST_REMOVE(dir_ace, ace); - SAFE_FREE(ace); + ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL); + if (ace && !ace->perms) { + DLIST_REMOVE(file_ace, ace); + SAFE_FREE(ace); + } } - } - - num_acls = count_canon_ace_list(file_ace); - num_dir_acls = count_canon_ace_list(dir_ace); - - /* Allocate the ace list. */ - 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; - } - memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) ); - - /* - * Create the NT ACE list from the canonical ace lists. - */ + num_acls = count_canon_ace_list(file_ace); + num_dir_acls = count_canon_ace_list(dir_ace); - ace = file_ace; + /* Allocate the ace list. */ + 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; + } - for (i = 0; i < num_acls; i++, ace = ace->next) { - SEC_ACCESS acc; + memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) ); + + /* + * Create the NT ACE list from the canonical ace lists. + */ + + ace = file_ace; - acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); - init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, 0); - } + for (i = 0; i < num_acls; i++, ace = ace->next) { + SEC_ACCESS acc; - /* 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; + acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); + init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0); + } - 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); - } + /* 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; - ace = dir_ace; + 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); + } - for (i = 0; i < num_dir_acls; i++, ace = ace->next) { - SEC_ACCESS acc; + ace = dir_ace; - acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); - init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, - SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); - } + for (i = 0; i < num_dir_acls; i++, ace = ace->next) { + SEC_ACCESS acc; + + acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); + init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, + SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY| + (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 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; + /* 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); - } - - /* - * Merge POSIX default ACLs and normal ACLs into one NT ACE. - * Win2K needs this to get the inheritance correct when replacing ACLs - * on a directory tree. Based on work by Jim @ IBM. - */ + 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|0); + } - num_aces = merge_default_aces(nt_ace_list, num_aces); + /* + * Merge POSIX default ACLs and normal ACLs into one NT ACE. + * Win2K needs this to get the inheritance correct when replacing ACLs + * on a directory tree. Based on work by Jim @ IBM. + */ - /* - * Sort to force deny entries to the front. - */ + num_aces = merge_default_aces(nt_ace_list, num_aces); - if (num_aces) - qsort( nt_ace_list, num_aces, sizeof(nt_ace_list[0]), QSORT_CAST nt_ace_comp); - } + } - if (num_aces) { - if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) { - DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n")); - goto done; + if (num_aces) { + if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) { + DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n")); + goto done; + } } - } + } /* security_info & DACL_SECURITY_INFORMATION */ - *ppdesc = make_standard_sec_desc( main_loop_talloc_get(), &owner_sid, &group_sid, psa, &sd_size); + psd = make_standard_sec_desc( main_loop_talloc_get(), + (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL, + (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL, + psa, + &sd_size); - if(!*ppdesc) { + if(!psd) { DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n")); sd_size = 0; } else { @@ -2482,17 +2882,24 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) * any ACEs that are inherited dynamically. The DACL_PROTECTED * flag doesn't seem to bother Windows NT. */ - (*ppdesc)->type |= SE_DESC_DACL_PROTECTED; + if (get_protected_flag(pal)) + psd->type |= SE_DESC_DACL_PROTECTED; } + if (psd->dacl) + dacl_sort_into_canonical_order(psd->dacl->ace, (unsigned int)psd->dacl->num_aces); + + *ppdesc = psd; + done: if (posix_acl) - conn->vfs_ops.sys_acl_free_acl(conn, posix_acl); + SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); if (dir_acl) - conn->vfs_ops.sys_acl_free_acl(conn, dir_acl); + SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl); free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); + free_inherited_info(pal); SAFE_FREE(nt_ace_list); return sd_size; @@ -2514,14 +2921,14 @@ static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_ SMB_STRUCT_STAT st; /* try the direct way first */ - ret = vfs_chown(conn, fname, uid, gid); + ret = SMB_VFS_CHOWN(conn, fname, uid, gid); if (ret == 0) return 0; if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn))) return -1; - if (vfs_stat(conn,fname,&st)) + if (SMB_VFS_STAT(conn,fname,&st)) return -1; fsp = open_file_fchmod(conn,fname,&st); @@ -2536,7 +2943,7 @@ static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_ become_root(); /* Keep the current file gid the same. */ - ret = vfswrap_fchown(fsp, fsp->fd, uid, (gid_t)-1); + ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1); unbecome_root(); close_file_fchmod(fsp); @@ -2579,10 +2986,10 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) */ if(fsp->is_directory || fsp->fd == -1) { - if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) + if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) return False; } else { - if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) + if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) return False; } @@ -2628,7 +3035,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) */ if(fsp->is_directory) { - if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) { + if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) { return False; } } else { @@ -2636,9 +3043,9 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) int ret; if(fsp->fd == -1) - ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf); + ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf); else - ret = vfs_fstat(fsp,fsp->fd,&sbuf); + ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf); if(ret != 0) return False; @@ -2706,7 +3113,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) * No default ACL - delete one if it exists. */ - if (conn->vfs_ops.sys_acl_delete_def_file(conn, fsp->fsp_name) == -1) { + if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) { DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno))); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); @@ -2715,6 +3122,10 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) } } + if (acl_set_support) + store_inheritance_attributes(fsp, file_ace_list, dir_ace_list, + (psd->type & SE_DESC_DACL_PROTECTED) ? True : False); + /* * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod. */ @@ -2735,7 +3146,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n", fsp->fsp_name, (unsigned int)posix_perms )); - if(conn->vfs_ops.chmod(conn,fsp->fsp_name, posix_perms) == -1) { + if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) { DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n", fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) )); free_canon_ace_list(file_ace_list); @@ -2777,7 +3188,7 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo SMB_ACL_ENTRY_T entry; int num_entries = 0; - while ( conn->vfs_ops.sys_acl_get_entry(conn, posix_acl, entry_id, &entry) == 1) { + while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) { SMB_ACL_TAG_T tagtype; SMB_ACL_PERMSET_T permset; mode_t perms; @@ -2786,10 +3197,10 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo if (entry_id == SMB_ACL_FIRST_ENTRY) entry_id = SMB_ACL_NEXT_ENTRY; - if (conn->vfs_ops.sys_acl_get_tag_type(conn, entry, &tagtype) == -1) + if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) return -1; - if (conn->vfs_ops.sys_acl_get_permset(conn, entry, &permset) == -1) + if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) return -1; num_entries++; @@ -2820,7 +3231,7 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo if (map_acl_perms_to_permset(conn, perms, &permset) == -1) return -1; - if (conn->vfs_ops.sys_acl_set_permset(conn, entry, permset) == -1) + if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1) return -1; } @@ -2846,17 +3257,17 @@ static int copy_access_acl(connection_struct *conn, const char *from, const char SMB_ACL_T posix_acl = NULL; int ret = -1; - if ((posix_acl = conn->vfs_ops.sys_acl_get_file(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL) + if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL) return -1; if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1) goto done; - ret = conn->vfs_ops.sys_acl_set_file(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl); + ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl); done: - conn->vfs_ops.sys_acl_free_acl(conn, posix_acl); + SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); return ret; } @@ -2898,17 +3309,17 @@ int fchmod_acl(files_struct *fsp, int fd, mode_t mode) SMB_ACL_T posix_acl = NULL; int ret = -1; - if ((posix_acl = conn->vfs_ops.sys_acl_get_fd(fsp, fd)) == NULL) + if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL) return -1; if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1) goto done; - ret = conn->vfs_ops.sys_acl_set_fd(fsp, fd, posix_acl); + ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl); done: - conn->vfs_ops.sys_acl_free_acl(conn, posix_acl); + SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); return ret; } @@ -2918,14 +3329,14 @@ int fchmod_acl(files_struct *fsp, int fd, mode_t mode) BOOL directory_has_default_acl(connection_struct *conn, const char *fname) { - SMB_ACL_T dir_acl = conn->vfs_ops.sys_acl_get_file( conn, fname, SMB_ACL_TYPE_DEFAULT); + SMB_ACL_T dir_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT); BOOL has_acl = False; SMB_ACL_ENTRY_T entry; - if (dir_acl != NULL && (conn->vfs_ops.sys_acl_get_entry(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) + if (dir_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) has_acl = True; if (dir_acl) - conn->vfs_ops.sys_acl_free_acl(conn, dir_acl); + SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl); return has_acl; } diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c index 5b843bd09a..91c952aa90 100644 --- a/source3/smbd/quotas.c +++ b/source3/smbd/quotas.c @@ -27,6 +27,15 @@ #include "includes.h" +#ifndef HAVE_SYS_QUOTAS + +/* just a quick hack because sysquotas.h is included before linux/quota.h */ +#ifdef QUOTABLOCK_SIZE +#undef QUOTABLOCK_SIZE +#endif + +#ifdef WITH_QUOTAS + #if defined(VXFS_QUOTA) /* @@ -1112,3 +1121,108 @@ BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_B #endif /* SUNOS5 || ... */ #endif /* VXFS_QUOTA */ + +#else /* WITH_QUOTAS */ + +BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) +{ + (*bsize) = 512; /* This value should be ignored */ + + /* And just to be sure we set some values that hopefully */ + /* will be larger that any possible real-world value */ + (*dfree) = (SMB_BIG_UINT)-1; + (*dsize) = (SMB_BIG_UINT)-1; + + /* As we have select not to use quotas, allways fail */ + return False; +} +#endif /* WITH_QUOTAS */ + +#else /* HAVE_SYS_QUOTAS */ +/* wrapper to the new sys_quota interface + this file should be removed later + */ +BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize) +{ + int r; + SMB_DISK_QUOTA D; + unid_t id; + + id.uid = geteuid(); + + r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D); + + /* Use softlimit to determine disk space, except when it has been exceeded */ + *bsize = D.bsize; + if (r == -1) { + if (errno == EDQUOT) { + *dfree =0; + *dsize =D.curblocks; + return (True); + } else { + goto try_group_quota; + } + } + + /* Use softlimit to determine disk space, except when it has been exceeded */ + if ( + (D.softlimit && D.curblocks >= D.softlimit) || + (D.hardlimit && D.curblocks >= D.hardlimit) || + (D.isoftlimit && D.curinodes >= D.isoftlimit) || + (D.ihardlimit && D.curinodes>=D.ihardlimit) + ) { + *dfree = 0; + *dsize = D.curblocks; + } else if (D.softlimit==0 && D.hardlimit==0) { + goto try_group_quota; + } else { + if (D.softlimit == 0) + D.softlimit = D.hardlimit; + *dfree = D.softlimit - D.curblocks; + *dsize = D.softlimit; + } + + return True; + +try_group_quota: +#ifdef HAVE_GROUP_QUOTA + id.gid = getegid(); + + r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D); + + /* Use softlimit to determine disk space, except when it has been exceeded */ + *bsize = D.bsize; + if (r == -1) { + if (errno == EDQUOT) { + *dfree =0; + *dsize =D.curblocks; + return (True); + } else { + return False; + } + } + + /* Use softlimit to determine disk space, except when it has been exceeded */ + if ( + (D.softlimit && D.curblocks >= D.softlimit) || + (D.hardlimit && D.curblocks >= D.hardlimit) || + (D.isoftlimit && D.curinodes >= D.isoftlimit) || + (D.ihardlimit && D.curinodes>=D.ihardlimit) + ) { + *dfree = 0; + *dsize = D.curblocks; + } else if (D.softlimit==0 && D.hardlimit==0) { + return False; + } else { + if (D.softlimit == 0) + D.softlimit = D.hardlimit; + *dfree = D.softlimit - D.curblocks; + *dsize = D.softlimit; + } + + return (True); +#else /* HAVE_GROUP_QUOTA */ + return False; +#endif /* HAVE_GROUP_QUOTA */ +} +#endif /* HAVE_SYS_QUOTAS */ diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index b2dab2fea2..e7f01ad02f 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -39,7 +39,7 @@ unsigned int smb_echo_count = 0; extern BOOL global_encrypted_passwords_negotiated; /**************************************************************************** - Reply to an special message. + Reply to a special message. ****************************************************************************/ int reply_special(char *inbuf,char *outbuf) @@ -148,7 +148,7 @@ int reply_tcon(connection_struct *conn, const char *service; pstring service_buf; pstring password; - fstring dev; + pstring dev; int outsize = 0; uint16 vuid = SVAL(inbuf,smb_uid); int pwlen=0; @@ -204,7 +204,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt { fstring service; DATA_BLOB password; - + /* what the cleint thinks the device is */ fstring client_devicetype; /* what the server tells the client the share represents */ @@ -283,15 +283,16 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt set_message_end(outbuf,p); } else { /* NT sets the fstype of IPC$ to the null string */ - const char *fsname = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn)); + const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn)); set_message(outbuf,3,0,True); - - p = smb_buf(outbuf); + + p = smb_buf(outbuf); p += srvstr_push(outbuf, p, server_devicetype, -1, - STR_TERMINATE|STR_ASCII); - p += srvstr_push(outbuf, p, fsname, -1, - STR_TERMINATE); + STR_TERMINATE|STR_ASCII); + p += srvstr_push(outbuf, p, fstype, -1, + STR_TERMINATE); + set_message_end(outbuf,p); /* what does setting this bit do? It is set by NT4 and @@ -398,7 +399,7 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size mode = SVAL(inbuf,smb_vwv0); if (check_name(name,conn)) { - if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0) + if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,name,&sbuf) == 0) if (!(ok = S_ISDIR(sbuf.st_mode))) errno = ENOTDIR; } @@ -457,7 +458,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size } else { unix_convert(fname,conn,0,&bad_path,&sbuf); if (check_name(fname,conn)) { - if (VALID_STAT(sbuf) || vfs_stat(conn,fname,&sbuf) == 0) { + if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,fname,&sbuf) == 0) { mode = dos_mode(conn,fname,&sbuf); size = sbuf.st_size; mtime = sbuf.st_mtime; @@ -552,7 +553,7 @@ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz SMB_BIG_UINT dfree,dsize,bsize; START_PROFILE(SMBdskattr); - conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize); + SMB_VFS_DISK_FREE(conn,".",True,&bsize,&dfree,&dsize); outsize = set_message(outbuf,5,0,True); @@ -1127,7 +1128,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return(UNIXERROR(ERRDOS,ERRnoaccess)); } - vfs_stat(conn,fname,&sbuf); + SMB_VFS_STAT(conn,fname,&sbuf); /* Open file in dos compatibility share mode. */ /* We should fail if file does not exist. */ @@ -1226,7 +1227,7 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) if (!CAN_WRITE(conn)) return NT_STATUS_MEDIA_WRITE_PROTECTED; - if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) + if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) return NT_STATUS_OBJECT_NAME_NOT_FOUND; fmode = dos_mode(conn,fname,&sbuf); @@ -1312,7 +1313,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) error = can_delete(directory,conn,dirtype); if (!NT_STATUS_IS_OK(error)) return error; - if (vfs_unlink(conn,directory) == 0) { + if (SMB_VFS_UNLINK(conn,directory) == 0) { count++; } } else { @@ -1342,7 +1343,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); error = can_delete(fname,conn,dirtype); if (!NT_STATUS_IS_OK(error)) continue; - if (vfs_unlink(conn,fname) == 0) count++; + if (SMB_VFS_UNLINK(conn,fname) == 0) count++; DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); } CloseDir(dirptr); @@ -1428,7 +1429,7 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st header.length = 4; header.free = NULL; - if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) { + if ( SMB_VFS_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. @@ -1463,6 +1464,7 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize) { + extern struct current_user current_user; ssize_t maxcount,mincount; size_t nread = 0; SMB_OFF_T startpos; @@ -1552,7 +1554,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s if (size < sizeneeded) { SMB_STRUCT_STAT st; - if (vfs_fstat(fsp,fsp->fd,&st) == 0) + if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0) size = st.st_size; if (!fsp->can_write) fsp->size = size; @@ -1721,7 +1723,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length SMB_STRUCT_STAT sbuf; DATA_BLOB header; - if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1) + if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1) return(UNIXERROR(ERRDOS,ERRnoaccess)); if (startpos > sbuf.st_size) @@ -1748,7 +1750,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length header.length = data - outbuf; header.free = NULL; - if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) { + if ( SMB_VFS_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. @@ -2260,7 +2262,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int break; } - if((res = conn->vfs_ops.lseek(fsp,fsp->fd,startpos,umode)) == -1) { + if((res = SMB_VFS_LSEEK(fsp,fsp->fd,startpos,umode)) == -1) { /* * Check for the special case where a seek before the start * of the file sets the offset to zero. Added in the CIFS spec, @@ -2272,7 +2274,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int if(umode == SEEK_CUR) { - if((current_pos = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1) { + if((current_pos = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_CUR)) == -1) { END_PROFILE(SMBlseek); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -2283,7 +2285,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int SMB_STRUCT_STAT sbuf; - if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1) { + if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1) { END_PROFILE(SMBlseek); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -2292,7 +2294,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int } if(current_pos < 0) - res = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_SET); + res = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_SET); } if(res == -1) { @@ -2360,6 +2362,7 @@ int reply_exit(connection_struct *conn, int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { + extern struct current_user current_user; int outsize = 0; time_t mtime; int32 eclass = 0, err = 0; @@ -2380,7 +2383,7 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, * We can only use CHECK_FSP if we know it's not a directory. */ - if(!fsp || (fsp->conn != conn)) { + if(!fsp || (fsp->conn != conn) || (fsp->vuid != current_user.vuid)) { END_PROFILE(SMBclose); return ERROR_DOS(ERRDOS,ERRbadfid); } @@ -2827,7 +2830,7 @@ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory) unix_convert(directory,conn,0,&bad_path,&sbuf); if (check_name(directory, conn)) - ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); + ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory)); if (ret == -1) { NTSTATUS nterr = set_bad_path_error(errno, bad_path); @@ -2898,7 +2901,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory) pstrcat(fullname, "/"); pstrcat(fullname, dname); - if(conn->vfs_ops.lstat(conn,fullname, &st) != 0) { + if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) { ret = True; break; } @@ -2908,11 +2911,11 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory) ret = True; break; } - if(vfs_rmdir(conn,fullname) != 0) { + if(SMB_VFS_RMDIR(conn,fullname) != 0) { ret = True; break; } - } else if(vfs_unlink(conn,fullname) != 0) { + } else if(SMB_VFS_UNLINK(conn,fullname) != 0) { ret = True; break; } @@ -2929,7 +2932,7 @@ BOOL rmdir_internals(connection_struct *conn, char *directory) { BOOL ok; - ok = (vfs_rmdir(conn,directory) == 0); + ok = (SMB_VFS_RMDIR(conn,directory) == 0); if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) { /* * Check to see if the only thing in this directory are @@ -2971,21 +2974,21 @@ BOOL rmdir_internals(connection_struct *conn, char *directory) pstrcat(fullname, "/"); pstrcat(fullname, dname); - if(conn->vfs_ops.lstat(conn,fullname, &st) != 0) + if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) break; if(st.st_mode & S_IFDIR) { if(lp_recursive_veto_delete(SNUM(conn))) { if(recursive_rmdir(conn, fullname) != 0) break; } - if(vfs_rmdir(conn,fullname) != 0) + if(SMB_VFS_RMDIR(conn,fullname) != 0) break; - } else if(vfs_unlink(conn,fullname) != 0) + } else if(SMB_VFS_UNLINK(conn,fullname) != 0) break; } CloseDir(dirptr); /* Retry the rmdir */ - ok = (vfs_rmdir(conn,directory) == 0); + ok = (SMB_VFS_RMDIR(conn,directory) == 0); } else { CloseDir(dirptr); } @@ -3104,7 +3107,7 @@ static BOOL resolve_wildcards(const char *name1, char *name2) if (ext2[0]) { snprintf(pname2, available_space - 1, "%s.%s", root2, ext2); } else { - StrnCpy(pname2, root2, available_space - 1); + pstrcpy_base(pname2, root2, name2); } return(True); @@ -3281,7 +3284,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", return NT_STATUS_OBJECT_NAME_COLLISION; } - if(conn->vfs_ops.rename(conn,directory, newname) == 0) { + if(SMB_VFS_RENAME(conn,directory, newname) == 0) { DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n", directory,newname)); return NT_STATUS_OK; @@ -3348,7 +3351,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", continue; } - if (!conn->vfs_ops.rename(conn,fname,destname)) + if (!SMB_VFS_RENAME(conn,fname,destname)) count++; DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); } @@ -3442,7 +3445,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, if (!target_is_directory && count) ofun = FILE_EXISTS_OPEN; - if (vfs_stat(conn,dest,&sbuf2) == -1) + if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1) ZERO_STRUCTP(&sbuf2); fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY), @@ -3454,7 +3457,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, } if ((ofun&3) == 1) { - if(conn->vfs_ops.lseek(fsp2,fsp2->fd,0,SEEK_END) == -1) { + if(SMB_VFS_LSEEK(fsp2,fsp2->fd,0,SEEK_END) == -1) { DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) )); /* * Stop the copy from occurring. @@ -3938,7 +3941,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+999)/1000); + lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+499)/500); /* Now do any requested locks */ data += ((large_file_format ? 20 : 10)*num_ulocks); @@ -4382,8 +4385,9 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, SIVAL(outbuf,smb_vwv6,0); SIVAL(outbuf,smb_vwv8,0); } else { + uint32 allocation_size = get_allocation_size(fsp, &sbuf); SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size); - SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024)); + SIVAL(outbuf,smb_vwv8,allocation_size); } SSVAL(outbuf,smb_vwv10, mode); diff --git a/source3/smbd/server.c b/source3/smbd/server.c index c24fc5134d..453ff54e4b 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -634,6 +634,12 @@ static BOOL init_structs(void ) main program. ****************************************************************************/ +/* Declare prototype for build_options() to avoid having to run it through + mkproto.h. Mixing $(builddir) and $(srcdir) source files in the current + prototype generation system is too complicated. */ + +void build_options(BOOL screen); + int main(int argc,const char *argv[]) { /* shall I run as a daemon */ @@ -836,29 +842,24 @@ static BOOL init_structs(void ) if (!init_registry()) exit(1); - if(!initialize_password_db(False)) - exit(1); + /* Initialise the password backed before the global_sam_sid + to ensure that we fetch from ldap before we make a domain sid up */ - if (!idmap_init()) + if(!initialize_password_db(False)) exit(1); - if (!idmap_init_wellknown_sids()) + if(!get_global_sam_sid()) { + DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n")); exit(1); + } static_init_rpc; init_modules(); - uni_group_cache_init(); /* Non-critical */ - /* possibly reload the services file. */ reload_services(True); - if(!get_global_sam_sid()) { - DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n")); - exit(1); - } - if (!init_account_policy()) { DEBUG(0,("Could not open account policy tdb.\n")); exit(1); @@ -877,10 +878,6 @@ static BOOL init_structs(void ) if (!init_change_notify()) exit(1); - /* Setup privileges database */ - if (!privilege_init()) - exit(1); - /* re-initialise the timezone */ TimeInit(); @@ -889,7 +886,6 @@ static BOOL init_structs(void ) smbd_process(); - uni_group_cache_shutdown(); namecache_shutdown(); exit_server("normal exit"); return(0); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index c9f5330551..18e0887071 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -237,7 +237,7 @@ static NTSTATUS share_sanity_checks(int snum, fstring dev) } } - strupper(dev); + strupper_m(dev); if (lp_print_ok(snum)) { if (!strequal(dev, "LPT1:")) { @@ -359,13 +359,15 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, guest = True; pass = getpwnam_alloc(guestname); if (!pass) { - DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname)); + DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname)); conn_free(conn); *status = NT_STATUS_NO_SUCH_USER; return NULL; } fstrcpy(user,pass->pw_name); conn->force_user = True; + conn->uid = pass->pw_uid; + conn->gid = pass->pw_gid; string_set(&conn->user,pass->pw_name); passwd_free(&pass); DEBUG(3,("Guest only user %s\n",user)); @@ -704,14 +706,12 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, /* Invoke VFS make connection hook */ - if (conn->vfs_ops.connect) { - if (conn->vfs_ops.connect(conn, lp_servicename(snum), user) < 0) { - DEBUG(0,("make_connection: VFS make connection failed!\n")); - change_to_root_user(); - conn_free(conn); - *status = NT_STATUS_UNSUCCESSFUL; - return NULL; - } + if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) { + DEBUG(0,("make_connection: VFS make connection failed!\n")); + change_to_root_user(); + conn_free(conn); + *status = NT_STATUS_UNSUCCESSFUL; + return NULL; } /* we've finished with the user stuff - go back to root */ @@ -828,7 +828,7 @@ connection_struct *make_connection(const char *service_in, DATA_BLOB password, fstrcpy(service, service_in); - strlower(service); + strlower_m(service); snum = find_service(service); @@ -872,13 +872,8 @@ void close_cnum(connection_struct *conn, uint16 vuid) get_remote_machine_name(),conn->client_address, lp_servicename(SNUM(conn)))); - if (conn->vfs_ops.disconnect != NULL) { - - /* Call VFS disconnect hook */ - - conn->vfs_ops.disconnect(conn); - - } + /* Call VFS disconnect hook */ + SMB_VFS_DISCONNECT(conn); yield_connection(conn, lp_servicename(SNUM(conn))); diff --git a/source3/smbd/session.c b/source3/smbd/session.c index 07a9504234..4d8826d332 100644 --- a/source3/smbd/session.c +++ b/source3/smbd/session.c @@ -33,6 +33,8 @@ BOOL session_claim(user_struct *vuser) { int i = 0; TDB_DATA data; + struct sockaddr sa; + struct in_addr *client_ip; struct sessionid sessionid; uint32 pid = (uint32)sys_getpid(); TDB_DATA key; @@ -64,7 +66,6 @@ BOOL session_claim(user_struct *vuser) data.dptr = NULL; data.dsize = 0; -#if WITH_UTMP if (lp_utmp()) { for (i=1;i<MAX_SESSION_ID;i++) { slprintf(keystr, sizeof(keystr)-1, "ID/%d", i); @@ -82,7 +83,6 @@ BOOL session_claim(user_struct *vuser) slprintf(sessionid.id_str, sizeof(sessionid.id_str)-1, SESSION_UTMP_TEMPLATE, i); tdb_store_flag = TDB_MODIFY; } else -#endif { slprintf(keystr, sizeof(keystr)-1, "ID/%lu/%u", (long unsigned int)sys_getpid(), @@ -117,6 +117,8 @@ BOOL session_claim(user_struct *vuser) fstrcpy(sessionid.remote_machine, get_remote_machine_name()); fstrcpy(sessionid.ip_addr, client_addr()); + client_ip = client_inaddr(&sa); + if (!smb_pam_claim_session(sessionid.username, sessionid.id_str, sessionid.hostname)) { DEBUG(1,("pam_session rejected the session for %s [%s]\n", sessionid.username, sessionid.id_str)); @@ -133,12 +135,11 @@ BOOL session_claim(user_struct *vuser) return False; } -#if WITH_UTMP if (lp_utmp()) { sys_utmp_claim(sessionid.username, sessionid.hostname, + client_ip, sessionid.id_str, sessionid.id_num); } -#endif vuser->session_keystr = strdup(keystr); if (!vuser->session_keystr) { @@ -153,7 +154,8 @@ void session_yield(user_struct *vuser) { TDB_DATA dbuf; struct sessionid sessionid; - TDB_DATA key; + struct in_addr *client_ip; + TDB_DATA key; if (!tdb) return; @@ -171,14 +173,15 @@ void session_yield(user_struct *vuser) memcpy(&sessionid, dbuf.dptr, sizeof(sessionid)); + client_ip = interpret_addr2(sessionid.ip_addr); + SAFE_FREE(dbuf.dptr); -#if WITH_UTMP if (lp_utmp()) { sys_utmp_yield(sessionid.username, sessionid.hostname, + client_ip, sessionid.id_str, sessionid.id_num); } -#endif smb_pam_close_session(sessionid.username, sessionid.id_str, sessionid.hostname); diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 2631961739..7d77ed3071 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -53,10 +53,10 @@ static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **serv return status; } - /**************************************************************************** Add the standard 'Samba' signature to the end of the session setup. ****************************************************************************/ + static int add_signature(char *outbuf, char *p) { char *start = p; @@ -72,8 +72,9 @@ static int add_signature(char *outbuf, char *p) } /**************************************************************************** -send a security blob via a session setup reply + Send a security blob via a session setup reply. ****************************************************************************/ + static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf, DATA_BLOB blob, NTSTATUS nt_status) { @@ -101,6 +102,7 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf, /**************************************************************************** Do a 'guest' logon, getting back the ****************************************************************************/ + static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) { struct auth_context *auth_context; @@ -267,12 +269,12 @@ static int reply_spnego_kerberos(connection_struct *conn, } #endif - /**************************************************************************** - send a session setup reply, wrapped in SPNEGO. - get vuid and check first. - end the NTLMSSP exchange context if we are OK/complete fail + Send a session setup reply, wrapped in SPNEGO. + Get vuid and check first. + End the NTLMSSP exchange context if we are OK/complete fail ***************************************************************************/ + static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *outbuf, AUTH_NTLMSSP_STATE **auth_ntlmssp_state, DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status) @@ -326,8 +328,9 @@ static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *outbuf, } /**************************************************************************** -reply to a session setup spnego negotiate packet + Reply to a session setup spnego negotiate packet. ****************************************************************************/ + static int reply_spnego_negotiate(connection_struct *conn, char *inbuf, char *outbuf, @@ -387,11 +390,11 @@ static int reply_spnego_negotiate(connection_struct *conn, /* already replied */ return -1; } - /**************************************************************************** -reply to a session setup spnego auth packet + Reply to a session setup spnego auth packet. ****************************************************************************/ + static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, DATA_BLOB blob1) @@ -425,10 +428,10 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, return -1; } - /**************************************************************************** -reply to a session setup command + Reply to a session setup command. ****************************************************************************/ + static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf, char *outbuf, int length,int bufsize) @@ -509,8 +512,9 @@ static void setup_new_vc_session(void) } /**************************************************************************** -reply to a session setup command + Reply to a session setup command. ****************************************************************************/ + int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, int length,int bufsize) { diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c index 44bae48990..22b8a33a1e 100644 --- a/source3/smbd/statcache.c +++ b/source3/smbd/statcache.c @@ -24,7 +24,6 @@ extern BOOL case_sensitive; - /**************************************************************************** Stat cache code used in unix_convert. *****************************************************************************/ @@ -53,123 +52,126 @@ static hash_table stat_cache; void stat_cache_add( const char *full_orig_name, const char *orig_translated_path) { - stat_cache_entry *scp; - stat_cache_entry *found_scp; - char *translated_path; - size_t translated_path_length; - - char *original_path; - size_t original_path_length; - - hash_element *hash_elem; - - if (!lp_stat_cache()) return; - - /* - * Don't cache trivial valid directory entries. - */ - if((*full_orig_name == '\0') || (strcmp(full_orig_name, ".") == 0) || - (strcmp(full_orig_name, "..") == 0)) - return; - - /* - * If we are in case insentive mode, we don't need to - * store names that need no translation - else, it - * would be a waste. - */ - - if(case_sensitive && (strcmp(full_orig_name, orig_translated_path) == 0)) - return; - - /* - * Remove any trailing '/' characters from the - * translated path. - */ - - translated_path = strdup(orig_translated_path); - if (!translated_path) - return; - - translated_path_length = strlen(translated_path); - - if(translated_path[translated_path_length-1] == '/') { - translated_path[translated_path_length-1] = '\0'; - translated_path_length--; - } - - original_path = strdup(full_orig_name); - if (!original_path) { - SAFE_FREE(translated_path); - return; - } - - original_path_length = strlen(original_path); - - if(original_path[original_path_length-1] == '/') { - original_path[original_path_length-1] = '\0'; - original_path_length--; - } - - if(!case_sensitive) - strupper(original_path); - - if (original_path_length != translated_path_length) { - if (original_path_length < translated_path_length) { - DEBUG(0, ("OOPS - tried to store stat cache entry for werid length paths [%s] %u and [%s] %u)!\n", original_path, original_path_length, translated_path, translated_path_length)); - SAFE_FREE(original_path); - SAFE_FREE(translated_path); - return; - } - - /* we only want to store the first part of original_path, - up to the length of translated_path */ - - original_path[translated_path_length] = '\0'; - original_path_length = translated_path_length; - } - - /* - * Check this name doesn't exist in the cache before we - * add it. - */ - - if ((hash_elem = hash_lookup(&stat_cache, original_path))) { - found_scp = (stat_cache_entry *)(hash_elem->value); - if (strcmp((found_scp->translated_path), orig_translated_path) == 0) { - /* already in hash table */ - SAFE_FREE(original_path); - SAFE_FREE(translated_path); - return; - } - /* hash collision - remove before we re-add */ - hash_remove(&stat_cache, hash_elem); - } + stat_cache_entry *scp; + stat_cache_entry *found_scp; + char *translated_path; + size_t translated_path_length; + + char *original_path; + size_t original_path_length; + + hash_element *hash_elem; + + if (!lp_stat_cache()) + return; + + /* + * Don't cache trivial valid directory entries. + */ + + if((*full_orig_name == '\0') || (strcmp(full_orig_name, ".") == 0) || + (strcmp(full_orig_name, "..") == 0)) + return; + + /* + * If we are in case insentive mode, we don't need to + * store names that need no translation - else, it + * would be a waste. + */ + + if(case_sensitive && (strcmp(full_orig_name, orig_translated_path) == 0)) + return; + + /* + * Remove any trailing '/' characters from the + * translated path. + */ + + translated_path = strdup(orig_translated_path); + if (!translated_path) + return; + + translated_path_length = strlen(translated_path); + + if(translated_path[translated_path_length-1] == '/') { + translated_path[translated_path_length-1] = '\0'; + translated_path_length--; + } + + original_path = strdup(full_orig_name); + if (!original_path) { + SAFE_FREE(translated_path); + return; + } + + original_path_length = strlen(original_path); + + if(original_path[original_path_length-1] == '/') { + original_path[original_path_length-1] = '\0'; + original_path_length--; + } + + if(!case_sensitive) + strupper_m(original_path); + + if (original_path_length != translated_path_length) { + if (original_path_length < translated_path_length) { + DEBUG(0, ("OOPS - tried to store stat cache entry for werid length paths [%s] %u and [%s] %u)!\n", + original_path, original_path_length, translated_path, translated_path_length)); + SAFE_FREE(original_path); + SAFE_FREE(translated_path); + return; + } + + /* we only want to store the first part of original_path, + up to the length of translated_path */ + + original_path[translated_path_length] = '\0'; + original_path_length = translated_path_length; + } + + /* + * Check this name doesn't exist in the cache before we + * add it. + */ + + if ((hash_elem = hash_lookup(&stat_cache, original_path))) { + found_scp = (stat_cache_entry *)(hash_elem->value); + if (strcmp((found_scp->translated_path), orig_translated_path) == 0) { + /* already in hash table */ + SAFE_FREE(original_path); + SAFE_FREE(translated_path); + return; + } + /* hash collision - remove before we re-add */ + hash_remove(&stat_cache, hash_elem); + } - /* - * New entry. - */ + /* + * New entry. + */ - if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry) - +original_path_length - +translated_path_length)) == NULL) { - DEBUG(0,("stat_cache_add: Out of memory !\n")); - SAFE_FREE(original_path); - SAFE_FREE(translated_path); - return; - } - - scp->original_path = scp->names; - scp->translated_path = scp->names + original_path_length + 1; - safe_strcpy(scp->original_path, original_path, original_path_length); - safe_strcpy(scp->translated_path, translated_path, translated_path_length); - scp->translated_path_length = translated_path_length; - - hash_insert(&stat_cache, (char *)scp, original_path); - - SAFE_FREE(original_path); - SAFE_FREE(translated_path); - - DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp->original_path, scp->translated_path)); + if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry) + +original_path_length + +translated_path_length)) == NULL) { + DEBUG(0,("stat_cache_add: Out of memory !\n")); + SAFE_FREE(original_path); + SAFE_FREE(translated_path); + return; + } + + scp->original_path = scp->names; + scp->translated_path = scp->names + original_path_length + 1; + safe_strcpy(scp->original_path, original_path, original_path_length); + safe_strcpy(scp->translated_path, translated_path, translated_path_length); + scp->translated_path_length = translated_path_length; + + hash_insert(&stat_cache, (char *)scp, original_path); + + SAFE_FREE(original_path); + SAFE_FREE(translated_path); + + DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp->original_path, scp->translated_path)); } /** @@ -191,73 +193,106 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath, char **start, SMB_STRUCT_STAT *pst) { - stat_cache_entry *scp; - pstring chk_name; - size_t namelen; - hash_element *hash_elem; - char *sp; - - if (!lp_stat_cache()) - return False; + stat_cache_entry *scp; + pstring chk_name; + size_t namelen; + hash_element *hash_elem; + char *sp; + BOOL sizechanged = False; + unsigned int num_components = 0; + + if (!lp_stat_cache()) + return False; - namelen = strlen(name); - - *start = name; - - DO_PROFILE_INC(statcache_lookups); - - /* - * Don't lookup trivial valid directory entries. - */ - if((*name == '\0') || (strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) { - DO_PROFILE_INC(statcache_misses); - return False; - } - - pstrcpy(chk_name, name); - if(!case_sensitive) - strupper( chk_name ); - - while (1) { - hash_elem = hash_lookup(&stat_cache, chk_name); - if(hash_elem == NULL) { - /* - * Didn't find it - remove last component for next try. - */ - sp = strrchr_m(chk_name, '/'); - if (sp) { - *sp = '\0'; - } else { - /* - * We reached the end of the name - no match. - */ - DO_PROFILE_INC(statcache_misses); - return False; - } - if((*chk_name == '\0') || (strcmp(chk_name, ".") == 0) - || (strcmp(chk_name, "..") == 0)) { - DO_PROFILE_INC(statcache_misses); - return False; - } - } else { - scp = (stat_cache_entry *)(hash_elem->value); - DO_PROFILE_INC(statcache_hits); - if(vfs_stat(conn,scp->translated_path, pst) != 0) { - /* Discard this entry - it doesn't exist in the filesystem. */ - hash_remove(&stat_cache, hash_elem); - return False; - } - memcpy(name, scp->translated_path, MIN(sizeof(pstring)-1, scp->translated_path_length)); - - /* set pointer for 'where to start' on fixing the rest of the name */ - *start = &name[scp->translated_path_length]; - if(**start == '/') - ++*start; - - pstrcpy(dirpath, scp->translated_path); - return (namelen == scp->translated_path_length); - } - } + namelen = strlen(name); + + *start = name; + + DO_PROFILE_INC(statcache_lookups); + + /* + * Don't lookup trivial valid directory entries. + */ + if((*name == '\0') || (strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) { + DO_PROFILE_INC(statcache_misses); + return False; + } + + pstrcpy(chk_name, name); + + if(!case_sensitive) { + strupper_m( chk_name ); + /* + * In some language encodings the length changes + * if we uppercase. We need to treat this differently + * below. + */ + if (strlen(chk_name) != namelen) + sizechanged = True; + } + + while (1) { + hash_elem = hash_lookup(&stat_cache, chk_name); + if(hash_elem == NULL) { + /* + * Didn't find it - remove last component for next try. + */ + sp = strrchr_m(chk_name, '/'); + if (sp) { + *sp = '\0'; + /* + * Count the number of times we have done this, + * we'll need it when reconstructing the string. + */ + if (sizechanged) + num_components++; + + } else { + /* + * We reached the end of the name - no match. + */ + DO_PROFILE_INC(statcache_misses); + return False; + } + if((*chk_name == '\0') || (strcmp(chk_name, ".") == 0) + || (strcmp(chk_name, "..") == 0)) { + DO_PROFILE_INC(statcache_misses); + return False; + } + } else { + scp = (stat_cache_entry *)(hash_elem->value); + DO_PROFILE_INC(statcache_hits); + if(SMB_VFS_STAT(conn,scp->translated_path, pst) != 0) { + /* Discard this entry - it doesn't exist in the filesystem. */ + hash_remove(&stat_cache, hash_elem); + return False; + } + + if (!sizechanged) { + memcpy(name, scp->translated_path, MIN(sizeof(pstring)-1, scp->translated_path_length)); + } else if (num_components == 0) { + pstrcpy(name, scp->translated_path); + } else { + sp = strnrchr_m(name, '/', num_components); + if (sp) { + pstring last_component; + pstrcpy(last_component, sp); + pstrcpy(name, scp->translated_path); + pstrcat(name, last_component); + } else { + pstrcpy(name, scp->translated_path); + } + } + + /* set pointer for 'where to start' on fixing the rest of the name */ + *start = &name[scp->translated_path_length]; + if(**start == '/') + ++*start; + + pstrcpy(dirpath, scp->translated_path); + return (namelen == scp->translated_path_length); + } + } } /*************************************************************************** ** @@ -271,7 +306,8 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath, BOOL reset_stat_cache( void ) { static BOOL initialised; - if (!lp_stat_cache()) return True; + if (!lp_stat_cache()) + return True; if (initialised) { hash_clear(&stat_cache); @@ -280,4 +316,4 @@ BOOL reset_stat_cache( void ) initialised = hash_table_init( &stat_cache, INIT_STAT_CACHE_SIZE, (compare_function)(strcmp)); return initialised; -} /* reset_stat_cache */ +} diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index de598d6713..bdcd04443e 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1,7 +1,8 @@ /* Unix SMB/CIFS implementation. SMB transaction2 handling - Copyright (C) Jeremy Allison 1994-2001 + Copyright (C) Jeremy Allison 1994-2001 + Copyright (C) Stefan (metze) Metzmacher 2003 Extensively modified by Andrew Tridgell, 1995 @@ -28,6 +29,7 @@ extern int smb_read_error; extern fstring local_machine; extern int global_oplock_break; extern uint32 global_client_caps; +extern struct current_user current_user; #define get_file_size(sbuf) ((sbuf).st_size) @@ -324,7 +326,7 @@ static BOOL exact_match(char *str,char *mask, BOOL case_sig) return False; if (case_sig) return strcmp(str,mask)==0; - return strcasecmp(str,mask) == 0; + return StrCaseCmp(str,mask) == 0; } /**************************************************************************** @@ -549,12 +551,12 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, pstrcat(pathreal,dname); if (INFO_LEVEL_IS_UNIX(info_level)) { - if (vfs_lstat(conn,pathreal,&sbuf) != 0) { + if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) { DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n", pathreal,strerror(errno))); continue; } - } else if (vfs_stat(conn,pathreal,&sbuf) != 0) { + } else if (SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) { /* Needed to show the msdfs symlinks as * directories */ @@ -647,8 +649,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, SIVAL(p,l2_cbList,0); /* No extended attributes */ p += l2_achName; nameptr = p; - p += align_string(outbuf, p, 0); - len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE); + len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE | STR_NOALIGN); if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) SCVAL(nameptr, -1, len-2); else @@ -680,14 +681,14 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, pstrcpy(mangled_name, fname); mangle_map(mangled_name,True,True,SNUM(conn)); mangled_name[12] = 0; - len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER); + len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE); SSVAL(p, 0, len); } else { SSVAL(p,0,0); *(p+2) = 0; } p += 2 + 24; - len = srvstr_push(outbuf, p, fname, -1, 0); + len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII); SIVAL(q,0,len); p += len; len = PTR_DIFF(p, pdata); @@ -708,7 +709,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, p += 16; SIVAL(p,0,nt_extmode); p += 4; p += 4; - len = srvstr_push(outbuf, p, fname, -1, 0); + len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII); SIVAL(p, -4, len); p += len; len = PTR_DIFF(p, pdata); @@ -727,13 +728,13 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, SOFF_T(p,0,file_size); SOFF_T(p,8,allocation_size); p += 16; - SIVAL(p,0,nt_extmode); p += 4; + SIVAL(p,0,nt_extmode); p += 4; - SIVAL(p,0,0); p += 4; - len = srvstr_push(outbuf, p, fname, -1, 0); - SIVAL(p, -4, len); - p += len; + SIVAL(p,4,0); /* ea size */ + len = srvstr_push(outbuf, p+8, fname, -1, STR_TERMINATE_ASCII); + SIVAL(p, 0, len); + p += 8 + len; len = PTR_DIFF(p, pdata); len = (len + 3) & ~3; @@ -747,7 +748,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, p += 4; /* this must *not* be null terminated or w2k gets in a loop trying to set an acl on a dir (tridge) */ - len = srvstr_push(outbuf, p, fname, -1, 0); + len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII); SIVAL(p, -4, len); p += len; len = PTR_DIFF(p, pdata); @@ -1318,10 +1319,11 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf char *vname = volume_label(SNUM(conn)); int snum = SNUM(conn); char *fstype = lp_fstype(SNUM(conn)); + int quota_flag = 0; DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); - if(vfs_stat(conn,".",&st)!=0) { + if(SMB_VFS_STAT(conn,".",&st)!=0) { DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); return ERROR_DOS(ERRSRV,ERRinvdevice); } @@ -1338,7 +1340,7 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf { SMB_BIG_UINT dfree,dsize,bsize; data_len = 18; - conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize); SIVAL(pdata,l1_idFileSystem,st.st_dev); SIVAL(pdata,l1_cSectorUnit,bsize/512); SIVAL(pdata,l1_cUnit,dsize); @@ -1357,7 +1359,7 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf * the called hostname and the service name. */ SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) ); - len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, STR_TERMINATE); + len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, 0); SCVAL(pdata,l2_vol_cch,len); data_len = l2_vol_szVolLabel + len; DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", @@ -1367,19 +1369,26 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf case SMB_QUERY_FS_ATTRIBUTE_INFO: case SMB_FS_ATTRIBUTE_INFORMATION: + +#if defined(HAVE_SYS_QUOTAS) + quota_flag = FILE_VOLUME_QUOTAS; +#endif + SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH| - (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */ + (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)| + quota_flag); /* FS ATTRIBUTES */ + SIVAL(pdata,4,255); /* Max filename component length */ /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it and will think we can't do long filenames */ - len = srvstr_push(outbuf, pdata+12, fstype, -1, 0); + len = srvstr_push(outbuf, pdata+12, fstype, -1, STR_UNICODE); SIVAL(pdata,8,len); data_len = 12 + len; break; case SMB_QUERY_FS_LABEL_INFO: case SMB_FS_LABEL_INFORMATION: - len = srvstr_push(outbuf, pdata+4, vname, -1, STR_TERMINATE); + len = srvstr_push(outbuf, pdata+4, vname, -1, 0); data_len = 4 + len; SIVAL(pdata,0,len); break; @@ -1394,7 +1403,7 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16)); - len = srvstr_push(outbuf, pdata+18, vname, -1, STR_TERMINATE); + len = srvstr_push(outbuf, pdata+18, vname, -1, STR_UNICODE); SIVAL(pdata,12,len); data_len = 18+len; DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", @@ -1406,7 +1415,7 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf { SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; data_len = 24; - conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize); block_size = lp_block_size(snum); if (bsize < block_size) { SMB_BIG_UINT factor = block_size/bsize; @@ -1436,7 +1445,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned { SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; data_len = 32; - conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize); block_size = lp_block_size(snum); if (bsize < block_size) { SMB_BIG_UINT factor = block_size/bsize; @@ -1470,6 +1479,78 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned SIVAL(pdata,4,0); /* characteristics */ break; +#ifdef HAVE_SYS_QUOTAS + case SMB_FS_QUOTA_INFORMATION: + /* + * what we have to send --metze: + * + * Unknown1: 24 NULL bytes + * Soft Quota Treshold: 8 bytes seems like SMB_BIG_UINT or so + * Hard Quota Limit: 8 bytes seems like SMB_BIG_UINT or so + * Quota Flags: 2 byte : + * Unknown3: 6 NULL bytes + * + * 48 bytes total + * + * details for Quota Flags: + * + * 0x0020 Log Limit: log if the user exceeds his Hard Quota + * 0x0010 Log Warn: log if the user exceeds his Soft Quota + * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota + * 0x0001 Enable Quotas: enable quota for this fs + * + */ + { + /* we need to fake up a fsp here, + * because its not send in this call + */ + files_struct fsp; + SMB_NTQUOTA_STRUCT quotas; + + ZERO_STRUCT(fsp); + ZERO_STRUCT(quotas); + + fsp.conn = conn; + fsp.fnum = -1; + fsp.fd = -1; + + /* access check */ + if (conn->admin_user != True) { + DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", + lp_servicename(SNUM(conn)),conn->user)); + return ERROR_DOS(ERRDOS,ERRnoaccess); + } + + if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { + DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn)))); + return ERROR_DOS(ERRSRV,ERRerror); + } + + data_len = 48; + + DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",lp_servicename(SNUM(conn)))); + + /* Unknown1 24 NULL bytes*/ + SBIG_UINT(pdata,0,(SMB_BIG_UINT)0); + SBIG_UINT(pdata,8,(SMB_BIG_UINT)0); + SBIG_UINT(pdata,16,(SMB_BIG_UINT)0); + + /* Default Soft Quota 8 bytes */ + SBIG_UINT(pdata,24,quotas.softlim); + + /* Default Hard Quota 8 bytes */ + SBIG_UINT(pdata,32,quotas.hardlim); + + /* Quota flag 2 bytes */ + SSVAL(pdata,40,quotas.qflags); + + /* Unknown3 6 NULL bytes */ + SSVAL(pdata,42,0); + SIVAL(pdata,44,0); + + break; + } +#endif /* HAVE_SYS_QUOTAS */ case SMB_FS_OBJECTID_INFORMATION: data_len = 64; break; @@ -1511,6 +1592,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned return -1; } +#ifdef HAVE_SYS_QUOTAS /**************************************************************************** Reply to a TRANS2_SETFSINFO (set filesystem info). ****************************************************************************/ @@ -1519,18 +1601,110 @@ static int call_trans2setfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, char **pparams, int total_params, char **ppdata, int total_data) { - /* Just say yes we did it - there is nothing that - can be set here so it doesn't matter. */ + char *pdata = *ppdata; + char *params = *pparams; + files_struct *fsp = NULL; + uint16 info_level; int outsize; - DEBUG(3,("call_trans2setfsinfo\n")); + SMB_NTQUOTA_STRUCT quotas; + + ZERO_STRUCT(quotas); - if (!CAN_WRITE(conn)) + DEBUG(10,("call_trans2setfsinfo: SET_FS_QUOTA: for service [%s]\n",lp_servicename(SNUM(conn)))); + + /* access check */ + if ((conn->admin_user != True)||!CAN_WRITE(conn)) { + DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", + lp_servicename(SNUM(conn)),conn->user)); return ERROR_DOS(ERRSRV,ERRaccess); + } + + /* */ + if (total_params < 4) { + DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n", + total_params)); + return ERROR_DOS(ERRDOS,ERRinvalidparam); + } + + fsp = file_fsp(params,0); + + if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) { + DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n")); + return ERROR_NT(NT_STATUS_INVALID_HANDLE); + } + info_level = SVAL(params,2); + + switch(info_level) { + case SMB_FS_QUOTA_INFORMATION: + /* note: normaly there're 48 bytes, + * but we didn't use the last 6 bytes for now + * --metze + */ + if (total_data < 42) { + DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n", + total_data)); + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + /* unknown_1 24 NULL bytes in pdata*/ + + /* the soft quotas 8 bytes (SMB_BIG_UINT)*/ + quotas.softlim = (SMB_BIG_UINT)IVAL(pdata,24); +#ifdef LARGE_SMB_OFF_T + quotas.softlim |= (((SMB_BIG_UINT)IVAL(pdata,28)) << 32); +#else /* LARGE_SMB_OFF_T */ + if ((IVAL(pdata,28) != 0)&& + ((quotas.softlim != 0xFFFFFFFF)|| + (IVAL(pdata,28)!=0xFFFFFFFF))) { + /* more than 32 bits? */ + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } +#endif /* LARGE_SMB_OFF_T */ + + /* the hard quotas 8 bytes (SMB_BIG_UINT)*/ + quotas.hardlim = (SMB_BIG_UINT)IVAL(pdata,32); +#ifdef LARGE_SMB_OFF_T + quotas.hardlim |= (((SMB_BIG_UINT)IVAL(pdata,36)) << 32); +#else /* LARGE_SMB_OFF_T */ + if ((IVAL(pdata,36) != 0)&& + ((quotas.hardlim != 0xFFFFFFFF)|| + (IVAL(pdata,36)!=0xFFFFFFFF))) { + /* more than 32 bits? */ + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } +#endif /* LARGE_SMB_OFF_T */ + + /* quota_flags 2 bytes **/ + quotas.qflags = SVAL(pdata,40); + + /* unknown_2 6 NULL bytes follow*/ + + /* now set the quotas */ + if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { + DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn)))); + return ERROR_DOS(ERRSRV,ERRerror); + } + + break; + default: + DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n", + info_level)); + return ERROR_DOS(ERRDOS,ERRunknownlevel); + break; + } + + /* + * sending this reply works fine, + * but I'm not sure it's the same + * like windows do... + * --metze + */ outsize = set_message(outbuf,10,0,True); return outsize; } +#endif /* HAVE_SYS_QUOTAS */ /**************************************************************************** * Utility function to set bad path error. @@ -1589,7 +1763,20 @@ static int call_trans2qfilepathinfo(connection_struct *conn, DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); - if(fsp && (fsp->is_directory || fsp->fd == -1)) { + if(fsp && (fsp->fake_file_handle)) { + /* + * This is actually for the QUOTA_FAKE_FILE --metze + */ + + pstrcpy(fname, fsp->fsp_name); + unix_convert(fname,conn,0,&bad_path,&sbuf); + if (!check_name(fname,conn)) { + DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed for fake_file(%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + + } else if(fsp && (fsp->is_directory || fsp->fd == -1)) { /* * This is actually a QFILEINFO on a directory * handle (returned from an NT SMB). NT5.0 seems @@ -1605,13 +1792,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn, if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ - if (vfs_lstat(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno))); + if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRbadpath)); } - } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno))); + } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRbadpath)); } @@ -1624,11 +1811,11 @@ static int call_trans2qfilepathinfo(connection_struct *conn, CHECK_FSP(fsp,conn); pstrcpy(fname, fsp->fsp_name); - if (vfs_fstat(fsp,fsp->fd,&sbuf) != 0) { + if (SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) { DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadfid)); } - if((pos = fsp->conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1) + if((pos = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_CUR)) == -1) return(UNIXERROR(ERRDOS,ERRnoaccess)); delete_pending = fsp->delete_on_close; @@ -1655,13 +1842,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn, if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ - if (vfs_lstat(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno))); + if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRbadpath)); } - } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno))); + } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRbadpath)); } @@ -1733,9 +1920,17 @@ static int call_trans2qfilepathinfo(connection_struct *conn, SIVAL(pdata,l1_cbFile,(uint32)file_size); SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size); SSVAL(pdata,l1_attrFile,mode); - SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */ + SIVAL(pdata,l1_attrFile+2,0); /* this is what win2003 does */ break; + case SMB_INFO_IS_NAME_VALID: + if (tran_call == TRANSACT2_QFILEINFO) { + /* os/2 needs this ? really ?*/ + return ERROR_DOS(ERRDOS,ERRbadfunc); + } + data_size = 0; + break; + case SMB_INFO_QUERY_EAS_FROM_LIST: data_size = 24; put_dos_date2(pdata,0,c_time); @@ -1748,12 +1943,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, case SMB_INFO_QUERY_ALL_EAS: data_size = 4; - SIVAL(pdata,0,data_size); + SIVAL(pdata,0,0); /* ea size */ break; - case 6: - return ERROR_DOS(ERRDOS,ERRbadfunc); /* os/2 needs this */ - case SMB_FILE_BASIC_INFORMATION: case SMB_QUERY_FILE_BASIC_INFO: @@ -1836,6 +2028,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, break; case SMB_QUERY_FILE_ALL_INFO: + case SMB_FILE_ALL_INFORMATION: put_long_date(pdata,c_time); put_long_date(pdata+8,sbuf.st_atime); put_long_date(pdata+16,sbuf.st_mtime); /* write time */ @@ -1848,20 +2041,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, SCVAL(pdata,20,delete_pending); SCVAL(pdata,21,(mode&aDIR)?1:0); pdata += 24; - SINO_T(pdata,0,(SMB_INO_T)sbuf.st_ino); - pdata += 8; /* index number */ pdata += 4; /* EA info */ - if (mode & aRONLY) - SIVAL(pdata,0,0xA9); - else - SIVAL(pdata,0,0xd01BF); - pdata += 4; - SOFF_T(pdata,0,pos); /* current offset */ - pdata += 8; - SIVAL(pdata,0,mode); /* is this the right sort of mode info? */ - pdata += 4; - pdata += 4; /* alignment */ - len = srvstr_push(outbuf, pdata+4, dos_fname, -1, STR_TERMINATE); + len = srvstr_push(outbuf, pdata+4, dos_fname, -1, STR_UNICODE); SIVAL(pdata,0,len); pdata += 4 + len; data_size = PTR_DIFF(pdata,(*ppdata)); @@ -1915,28 +2096,6 @@ static int call_trans2qfilepathinfo(connection_struct *conn, break; #if 0 - /* Not yet finished... JRA */ - case 1018: - { - put_long_date(pdata,c_time); - put_long_date(pdata+8,sbuf.st_atime); - put_long_date(pdata+16,sbuf.st_mtime); /* write time */ - put_long_date(pdata+24,sbuf.st_mtime); /* change time */ - SIVAL(pdata,32,mode); - SIVAL(pdata,36,0); /* ??? */ - SIVAL(pdata,40,0x20); /* ??? */ - SIVAL(pdata,44,0); /* ??? */ - SOFF_T(pdata,48,size); - SIVAL(pdata,56,0x1); /* ??? */ - SIVAL(pdata,60,0); /* ??? */ - SIVAL(pdata,64,0); /* ??? */ - SIVAL(pdata,68,length); /* Following string length in bytes. */ - dos_PutUniCode(pdata+72,,False); - break; - } -#endif - -#if 0 /* * NT4 server just returns "invalid query" to this - if we try to answer * it then NTws gets a BSOD! (tridge). @@ -1958,8 +2117,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, } break; + case SMB_QUERY_COMPRESSION_INFO: case SMB_FILE_COMPRESSION_INFORMATION: - SOFF_T(pdata,0,allocation_size); + SOFF_T(pdata,0,file_size); SIVAL(pdata,8,0); /* ??? */ SIVAL(pdata,12,0); /* ??? */ data_size = 16; @@ -2054,7 +2214,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, #else return(UNIXERROR(ERRDOS,ERRbadlink)); #endif - len = conn->vfs_ops.readlink(conn,fullpathname, buffer, sizeof(pstring)-1); /* read link */ + len = SMB_VFS_READLINK(conn,fullpathname, buffer, sizeof(pstring)-1); /* read link */ if (len == -1) return(UNIXERROR(ERRDOS,ERRnoaccess)); buffer[len] = 0; @@ -2178,7 +2338,7 @@ static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in pstrcpy(link_dest, "./"); } - if (conn->vfs_ops.realpath(conn,link_dest,resolved_name) == NULL) + if (SMB_VFS_REALPATH(conn,link_dest,resolved_name) == NULL) return -1; pstrcpy(link_dest, resolved_name); @@ -2229,7 +2389,13 @@ static int call_trans2setfilepathinfo(connection_struct *conn, gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE; mode_t unixmode = 0; + if (!params) + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); + if (tran_call == TRANSACT2_SETFILEINFO) { + if (total_params < 4) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + fsp = file_fsp(params,0); info_level = SVAL(params,2); @@ -2269,7 +2435,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, pstrcpy(fname, fsp->fsp_name); fd = fsp->fd; - if (vfs_fstat(fsp,fd,&sbuf) != 0) { + if (SMB_VFS_FSTAT(fsp,fd,&sbuf) != 0) { DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadfid)); } @@ -2461,7 +2627,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, if (new_fsp == NULL) return(UNIXERROR(ERRDOS,ERRbadpath)); ret = vfs_allocate_file_space(new_fsp, allocation_size); - if (vfs_fstat(new_fsp,new_fsp->fd,&new_sbuf) != 0) { + if (SMB_VFS_FSTAT(new_fsp,new_fsp->fd,&new_sbuf) != 0) { DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n", new_fsp->fnum, strerror(errno))); ret = -1; @@ -2469,7 +2635,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, close_file(new_fsp,True); } else { ret = vfs_allocate_file_space(fsp, allocation_size); - if (vfs_fstat(fsp,fd,&new_sbuf) != 0) { + if (SMB_VFS_FSTAT(fsp,fd,&new_sbuf) != 0) { DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno))); ret = -1; @@ -2609,7 +2775,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", 0%o for file %s\n", (double)dev, unixmode, fname )); /* Ok - do the mknod. */ - if (conn->vfs_ops.mknod(conn,dos_to_unix_static(fname), unixmode, dev) != 0) + if (SMB_VFS_MKNOD(conn,dos_to_unix_static(fname), unixmode, dev) != 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); inherit_access_acl(conn, fname, unixmode); @@ -2628,7 +2794,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", if (raw_unixmode != SMB_MODE_NO_CHANGE) { DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n", (unsigned int)unixmode, fname )); - if (vfs_chmod(conn,fname,unixmode) != 0) + if (SMB_VFS_CHMOD(conn,fname,unixmode) != 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -2639,7 +2805,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (sbuf.st_uid != set_owner)) { DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing owner %u for file %s\n", (unsigned int)set_owner, fname )); - if (vfs_chown(conn,fname,set_owner, (gid_t)-1) != 0) + if (SMB_VFS_CHOWN(conn,fname,set_owner, (gid_t)-1) != 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -2650,7 +2816,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (sbuf.st_gid != set_grp)) { DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n", (unsigned int)set_owner, fname )); - if (vfs_chown(conn,fname,(uid_t)-1, set_grp) != 0) + if (SMB_VFS_CHOWN(conn,fname,(uid_t)-1, set_grp) != 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); } break; @@ -2677,7 +2843,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n", fname, link_dest )); - if (conn->vfs_ops.symlink(conn,link_dest,fname) != 0) + if (SMB_VFS_SYMLINK(conn,link_dest,fname) != 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); SSVAL(params,0,0); send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); @@ -2702,7 +2868,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n", fname, link_dest )); - if (conn->vfs_ops.link(conn,link_dest,fname) != 0) + if (SMB_VFS_LINK(conn,link_dest,fname) != 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); SSVAL(params,0,0); send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); @@ -2854,7 +3020,7 @@ static int call_trans2mkdir(connection_struct *conn, unix_convert(directory,conn,0,&bad_path,&sbuf); if (check_name(directory,conn)) - ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); + ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory)); if(ret < 0) { DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); @@ -3298,13 +3464,14 @@ int reply_trans2(connection_struct *conn, END_PROFILE_NESTED(Trans2_qfsinfo); break; +#ifdef HAVE_SYS_QUOTAS case TRANSACT2_SETFSINFO: START_PROFILE_NESTED(Trans2_setfsinfo); outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize, ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_setfsinfo); break; - +#endif case TRANSACT2_QPATHINFO: case TRANSACT2_QFILEINFO: START_PROFILE_NESTED(Trans2_qpathinfo); diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index c68d00025c..8d3e7cd9be 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -529,3 +529,375 @@ BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE } return True; } + + +/***************************************************************** + Id mapping cache. This is to avoid Winbind mappings already + seen by smbd to be queried too frequently, keeping winbindd + busy, and blocking smbd while winbindd is busy with other + stuff. Written by Michael Steffens <michael.steffens@hp.com>, + modified to use linked lists by jra. +*****************************************************************/ + +#define MAX_UID_SID_CACHE_SIZE 100 +#define TURNOVER_UID_SID_CACHE_SIZE 10 +#define MAX_GID_SID_CACHE_SIZE 100 +#define TURNOVER_GID_SID_CACHE_SIZE 10 + +static size_t n_uid_sid_cache = 0; +static size_t n_gid_sid_cache = 0; + +static struct uid_sid_cache { + struct uid_sid_cache *next, *prev; + uid_t uid; + DOM_SID sid; + enum SID_NAME_USE sidtype; +} *uid_sid_cache_head; + +static struct gid_sid_cache { + struct gid_sid_cache *next, *prev; + gid_t gid; + DOM_SID sid; + enum SID_NAME_USE sidtype; +} *gid_sid_cache_head; + +/***************************************************************** + Find a SID given a uid. +*****************************************************************/ + +static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid) +{ + struct uid_sid_cache *pc; + + for (pc = uid_sid_cache_head; pc; pc = pc->next) { + if (pc->uid == uid) { + fstring sid; + *psid = pc->sid; + DEBUG(3,("fetch sid from uid cache %u -> %s\n", + (unsigned int)uid, sid_to_string(sid, psid))); + DLIST_PROMOTE(uid_sid_cache_head, pc); + return True; + } + } + return False; +} + +/***************************************************************** + Find a uid given a SID. +*****************************************************************/ + +static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid ) +{ + struct uid_sid_cache *pc; + + for (pc = uid_sid_cache_head; pc; pc = pc->next) { + if (sid_compare(&pc->sid, psid) == 0) { + fstring sid; + *puid = pc->uid; + DEBUG(3,("fetch uid from cache %u -> %s\n", + (unsigned int)*puid, sid_to_string(sid, psid))); + DLIST_PROMOTE(uid_sid_cache_head, pc); + return True; + } + } + return False; +} + +/***************************************************************** + Store uid to SID mapping in cache. +*****************************************************************/ + +static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid) +{ + struct uid_sid_cache *pc; + + if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) { + /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */ + struct uid_sid_cache *pc_next; + size_t i; + + for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next) + ; + for(; pc; pc = pc_next) { + pc_next = pc->next; + DLIST_REMOVE(uid_sid_cache_head,pc); + SAFE_FREE(pc); + n_uid_sid_cache--; + } + } + + pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache)); + if (!pc) + return; + pc->uid = uid; + sid_copy(&pc->sid, psid); + DLIST_ADD(uid_sid_cache_head, pc); + n_uid_sid_cache++; +} + +/***************************************************************** + Find a SID given a gid. +*****************************************************************/ + +static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid) +{ + struct gid_sid_cache *pc; + + for (pc = gid_sid_cache_head; pc; pc = pc->next) { + if (pc->gid == gid) { + fstring sid; + *psid = pc->sid; + DEBUG(3,("fetch sid from gid cache %u -> %s\n", + (unsigned int)gid, sid_to_string(sid, psid))); + DLIST_PROMOTE(gid_sid_cache_head, pc); + return True; + } + } + return False; +} + +/***************************************************************** + Find a gid given a SID. +*****************************************************************/ + +static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid) +{ + struct gid_sid_cache *pc; + + for (pc = gid_sid_cache_head; pc; pc = pc->next) { + if (sid_compare(&pc->sid, psid) == 0) { + fstring sid; + *pgid = pc->gid; + DEBUG(3,("fetch uid from cache %u -> %s\n", + (unsigned int)*pgid, sid_to_string(sid, psid))); + DLIST_PROMOTE(gid_sid_cache_head, pc); + return True; + } + } + return False; +} + +/***************************************************************** + Store gid to SID mapping in cache. +*****************************************************************/ + +static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid) +{ + struct gid_sid_cache *pc; + + if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) { + /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */ + struct gid_sid_cache *pc_next; + size_t i; + + for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next) + ; + for(; pc; pc = pc_next) { + pc_next = pc->next; + DLIST_REMOVE(gid_sid_cache_head,pc); + SAFE_FREE(pc); + n_gid_sid_cache--; + } + } + + pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache)); + if (!pc) + return; + pc->gid = gid; + sid_copy(&pc->sid, psid); + DLIST_ADD(gid_sid_cache_head, pc); + n_gid_sid_cache++; +} + +/***************************************************************** + *THE CANONICAL* convert uid_t to SID function. +*****************************************************************/ + +NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid) +{ + uid_t low, high; + fstring sid; + + ZERO_STRUCTP(psid); + + if (fetch_sid_from_uid_cache(psid, uid)) + return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + + if (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) { + if (winbind_uid_to_sid(psid, uid)) { + + DEBUG(10,("uid_to_sid: winbindd %u -> %s\n", + (unsigned int)uid, sid_to_string(sid, psid))); + + if (psid) + store_uid_sid_cache(psid, uid); + return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + } + } + + if (!local_uid_to_sid(psid, uid)) { + DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid )); + return NT_STATUS_UNSUCCESSFUL; + } + + DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid))); + + store_uid_sid_cache(psid, uid); + return NT_STATUS_OK; +} + +/***************************************************************** + *THE CANONICAL* convert gid_t to SID function. +*****************************************************************/ + +NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid) +{ + gid_t low, high; + fstring sid; + + ZERO_STRUCTP(psid); + + if (fetch_sid_from_gid_cache(psid, gid)) + return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + + if (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) { + if (winbind_gid_to_sid(psid, gid)) { + + DEBUG(10,("gid_to_sid: winbindd %u -> %s\n", + (unsigned int)gid, sid_to_string(sid, psid))); + + if (psid) + store_gid_sid_cache(psid, gid); + return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + } + } + + if (!local_gid_to_sid(psid, gid)) { + DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid )); + return NT_STATUS_UNSUCCESSFUL; + } + + DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid))); + + store_gid_sid_cache(psid, gid); + return NT_STATUS_OK; +} + +/***************************************************************** + *THE CANONICAL* convert SID to uid function. +*****************************************************************/ + +NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid) +{ + fstring dom_name, name, sid_str; + enum SID_NAME_USE name_type; + + if (fetch_uid_from_cache(puid, psid)) + return NT_STATUS_OK; + + /* if this is our SID then go straight to a local lookup */ + + if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) { + DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n", + sid_string_static(psid) )); + + if ( local_sid_to_uid(puid, psid, &name_type) ) + goto success; + + DEBUG(10,("sid_to_uid: local lookup failed\n")); + + return NT_STATUS_UNSUCCESSFUL; + } + + /* If it is not our local domain, only hope is winbindd */ + + if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) { + DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n", + sid_string_static(psid) )); + + return NT_STATUS_UNSUCCESSFUL; + } + + /* If winbindd does know the SID, ensure this is a user */ + + if (name_type != SID_NAME_USER) { + DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n", + (unsigned int)name_type )); + return NT_STATUS_INVALID_PARAMETER; + } + + /* get the uid. Has to work or else we are dead in the water */ + + if ( !winbind_sid_to_uid(puid, psid) ) { + DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n", + sid_to_string(sid_str, psid) )); + return NT_STATUS_UNSUCCESSFUL; + } + +success: + DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid), + (unsigned int)*puid )); + + store_uid_sid_cache(psid, *puid); + + return NT_STATUS_OK; +} +/***************************************************************** + *THE CANONICAL* convert SID to gid function. + Group mapping is used for gids that maps to Wellknown SIDs +*****************************************************************/ + +NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid) +{ + fstring dom_name, name, sid_str; + enum SID_NAME_USE name_type; + + if (fetch_gid_from_cache(pgid, psid)) + return NT_STATUS_OK; + + /* + * First we must look up the name and decide if this is a group sid. + * Group mapping can deal with foreign SIDs + */ + + if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) { + DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n", + sid_to_string(sid_str, psid) )); + + if ( local_sid_to_gid(pgid, psid, &name_type) ) + goto success; + + DEBUG(10,("sid_to_gid: no one knows this SID\n")); + + return NT_STATUS_UNSUCCESSFUL; + } + + /* winbindd knows it; Ensure this is a group sid */ + + if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) { + DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n", + (unsigned int)name_type )); + + /* winbindd is running and knows about this SID. Just the wrong type. + Don't fallback to a local lookup here */ + + return NT_STATUS_INVALID_PARAMETER; + } + + /* winbindd knows it and it is a type of group; sid_to_gid must succeed + or we are dead in the water */ + + if ( !winbind_sid_to_gid(pgid, psid) ) { + DEBUG(10,("sid_to_uid: winbind failed to allocate a new gid for sid %s\n", + sid_to_string(sid_str, psid) )); + return NT_STATUS_UNSUCCESSFUL; + } + +success: + DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid), + (unsigned int)*pgid )); + + store_gid_sid_cache(psid, *pgid); + + return NT_STATUS_OK; +} diff --git a/source3/smbd/utmp.c b/source3/smbd/utmp.c index 6c12cfac62..9833a11f2d 100644 --- a/source3/smbd/utmp.c +++ b/source3/smbd/utmp.c @@ -21,8 +21,6 @@ #include "includes.h" -#ifdef WITH_UTMP - /**************************************************************************** Reflect connection status in utmp/wtmp files. T.D.Lee@durham.ac.uk September 1999 @@ -81,11 +79,11 @@ lastlog: Notes: Each connection requires a small number (starting at 0, working up) - to represent the line (unum). This must be unique within and across - all smbd processes. + to represent the line. This must be unique within and across all + smbd processes. It is the 'id_num' from Samba's session.c code. The 4 byte 'ut_id' component is vital to distinguish connections, - of which there could be several hundered or even thousand. + of which there could be several hundred or even thousand. Entries seem to be printable characters, with optional NULL pads. We need to be distinct from other entries in utmp/wtmp. @@ -105,14 +103,28 @@ Notes: Arbitrarily I have chosen to use a distinctive 'SM' for the first two bytes. - The remaining two encode the "unum" (see above). - - For "utmp consolidate" the suggestion was made to encode the pid into - those remaining two bytes (16 bits). But recent UNIX (e.g Solaris 8) - is migrating to pids > 16 bits, so we ought not to do this. + The remaining two bytes encode the session 'id_num' (see above). + Our caller (session.c) should note our 16-bit limitation. ****************************************************************************/ +#ifndef WITH_UTMP +/* + * Not WITH_UTMP? Simply supply dummy routines. + */ + +void sys_utmp_claim(const char *username, const char *hostname, + struct in_addr *ipaddr, + const char *id_str, int id_num) +{} + +void sys_utmp_yield(const char *username, const char *hostname, + struct in_addr *ipaddr, + const char *id_str, int id_num) +{} + +#else /* WITH_UTMP */ + #include <utmp.h> #ifdef HAVE_UTMPX_H @@ -126,33 +138,6 @@ Notes: #endif /**************************************************************************** - Obtain/release a small number (0 upwards) unique within and across smbds. -****************************************************************************/ -/* - * Need a "small" number to represent this connection, unique within this - * smbd and across all smbds. - * - * claim: - * Start at 0, hunt up for free, unique number "unum" by attempting to - * store it as a key in a tdb database: - * key: unum data: pid+conn - * Also store its inverse, ready for yield function: - * key: pid+conn data: unum - * - * yield: - * Find key: pid+conn; data is unum; delete record - * Find key: unum ; delete record. - * - * Comment: - * The claim algorithm (a "for" loop attempting to store numbers in a tdb - * database) will be increasingly inefficient with larger numbers of - * connections. Is it possible to write a suitable primitive within tdb? - * - * However, by also storing the inverse key/data pair, we at least make - * the yield algorithm efficient. - */ - -/**************************************************************************** Default paths to various {u,w}tmp{,x} files. ****************************************************************************/ @@ -484,6 +469,7 @@ static int ut_id_encode(int i, char *fourbyte) */ static BOOL sys_utmp_fill(struct utmp *u, const char *username, const char *hostname, + struct in_addr *ipaddr, const char *id_str, int id_num) { struct timeval timeval; @@ -503,10 +489,6 @@ static BOOL sys_utmp_fill(struct utmp *u, /* * ut_line: * If size limit proves troublesome, then perhaps use "ut_id_encode()". - * - * Temporary variable "line_tmp" avoids trouble: - * o with unwanted trailing NULL if ut_line full; - * o with overflow if ut_line would be more than full. */ if (strlen(id_str) > sizeof(u->ut_line)) { DEBUG(1,("id_str [%s] is too long for %d char utmp field\n", @@ -538,8 +520,9 @@ static BOOL sys_utmp_fill(struct utmp *u, #if defined(HAVE_UT_UT_HOST) utmp_strcpy(u->ut_host, hostname, sizeof(u->ut_host)); #endif - #if defined(HAVE_UT_UT_ADDR) + if (ipaddr) + u->ut_addr = ipaddr->s_addr; /* * "(unsigned long) ut_addr" apparently exists on at least HP-UX 10.20. * Volunteer to implement, please ... @@ -561,6 +544,7 @@ static BOOL sys_utmp_fill(struct utmp *u, ****************************************************************************/ void sys_utmp_yield(const char *username, const char *hostname, + struct in_addr *ipaddr, const char *id_str, int id_num) { struct utmp u; @@ -576,7 +560,7 @@ void sys_utmp_yield(const char *username, const char *hostname, u.ut_type = DEAD_PROCESS; #endif - if (!sys_utmp_fill(&u, username, hostname, id_str, id_num)) return; + if (!sys_utmp_fill(&u, username, hostname, ipaddr, id_str, id_num)) return; sys_utmp_update(&u, NULL, False); } @@ -586,6 +570,7 @@ void sys_utmp_yield(const char *username, const char *hostname, ****************************************************************************/ void sys_utmp_claim(const char *username, const char *hostname, + struct in_addr *ipaddr, const char *id_str, int id_num) { struct utmp u; @@ -596,11 +581,9 @@ void sys_utmp_claim(const char *username, const char *hostname, u.ut_type = USER_PROCESS; #endif - if (!sys_utmp_fill(&u, username, hostname, id_str, id_num)) return; + if (!sys_utmp_fill(&u, username, hostname, ipaddr, id_str, id_num)) return; sys_utmp_update(&u, hostname, True); } -#else /* WITH_UTMP */ - void dummy_utmp(void) {} -#endif +#endif /* WITH_UTMP */ diff --git a/source3/smbd/vfs-wrap.c b/source3/smbd/vfs-wrap.c index 491fa70e68..8d44a1a0fa 100644 --- a/source3/smbd/vfs-wrap.c +++ b/source3/smbd/vfs-wrap.c @@ -30,18 +30,18 @@ is sure to try and execute them. These stubs are used to prevent this possibility. */ -int vfswrap_dummy_connect(connection_struct *conn, const char *service, const char *user) +int vfswrap_dummy_connect(vfs_handle_struct *handle, connection_struct *conn, const char *service, const char *user) { return 0; /* Return >= 0 for success */ } -void vfswrap_dummy_disconnect(connection_struct *conn) +void vfswrap_dummy_disconnect(vfs_handle_struct *handle, connection_struct *conn) { } /* Disk operations */ -SMB_BIG_UINT vfswrap_disk_free(connection_struct *conn, const char *path, BOOL small_query, SMB_BIG_UINT *bsize, +SMB_BIG_UINT vfswrap_disk_free(vfs_handle_struct *handle, connection_struct *conn, const char *path, BOOL small_query, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { SMB_BIG_UINT result; @@ -52,7 +52,7 @@ SMB_BIG_UINT vfswrap_disk_free(connection_struct *conn, const char *path, BOOL s /* Directory operations */ -DIR *vfswrap_opendir(connection_struct *conn, const char *fname) +DIR *vfswrap_opendir(vfs_handle_struct *handle, connection_struct *conn, const char *fname) { DIR *result; @@ -62,7 +62,7 @@ DIR *vfswrap_opendir(connection_struct *conn, const char *fname) return result; } -struct dirent *vfswrap_readdir(connection_struct *conn, DIR *dirp) +struct dirent *vfswrap_readdir(vfs_handle_struct *handle, connection_struct *conn, DIR *dirp) { struct dirent *result; @@ -72,7 +72,7 @@ struct dirent *vfswrap_readdir(connection_struct *conn, DIR *dirp) return result; } -int vfswrap_mkdir(connection_struct *conn, const char *path, mode_t mode) +int vfswrap_mkdir(vfs_handle_struct *handle, connection_struct *conn, const char *path, mode_t mode) { int result; BOOL has_dacl = False; @@ -93,17 +93,15 @@ int vfswrap_mkdir(connection_struct *conn, const char *path, mode_t mode) * mess up any inherited ACL bits that were set. JRA. */ int saved_errno = errno; /* We may get ENOSYS */ - if (conn->vfs_ops.chmod_acl != NULL) { - if ((conn->vfs_ops.chmod_acl(conn, path, mode) == -1) && (errno == ENOSYS)) - errno = saved_errno; - } + if ((SMB_VFS_CHMOD_ACL(conn, path, mode) == -1) && (errno == ENOSYS)) + errno = saved_errno; } END_PROFILE(syscall_mkdir); return result; } -int vfswrap_rmdir(connection_struct *conn, const char *path) +int vfswrap_rmdir(vfs_handle_struct *handle, connection_struct *conn, const char *path) { int result; @@ -113,7 +111,7 @@ int vfswrap_rmdir(connection_struct *conn, const char *path) return result; } -int vfswrap_closedir(connection_struct *conn, DIR *dirp) +int vfswrap_closedir(vfs_handle_struct *handle, connection_struct *conn, DIR *dirp) { int result; @@ -125,7 +123,7 @@ int vfswrap_closedir(connection_struct *conn, DIR *dirp) /* File operations */ -int vfswrap_open(connection_struct *conn, const char *fname, int flags, mode_t mode) +int vfswrap_open(vfs_handle_struct *handle, connection_struct *conn, const char *fname, int flags, mode_t mode) { int result; @@ -135,7 +133,7 @@ int vfswrap_open(connection_struct *conn, const char *fname, int flags, mode_t m return result; } -int vfswrap_close(files_struct *fsp, int fd) +int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp, int fd) { int result; @@ -146,7 +144,7 @@ int vfswrap_close(files_struct *fsp, int fd) return result; } -ssize_t vfswrap_read(files_struct *fsp, int fd, void *data, size_t n) +ssize_t vfswrap_read(vfs_handle_struct *handle, files_struct *fsp, int fd, void *data, size_t n) { ssize_t result; @@ -156,7 +154,7 @@ ssize_t vfswrap_read(files_struct *fsp, int fd, void *data, size_t n) return result; } -ssize_t vfswrap_write(files_struct *fsp, int fd, const void *data, size_t n) +ssize_t vfswrap_write(vfs_handle_struct *handle, files_struct *fsp, int fd, const void *data, size_t n) { ssize_t result; @@ -166,7 +164,7 @@ ssize_t vfswrap_write(files_struct *fsp, int fd, const void *data, size_t n) return result; } -SMB_OFF_T vfswrap_lseek(files_struct *fsp, int filedes, SMB_OFF_T offset, int whence) +SMB_OFF_T vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, int filedes, SMB_OFF_T offset, int whence) { SMB_OFF_T result = 0; @@ -192,7 +190,7 @@ 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, +ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, int fromfd, const DATA_BLOB *hdr, SMB_OFF_T offset, size_t n) { ssize_t result; @@ -203,7 +201,7 @@ ssize_t vfswrap_sendfile(int tofd, struct files_struct *fsp, int fromfd, const D return result; } -int vfswrap_rename(connection_struct *conn, const char *old, const char *new) +int vfswrap_rename(vfs_handle_struct *handle, connection_struct *conn, const char *old, const char *new) { int result; @@ -213,7 +211,7 @@ int vfswrap_rename(connection_struct *conn, const char *old, const char *new) return result; } -int vfswrap_fsync(files_struct *fsp, int fd) +int vfswrap_fsync(vfs_handle_struct *handle, files_struct *fsp, int fd) { #ifdef HAVE_FSYNC int result; @@ -228,7 +226,7 @@ int vfswrap_fsync(files_struct *fsp, int fd) #endif } -int vfswrap_stat(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf) +int vfswrap_stat(vfs_handle_struct *handle, connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf) { int result; @@ -238,7 +236,7 @@ int vfswrap_stat(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sb return result; } -int vfswrap_fstat(files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf) +int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf) { int result; @@ -248,7 +246,7 @@ int vfswrap_fstat(files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf) return result; } -int vfswrap_lstat(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf) +int vfswrap_lstat(vfs_handle_struct *handle, connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf) { int result; @@ -258,7 +256,7 @@ int vfswrap_lstat(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sb return result; } -int vfswrap_unlink(connection_struct *conn, const char *path) +int vfswrap_unlink(vfs_handle_struct *handle, connection_struct *conn, const char *path) { int result; @@ -268,7 +266,7 @@ int vfswrap_unlink(connection_struct *conn, const char *path) return result; } -int vfswrap_chmod(connection_struct *conn, const char *path, mode_t mode) +int vfswrap_chmod(vfs_handle_struct *handle, connection_struct *conn, const char *path, mode_t mode) { int result; @@ -281,9 +279,9 @@ int vfswrap_chmod(connection_struct *conn, const char *path, mode_t mode) */ - if (conn->vfs_ops.chmod_acl != NULL) { + { int saved_errno = errno; /* We might get ENOSYS */ - if ((result = conn->vfs_ops.chmod_acl(conn, path, mode)) == 0) { + if ((result = SMB_VFS_CHMOD_ACL(conn, path, mode)) == 0) { END_PROFILE(syscall_chmod); return result; } @@ -296,10 +294,9 @@ int vfswrap_chmod(connection_struct *conn, const char *path, mode_t mode) return result; } -int vfswrap_fchmod(files_struct *fsp, int fd, mode_t mode) +int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) { int result; - struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops; START_PROFILE(syscall_fchmod); @@ -309,9 +306,9 @@ int vfswrap_fchmod(files_struct *fsp, int fd, mode_t mode) * group owner bits directly. JRA. */ - if (vfs_ops->fchmod_acl != NULL) { + { int saved_errno = errno; /* We might get ENOSYS */ - if ((result = vfs_ops->fchmod_acl(fsp, fd, mode)) == 0) { + if ((result = SMB_VFS_FCHMOD_ACL(fsp, fd, mode)) == 0) { END_PROFILE(syscall_chmod); return result; } @@ -330,7 +327,7 @@ int vfswrap_fchmod(files_struct *fsp, int fd, mode_t mode) return result; } -int vfswrap_chown(connection_struct *conn, const char *path, uid_t uid, gid_t gid) +int vfswrap_chown(vfs_handle_struct *handle, connection_struct *conn, const char *path, uid_t uid, gid_t gid) { int result; @@ -340,7 +337,7 @@ int vfswrap_chown(connection_struct *conn, const char *path, uid_t uid, gid_t gi return result; } -int vfswrap_fchown(files_struct *fsp, int fd, uid_t uid, gid_t gid) +int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, int fd, uid_t uid, gid_t gid) { #ifdef HAVE_FCHOWN int result; @@ -356,7 +353,7 @@ int vfswrap_fchown(files_struct *fsp, int fd, uid_t uid, gid_t gid) #endif } -int vfswrap_chdir(connection_struct *conn, const char *path) +int vfswrap_chdir(vfs_handle_struct *handle, connection_struct *conn, const char *path) { int result; @@ -366,7 +363,7 @@ int vfswrap_chdir(connection_struct *conn, const char *path) return result; } -char *vfswrap_getwd(connection_struct *conn, char *path) +char *vfswrap_getwd(vfs_handle_struct *handle, connection_struct *conn, char *path) { char *result; @@ -376,7 +373,7 @@ char *vfswrap_getwd(connection_struct *conn, char *path) return result; } -int vfswrap_utime(connection_struct *conn, const char *path, struct utimbuf *times) +int vfswrap_utime(vfs_handle_struct *handle, connection_struct *conn, const char *path, struct utimbuf *times) { int result; @@ -391,18 +388,17 @@ int vfswrap_utime(connection_struct *conn, const char *path, struct utimbuf *tim allocate is set. **********************************************************************/ -static int strict_allocate_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) +static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len) { - struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops; SMB_STRUCT_STAT st; - SMB_OFF_T currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR); + SMB_OFF_T currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); unsigned char zero_space[4096]; SMB_OFF_T space_to_write; if (currpos == -1) return -1; - if (vfs_ops->fstat(fsp, fd, &st) == -1) + if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) return -1; space_to_write = len - st.st_size; @@ -420,7 +416,7 @@ static int strict_allocate_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) return sys_ftruncate(fd, len); /* Write out the real space on disk. */ - if (vfs_ops->lseek(fsp, fd, st.st_size, SEEK_SET) != st.st_size) + if (SMB_VFS_LSEEK(fsp, fd, st.st_size, SEEK_SET) != st.st_size) return -1; space_to_write = len - st.st_size; @@ -430,7 +426,7 @@ static int strict_allocate_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) SMB_OFF_T retlen; SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write); - retlen = vfs_ops->write(fsp,fsp->fd,(char *)zero_space,current_len_to_write); + retlen = SMB_VFS_WRITE(fsp,fsp->fd,(char *)zero_space,current_len_to_write); if (retlen <= 0) return -1; @@ -438,16 +434,15 @@ static int strict_allocate_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) } /* Seek to where we were */ - if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos) + if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos) return -1; return 0; } -int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) +int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len) { int result = -1; - struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops; SMB_STRUCT_STAT st; char c = 0; SMB_OFF_T currpos; @@ -455,7 +450,7 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) START_PROFILE(syscall_ftruncate); if (lp_strict_allocate(SNUM(fsp->conn))) { - result = strict_allocate_ftruncate(fsp, fd, len); + result = strict_allocate_ftruncate(handle, fsp, fd, len); END_PROFILE(syscall_ftruncate); return result; } @@ -473,7 +468,7 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot extend a file with ftruncate. Provide alternate implementation for this */ - currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR); + currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR); if (currpos == -1) { goto done; } @@ -482,7 +477,7 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) size in which case the ftruncate above should have succeeded or shorter, in which case seek to len - 1 and write 1 byte of zero */ - if (vfs_ops->fstat(fsp, fd, &st) == -1) { + if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) { goto done; } @@ -503,14 +498,14 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) goto done; } - if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1) + if (SMB_VFS_LSEEK(fsp, fd, len-1, SEEK_SET) != len -1) goto done; - if (vfs_ops->write(fsp, fd, &c, 1)!=1) + if (SMB_VFS_WRITE(fsp, fd, &c, 1)!=1) goto done; /* Seek to where we were */ - if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos) + if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos) goto done; result = 0; @@ -520,7 +515,7 @@ int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len) return result; } -BOOL vfswrap_lock(files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) +BOOL vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) { BOOL result; @@ -531,7 +526,7 @@ BOOL vfswrap_lock(files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T return result; } -int vfswrap_symlink(connection_struct *conn, const char *oldpath, const char *newpath) +int vfswrap_symlink(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath) { int result; @@ -541,7 +536,7 @@ int vfswrap_symlink(connection_struct *conn, const char *oldpath, const char *ne return result; } -int vfswrap_readlink(connection_struct *conn, const char *path, char *buf, size_t bufsiz) +int vfswrap_readlink(vfs_handle_struct *handle, connection_struct *conn, const char *path, char *buf, size_t bufsiz) { int result; @@ -551,7 +546,7 @@ int vfswrap_readlink(connection_struct *conn, const char *path, char *buf, size_ return result; } -int vfswrap_link(connection_struct *conn, const char *oldpath, const char *newpath) +int vfswrap_link(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath) { int result; @@ -561,7 +556,7 @@ int vfswrap_link(connection_struct *conn, const char *oldpath, const char *newpa return result; } -int vfswrap_mknod(connection_struct *conn, const char *pathname, mode_t mode, SMB_DEV_T dev) +int vfswrap_mknod(vfs_handle_struct *handle, connection_struct *conn, const char *pathname, mode_t mode, SMB_DEV_T dev) { int result; @@ -571,7 +566,7 @@ int vfswrap_mknod(connection_struct *conn, const char *pathname, mode_t mode, SM return result; } -char *vfswrap_realpath(connection_struct *conn, const char *path, char *resolved_path) +char *vfswrap_realpath(vfs_handle_struct *handle, connection_struct *conn, const char *path, char *resolved_path) { char *result; @@ -581,27 +576,27 @@ char *vfswrap_realpath(connection_struct *conn, const char *path, char *resolved return result; } -size_t vfswrap_fget_nt_acl(files_struct *fsp, int fd, SEC_DESC **ppdesc) +size_t vfswrap_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info, SEC_DESC **ppdesc) { size_t result; START_PROFILE(fget_nt_acl); - result = get_nt_acl(fsp, ppdesc); + result = get_nt_acl(fsp, security_info, ppdesc); END_PROFILE(fget_nt_acl); return result; } -size_t vfswrap_get_nt_acl(files_struct *fsp, const char *name, SEC_DESC **ppdesc) +size_t vfswrap_get_nt_acl(vfs_handle_struct *handle, files_struct *fsp, const char *name, uint32 security_info, SEC_DESC **ppdesc) { size_t result; START_PROFILE(get_nt_acl); - result = get_nt_acl(fsp, ppdesc); + result = get_nt_acl(fsp, security_info, ppdesc); END_PROFILE(get_nt_acl); return result; } -BOOL vfswrap_fset_nt_acl(files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd) +BOOL vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd) { BOOL result; @@ -611,7 +606,7 @@ BOOL vfswrap_fset_nt_acl(files_struct *fsp, int fd, uint32 security_info_sent, S return result; } -BOOL vfswrap_set_nt_acl(files_struct *fsp, const char *name, uint32 security_info_sent, SEC_DESC *psd) +BOOL vfswrap_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, const char *name, uint32 security_info_sent, SEC_DESC *psd) { BOOL result; @@ -621,132 +616,236 @@ BOOL vfswrap_set_nt_acl(files_struct *fsp, const char *name, uint32 security_inf return result; } -int vfswrap_chmod_acl(connection_struct *conn, const char *name, mode_t mode) +int vfswrap_chmod_acl(vfs_handle_struct *handle, connection_struct *conn, const char *name, mode_t mode) { +#ifdef HAVE_NO_ACL + errno = ENOSYS; + return -1; +#else int result; START_PROFILE(chmod_acl); result = chmod_acl(conn, name, mode); END_PROFILE(chmod_acl); return result; +#endif } -int vfswrap_fchmod_acl(files_struct *fsp, int fd, mode_t mode) +int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode) { +#ifdef HAVE_NO_ACL + errno = ENOSYS; + return -1; +#else int result; START_PROFILE(fchmod_acl); result = fchmod_acl(fsp, fd, mode); END_PROFILE(fchmod_acl); return result; +#endif } -int vfswrap_sys_acl_get_entry(struct connection_struct *conn, SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p) +int vfswrap_sys_acl_get_entry(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p) { return sys_acl_get_entry(theacl, entry_id, entry_p); } -int vfswrap_sys_acl_get_tag_type(struct connection_struct *conn, SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) +int vfswrap_sys_acl_get_tag_type(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) { return sys_acl_get_tag_type(entry_d, tag_type_p); } -int vfswrap_sys_acl_get_permset(struct connection_struct *conn, SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p) +int vfswrap_sys_acl_get_permset(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p) { return sys_acl_get_permset(entry_d, permset_p); } -void * vfswrap_sys_acl_get_qualifier(struct connection_struct *conn, SMB_ACL_ENTRY_T entry_d) +void * vfswrap_sys_acl_get_qualifier(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry_d) { return sys_acl_get_qualifier(entry_d); } -SMB_ACL_T vfswrap_sys_acl_get_file(struct connection_struct *conn, const char *path_p, SMB_ACL_TYPE_T type) +SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle, connection_struct *conn, const char *path_p, SMB_ACL_TYPE_T type) { return sys_acl_get_file(path_p, type); } -SMB_ACL_T vfswrap_sys_acl_get_fd(struct files_struct *fsp, int fd) +SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd) { return sys_acl_get_fd(fd); } -int vfswrap_sys_acl_clear_perms(struct connection_struct *conn, SMB_ACL_PERMSET_T permset) +int vfswrap_sys_acl_clear_perms(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_PERMSET_T permset) { return sys_acl_clear_perms(permset); } -int vfswrap_sys_acl_add_perm(struct connection_struct *conn, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) +int vfswrap_sys_acl_add_perm(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) { return sys_acl_add_perm(permset, perm); } -char * vfswrap_sys_acl_to_text(struct connection_struct *conn, SMB_ACL_T theacl, ssize_t *plen) +char * vfswrap_sys_acl_to_text(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_T theacl, ssize_t *plen) { return sys_acl_to_text(theacl, plen); } -SMB_ACL_T vfswrap_sys_acl_init(struct connection_struct *conn, int count) +SMB_ACL_T vfswrap_sys_acl_init(vfs_handle_struct *handle, connection_struct *conn, int count) { return sys_acl_init(count); } -int vfswrap_sys_acl_create_entry(struct connection_struct *conn, SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) +int vfswrap_sys_acl_create_entry(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) { return sys_acl_create_entry(pacl, pentry); } -int vfswrap_sys_acl_set_tag_type(struct connection_struct *conn, SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype) +int vfswrap_sys_acl_set_tag_type(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype) { return sys_acl_set_tag_type(entry, tagtype); } -int vfswrap_sys_acl_set_qualifier(struct connection_struct *conn, SMB_ACL_ENTRY_T entry, void *qual) +int vfswrap_sys_acl_set_qualifier(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry, void *qual) { return sys_acl_set_qualifier(entry, qual); } -int vfswrap_sys_acl_set_permset(struct connection_struct *conn, SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset) +int vfswrap_sys_acl_set_permset(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset) { return sys_acl_set_permset(entry, permset); } -int vfswrap_sys_acl_valid(struct connection_struct *conn, SMB_ACL_T theacl ) +int vfswrap_sys_acl_valid(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_T theacl ) { return sys_acl_valid(theacl ); } -int vfswrap_sys_acl_set_file(struct connection_struct *conn, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) +int vfswrap_sys_acl_set_file(vfs_handle_struct *handle, connection_struct *conn, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) { return sys_acl_set_file(name, acltype, theacl); } -int vfswrap_sys_acl_set_fd(struct files_struct *fsp, int fd, SMB_ACL_T theacl) +int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_ACL_T theacl) { return sys_acl_set_fd(fd, theacl); } -int vfswrap_sys_acl_delete_def_file(struct connection_struct *conn, const char *path) +int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle, connection_struct *conn, const char *path) { return sys_acl_delete_def_file(path); } -int vfswrap_sys_acl_get_perm(struct connection_struct *conn, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) +int vfswrap_sys_acl_get_perm(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) { return sys_acl_get_perm(permset, perm); } -int vfswrap_sys_acl_free_text(struct connection_struct *conn, char *text) +int vfswrap_sys_acl_free_text(vfs_handle_struct *handle, connection_struct *conn, char *text) { return sys_acl_free_text(text); } -int vfswrap_sys_acl_free_acl(struct connection_struct *conn, SMB_ACL_T posix_acl) +int vfswrap_sys_acl_free_acl(vfs_handle_struct *handle, connection_struct *conn, SMB_ACL_T posix_acl) { return sys_acl_free_acl(posix_acl); } -int vfswrap_sys_acl_free_qualifier(struct connection_struct *conn, void *qualifier, SMB_ACL_TAG_T tagtype) +int vfswrap_sys_acl_free_qualifier(vfs_handle_struct *handle, connection_struct *conn, void *qualifier, SMB_ACL_TAG_T tagtype) { return sys_acl_free_qualifier(qualifier, tagtype); } + +int vfswrap_get_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt) +{ +#ifdef HAVE_SYS_QUOTAS + int result; + + START_PROFILE(syscall_get_quota); + result = sys_get_quota(conn->connectpath, qtype, id, qt); + END_PROFILE(syscall_get_quota); + return result; +#else + errno = ENOSYS; + return -1; +#endif +} + +int vfswrap_set_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt) +{ +#ifdef HAVE_SYS_QUOTAS + int result; + + START_PROFILE(syscall_set_quota); + result = sys_set_quota(conn->connectpath, qtype, id, qt); + END_PROFILE(syscall_set_quota); + return result; +#else + errno = ENOSYS; + return -1; +#endif +} + +/**************************************************************** + Extended attribute operations. +*****************************************************************/ + +ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle,struct connection_struct *conn,const char *path, const char *name, void *value, size_t size) +{ + return sys_getxattr(path, name, value, size); +} + +ssize_t vfswrap_lgetxattr(struct vfs_handle_struct *handle,struct connection_struct *conn,const char *path, const char *name, void *value, size_t size) +{ + return sys_lgetxattr(path, name, value, size); +} + +ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, void *value, size_t size) +{ + return sys_fgetxattr(fd, name, value, size); +} + +ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, char *list, size_t size) +{ + return sys_listxattr(path, list, size); +} + +ssize_t vfswrap_llistxattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, char *list, size_t size) +{ + return sys_llistxattr(path, list, size); +} + +ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, char *list, size_t size) +{ + return sys_flistxattr(fd, list, size); +} + +int vfswrap_removexattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name) +{ + return sys_removexattr(path, name); +} + +int vfswrap_lremovexattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name) +{ + return sys_lremovexattr(path, name); +} + +int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name) +{ + return sys_fremovexattr(fd, name); +} + +int vfswrap_setxattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags) +{ + return sys_setxattr(path, name, value, size, flags); +} + +int vfswrap_lsetxattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, const char *name, const void *value, size_t size, int flags) +{ + return sys_lsetxattr(path, name, value, size, flags); +} + +int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, const void *value, size_t size, int flags) +{ + return sys_fsetxattr(fd, name, value, size, flags); +} diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 5fcf9a575e..5f3abe7efe 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -28,9 +28,9 @@ #define DBGC_CLASS DBGC_VFS struct vfs_init_function_entry { - char *name; - vfs_op_tuple *ops, *(*init)(const struct vfs_ops *, struct smb_vfs_handle_struct *); - struct vfs_init_function_entry *prev, *next; + char *name; + vfs_op_tuple *vfs_op_tuples; + struct vfs_init_function_entry *prev, *next; }; static struct vfs_init_function_entry *backends = NULL; @@ -42,96 +42,106 @@ struct vfs_syminfo { void *fptr; }; -/* - Opaque (final) vfs operations. This is a combination of first-met opaque vfs operations - across all currently processed modules. */ - -static vfs_op_tuple vfs_opaque_ops[SMB_VFS_OP_LAST]; - /* Default vfs hooks. WARNING: The order of these initialisers is very important. They must be in the same order as defined in vfs.h. Change at your own peril. */ -static struct vfs_ops default_vfs_ops = { - - /* Disk operations */ - - vfswrap_dummy_connect, - vfswrap_dummy_disconnect, - vfswrap_disk_free, - - /* Directory operations */ - - vfswrap_opendir, - vfswrap_readdir, - vfswrap_mkdir, - vfswrap_rmdir, - vfswrap_closedir, - - /* File operations */ - - vfswrap_open, - vfswrap_close, - vfswrap_read, - vfswrap_write, - vfswrap_lseek, - vfswrap_sendfile, - vfswrap_rename, - vfswrap_fsync, - vfswrap_stat, - vfswrap_fstat, - vfswrap_lstat, - vfswrap_unlink, - vfswrap_chmod, - vfswrap_fchmod, - vfswrap_chown, - vfswrap_fchown, - vfswrap_chdir, - vfswrap_getwd, - vfswrap_utime, - vfswrap_ftruncate, - vfswrap_lock, - vfswrap_symlink, - vfswrap_readlink, - vfswrap_link, - vfswrap_mknod, - vfswrap_realpath, - - vfswrap_fget_nt_acl, - vfswrap_get_nt_acl, - vfswrap_fset_nt_acl, - vfswrap_set_nt_acl, - - /* POSIX ACL operations. */ -#if defined(HAVE_NO_ACLS) - NULL, - NULL, -#else - vfswrap_chmod_acl, - vfswrap_fchmod_acl, -#endif - vfswrap_sys_acl_get_entry, - vfswrap_sys_acl_get_tag_type, - vfswrap_sys_acl_get_permset, - vfswrap_sys_acl_get_qualifier, - vfswrap_sys_acl_get_file, - vfswrap_sys_acl_get_fd, - vfswrap_sys_acl_clear_perms, - vfswrap_sys_acl_add_perm, - vfswrap_sys_acl_to_text, - vfswrap_sys_acl_init, - vfswrap_sys_acl_create_entry, - vfswrap_sys_acl_set_tag_type, - vfswrap_sys_acl_set_qualifier, - vfswrap_sys_acl_set_permset, - vfswrap_sys_acl_valid, - vfswrap_sys_acl_set_file, - vfswrap_sys_acl_set_fd, - vfswrap_sys_acl_delete_def_file, - vfswrap_sys_acl_get_perm, - vfswrap_sys_acl_free_text, - vfswrap_sys_acl_free_acl, - vfswrap_sys_acl_free_qualifier +static struct vfs_ops default_vfs = { + + { + /* Disk operations */ + + vfswrap_dummy_connect, + vfswrap_dummy_disconnect, + vfswrap_disk_free, + vfswrap_get_quota, + vfswrap_set_quota, + + /* Directory operations */ + + vfswrap_opendir, + vfswrap_readdir, + vfswrap_mkdir, + vfswrap_rmdir, + vfswrap_closedir, + + /* File operations */ + + vfswrap_open, + vfswrap_close, + vfswrap_read, + vfswrap_write, + vfswrap_lseek, + vfswrap_sendfile, + vfswrap_rename, + vfswrap_fsync, + vfswrap_stat, + vfswrap_fstat, + vfswrap_lstat, + vfswrap_unlink, + vfswrap_chmod, + vfswrap_fchmod, + vfswrap_chown, + vfswrap_fchown, + vfswrap_chdir, + vfswrap_getwd, + vfswrap_utime, + vfswrap_ftruncate, + vfswrap_lock, + vfswrap_symlink, + vfswrap_readlink, + vfswrap_link, + vfswrap_mknod, + vfswrap_realpath, + + /* Windows ACL operations. */ + vfswrap_fget_nt_acl, + vfswrap_get_nt_acl, + vfswrap_fset_nt_acl, + vfswrap_set_nt_acl, + + /* POSIX ACL operations. */ + vfswrap_chmod_acl, + vfswrap_fchmod_acl, + + vfswrap_sys_acl_get_entry, + vfswrap_sys_acl_get_tag_type, + vfswrap_sys_acl_get_permset, + vfswrap_sys_acl_get_qualifier, + vfswrap_sys_acl_get_file, + vfswrap_sys_acl_get_fd, + vfswrap_sys_acl_clear_perms, + vfswrap_sys_acl_add_perm, + vfswrap_sys_acl_to_text, + vfswrap_sys_acl_init, + vfswrap_sys_acl_create_entry, + vfswrap_sys_acl_set_tag_type, + vfswrap_sys_acl_set_qualifier, + vfswrap_sys_acl_set_permset, + vfswrap_sys_acl_valid, + vfswrap_sys_acl_set_file, + vfswrap_sys_acl_set_fd, + vfswrap_sys_acl_delete_def_file, + vfswrap_sys_acl_get_perm, + vfswrap_sys_acl_free_text, + vfswrap_sys_acl_free_acl, + vfswrap_sys_acl_free_qualifier, + + /* EA operations. */ + vfswrap_getxattr, + vfswrap_lgetxattr, + vfswrap_fgetxattr, + vfswrap_listxattr, + vfswrap_llistxattr, + vfswrap_flistxattr, + vfswrap_removexattr, + vfswrap_lremovexattr, + vfswrap_fremovexattr, + vfswrap_setxattr, + vfswrap_lsetxattr, + vfswrap_fsetxattr + + } }; /**************************************************************************** @@ -140,52 +150,46 @@ static struct vfs_ops default_vfs_ops = { static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name) { - struct vfs_init_function_entry *entry = backends; - pstring stripped; - - module_path_get_name(name, stripped); - - while(entry) { - if (strequal(entry->name, stripped)) return entry; - entry = entry->next; - } + struct vfs_init_function_entry *entry = backends; + + while(entry) { + if (strcmp(entry->name, name)==0) return entry; + entry = entry->next; + } - return NULL; + return NULL; } -NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *(*init)(const struct vfs_ops *, struct smb_vfs_handle_struct *)) +NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples) { - struct vfs_init_function_entry *entry = backends; - - if ((version < SMB_VFS_INTERFACE_CASCADED)) { - DEBUG(0, ("vfs_init() returned wrong interface version info (was %d, should be no less than %d)\n", - version, SMB_VFS_INTERFACE_VERSION )); - return NT_STATUS_OBJECT_TYPE_MISMATCH; - } - - if ((version < SMB_VFS_INTERFACE_VERSION)) { - DEBUG(0, ("Warning: vfs_init() states that module confirms interface version #%d, current interface version is #%d.\n\ - Proceeding in compatibility mode, new operations (since version #%d) will fallback to default ones.\n", - version, SMB_VFS_INTERFACE_VERSION, version )); - return NT_STATUS_OBJECT_TYPE_MISMATCH; - } - - if (!name || !init) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (vfs_find_backend_entry(name)) { - DEBUG(0,("VFS module %s already loaded!\n", name)); - return NT_STATUS_OBJECT_NAME_COLLISION; - } - - entry = smb_xmalloc(sizeof(struct vfs_init_function_entry)); - entry->name = smb_xstrdup(name); - entry->init = init; - - DLIST_ADD(backends, entry); - DEBUG(5, ("Successfully added vfs backend '%s'\n", name)); - return NT_STATUS_OK; + struct vfs_init_function_entry *entry = backends; + + if ((version != SMB_VFS_INTERFACE_VERSION)) { + DEBUG(0, ("Failed to register vfs module.\n" + "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n" + "current SMB_VFS_INTERFACE_VERSION is %d.\n" + "Please recompile against the current Samba Version!\n", + version, SMB_VFS_INTERFACE_VERSION)); + return NT_STATUS_OBJECT_TYPE_MISMATCH; + } + + if (!name || !name[0] || !vfs_op_tuples) { + DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (vfs_find_backend_entry(name)) { + DEBUG(0,("VFS module %s already loaded!\n", name)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + entry = smb_xmalloc(sizeof(struct vfs_init_function_entry)); + entry->name = smb_xstrdup(name); + entry->vfs_op_tuples = vfs_op_tuples; + + DLIST_ADD(backends, entry); + DEBUG(5, ("Successfully added vfs backend '%s'\n", name)); + return NT_STATUS_OK; } /**************************************************************************** @@ -196,62 +200,10 @@ static void vfs_init_default(connection_struct *conn) { DEBUG(3, ("Initialising default vfs hooks\n")); - memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(struct vfs_ops)); - conn->vfs_private = NULL; -} - -/*************************************************************************** - Function to load old VFS modules. Should go away after a while. - **************************************************************************/ - -static vfs_op_tuple *vfs_load_old_plugin(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 *); - /* Open object file */ - - if ((conn->vfs_private->handle = sys_dlopen(vfs_object, RTLD_NOW)) == NULL) { - DEBUG(0, ("Error opening %s: %s\n", vfs_object, sys_dlerror())); - return NULL; - } - - /* Get handle on vfs_init() symbol */ - - init_fptr = (vfs_op_tuple *(*)(int *, const struct vfs_ops *, struct smb_vfs_handle_struct *))sys_dlsym(conn->vfs_private->handle, "vfs_init"); - - if (init_fptr == NULL) { - DEBUG(0, ("No vfs_init() symbol found in %s\n", vfs_object)); - sys_dlclose(conn->vfs_private->handle); - return NULL; - } - - /* Initialise vfs_ops structure */ - if ((ops = init_fptr(&vfs_version, &conn->vfs_ops, conn->vfs_private)) == NULL) { - DEBUG(0, ("vfs_init() function from %s failed\n", vfs_object)); - sys_dlclose(conn->vfs_private->handle); - return NULL; - } - - if ((vfs_version < SMB_VFS_INTERFACE_CASCADED)) { - DEBUG(0, ("vfs_init() returned wrong interface version info (was %d, should be no less than %d)\n", - vfs_version, SMB_VFS_INTERFACE_VERSION )); - sys_dlclose(conn->vfs_private->handle); - return NULL; - } - - if ((vfs_version < SMB_VFS_INTERFACE_VERSION)) { - DEBUG(0, ("Warning: vfs_init() states that module confirms interface version #%d, current interface version is #%d.\n\ - Proceeding in compatibility mode, new operations (since version #%d) will fallback to default ones.\n", - vfs_version, SMB_VFS_INTERFACE_VERSION, vfs_version )); - sys_dlclose(conn->vfs_private->handle); - return NULL; - } - - return ops; + memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops)); + memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops)); } - - /**************************************************************************** initialise custom vfs hooks ****************************************************************************/ @@ -259,51 +211,82 @@ static vfs_op_tuple *vfs_load_old_plugin(connection_struct *conn, const char *vf BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object) { vfs_op_tuple *ops; + char *module_name = NULL; + char *module_param = NULL, *p; int i; + vfs_handle_struct *handle; struct vfs_init_function_entry *entry; - - DEBUG(3, ("Initialising custom vfs hooks from %s\n", vfs_object)); + + if (!conn||!vfs_object||!vfs_object[0]) { + DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n")); + return False; + } if(!backends) static_init_vfs; + DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object)); + + module_name = smb_xstrdup(vfs_object); + + p = strchr(module_name, ':'); + + if (p) { + *p = 0; + module_param = p+1; + trim_string(module_param, " ", " "); + } + + trim_string(module_name, " ", " "); + /* First, try to load the module with the new module system */ - if((entry = vfs_find_backend_entry(vfs_object)) || - (NT_STATUS_IS_OK(smb_probe_module("vfs", vfs_object)) && - (entry = vfs_find_backend_entry(vfs_object)))) { + if((entry = vfs_find_backend_entry(module_name)) || + (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) && + (entry = vfs_find_backend_entry(module_name)))) { - DEBUG(3,("Successfully loaded %s with the new modules system\n", vfs_object)); + DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object)); - if ((ops = entry->init(&conn->vfs_ops, conn->vfs_private)) == NULL) { - DEBUG(0, ("vfs init function from %s failed\n", vfs_object)); - return False; - } + if ((ops = entry->vfs_op_tuples) == NULL) { + DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object)); + SAFE_FREE(module_name); + return False; + } } else { - /* If that doesn't work, fall back to the old system - * (This part should go away after a while, it's only here - * for backwards compatibility) */ - DEBUG(2, ("Can't load module %s with new modules system, falling back to compatibility\n", - vfs_object)); - if ((ops = vfs_load_old_plugin(conn, vfs_object)) == NULL) { - DEBUG(0, ("vfs init function from %s failed\n", vfs_object)); - return False; - } + DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object)); + SAFE_FREE(module_name); + return False; + } + + handle = (vfs_handle_struct *)talloc_zero(conn->mem_ctx,sizeof(vfs_handle_struct)); + if (!handle) { + DEBUG(0,("talloc_zero() failed!\n")); + SAFE_FREE(module_name); + return False; } + memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops)); + handle->conn = conn; + if (module_param) { + handle->param = talloc_strdup(conn->mem_ctx, module_param); + } + DLIST_ADD(conn->vfs_handles, handle); for(i=0; ops[i].op != NULL; i++) { - DEBUG(3, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer)); + DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer)); if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) { /* Check whether this operation was already made opaque by different module */ - if(vfs_opaque_ops[ops[i].type].op == ((void**)&default_vfs_ops)[ops[i].type]) { + if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) { /* No, it isn't overloaded yet. Overload. */ - DEBUG(3, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object)); - vfs_opaque_ops[ops[i].type] = ops[i]; + DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object)); + ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op; + ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle; } } /* Change current VFS disposition*/ - DEBUG(3, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object)); - ((void**)&conn->vfs_ops)[ops[i].type] = ops[i].op; + DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object)); + ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op; + ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle; } + SAFE_FREE(module_name); return True; } @@ -314,71 +297,31 @@ BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object) BOOL smbd_vfs_init(connection_struct *conn) { const char **vfs_objects; - char *vfs_module, *vfs_path; unsigned int i = 0; int j = 0; - struct smb_vfs_handle_struct *handle; /* Normal share - initialise with disk access functions */ vfs_init_default(conn); - vfs_objects = lp_vfsobj(SNUM(conn)); + vfs_objects = lp_vfs_objects(SNUM(conn)); /* Override VFS functions if 'vfs object' was not specified*/ if (!vfs_objects || !vfs_objects[0]) return True; - - for(i=0; i<SMB_VFS_OP_LAST; i++) { - vfs_opaque_ops[i].op = ((void**)&default_vfs_ops)[i]; - vfs_opaque_ops[i].type = i; - vfs_opaque_ops[i].layer = SMB_VFS_LAYER_OPAQUE; + + for (i=0; vfs_objects[i] ;) { + i++; } - vfs_path = lp_vfs_path(SNUM(conn)); - - for (i=0; vfs_objects[i]; i++); /* count passed modules */ - for (j=i-1; j >= 0; j--) { - conn->vfs_private = NULL; - handle = (struct smb_vfs_handle_struct *) smb_xmalloc(sizeof(smb_vfs_handle_struct)); - /* Loadable object file */ - handle->handle = NULL; - DLIST_ADD(conn->vfs_private, handle); - vfs_module = NULL; - if (vfs_path && *vfs_path) { - asprintf(&vfs_module, "%s/%s", vfs_path, vfs_objects[j]); - } else { - asprintf(&vfs_module, "%s", vfs_objects[j]); - } - if (!vfs_init_custom(conn, vfs_module)) { - DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_module)); - SAFE_FREE(vfs_module); - DLIST_REMOVE(conn->vfs_private, handle); - SAFE_FREE(handle); + if (!vfs_init_custom(conn, vfs_objects[j])) { + DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j])); return False; } - SAFE_FREE(vfs_module); } return True; } /******************************************************************* - Create vfs_ops reflecting current vfs_opaque_ops -*******************************************************************/ - -struct vfs_ops *smb_vfs_get_opaque_ops(void) -{ - int i; - struct vfs_ops *ops; - - ops = smb_xmalloc(sizeof(struct vfs_ops)); - - for(i=0; i<SMB_VFS_OP_LAST; i++) { - ((void**)ops)[i] = vfs_opaque_ops[i].op; - } - return ops; -} - -/******************************************************************* Check if directory exists. ********************************************************************/ @@ -390,7 +333,7 @@ BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_ if (!st) st = &st2; - if (vfs_stat(conn,dname,st) != 0) + if (SMB_VFS_STAT(conn,dname,st) != 0) return(False); ret = S_ISDIR(st->st_mode); @@ -401,24 +344,15 @@ 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); -} - -/******************************************************************* vfs mkdir wrapper ********************************************************************/ -int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode) +int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode) { int ret; SMB_STRUCT_STAT sbuf; - if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) { + if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) { inherit_access_acl(conn, name, mode); @@ -428,8 +362,8 @@ int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode) * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir. */ if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) && - !vfs_stat(conn,name,&sbuf) && (mode & ~sbuf.st_mode)) - vfs_chmod(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode)); + !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode)) + SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode)); } return ret; } @@ -447,7 +381,7 @@ BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT ZERO_STRUCTP(sbuf); - if (vfs_stat(conn,fname,sbuf) == -1) + if (SMB_VFS_STAT(conn,fname,sbuf) == -1) return(False); return True; } @@ -465,7 +399,7 @@ BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT * ZERO_STRUCTP(sbuf); - if (vfs_stat(conn,fname,sbuf) == -1) + if (SMB_VFS_STAT(conn,fname,sbuf) == -1) return False; return(S_ISREG(sbuf->st_mode)); } @@ -480,7 +414,7 @@ ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count) while (total < byte_count) { - ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total, + ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total, byte_count - total); if (ret == 0) return total; @@ -505,7 +439,7 @@ ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N) ssize_t ret; while (total < N) { - ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total); + ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total); if (ret == -1) return -1; @@ -528,7 +462,6 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len) int ret; SMB_STRUCT_STAT st; connection_struct *conn = fsp->conn; - struct vfs_ops *vfs_ops = &conn->vfs_ops; SMB_BIG_UINT space_avail; SMB_BIG_UINT bsize,dfree,dsize; @@ -545,7 +478,7 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len) return -1; } - ret = vfs_fstat(fsp,fsp->fd,&st); + ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st); if (ret == -1) return ret; @@ -559,7 +492,7 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len) fsp->fsp_name, (double)st.st_size )); flush_write_cache(fsp, SIZECHANGE_FLUSH); - if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) { + if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) { set_filelen_write_cache(fsp, len); } return ret; @@ -572,7 +505,7 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len) len -= st.st_size; len /= 1024; /* Len is now number of 1k blocks needed. */ - space_avail = conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize); + space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize); DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n", fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail )); @@ -598,7 +531,7 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len) release_level_2_oplocks_on_change(fsp); DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len)); flush_write_cache(fsp, SIZECHANGE_FLUSH); - if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1) + if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1) set_filelen_write_cache(fsp, len); return ret; @@ -613,12 +546,12 @@ static files_struct *out_fsp; static ssize_t read_fn(int fd, void *buf, size_t len) { - return in_fsp->conn->vfs_ops.read(in_fsp, fd, buf, len); + return SMB_VFS_READ(in_fsp, fd, buf, len); } static ssize_t write_fn(int fd, const void *buf, size_t len) { - return out_fsp->conn->vfs_ops.write(out_fsp, fd, buf, len); + return SMB_VFS_WRITE(out_fsp, fd, buf, len); } SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n) @@ -635,13 +568,13 @@ SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n) char *vfs_readdirname(connection_struct *conn, void *p) { - struct dirent *ptr; + struct dirent *ptr= NULL; char *dname; if (!p) return(NULL); - ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p); + ptr = (struct dirent *)SMB_VFS_READDIR(conn,p); if (!ptr) return(NULL); @@ -660,72 +593,6 @@ char *vfs_readdirname(connection_struct *conn, void *p) return(dname); } -/* VFS options not quite working yet */ - -#if 0 - -/*************************************************************************** - handle the interpretation of the vfs option parameter - *************************************************************************/ -static BOOL handle_vfs_option(char *pszParmValue, char **ptr) -{ - struct vfs_options *new_option, **options = (struct vfs_options **)ptr; - int i; - - /* Create new vfs option */ - - new_option = (struct vfs_options *)malloc(sizeof(*new_option)); - if (new_option == NULL) { - return False; - } - - ZERO_STRUCTP(new_option); - - /* Get name and value */ - - new_option->name = strtok(pszParmValue, "="); - - if (new_option->name == NULL) { - return False; - } - - while(isspace(*new_option->name)) { - new_option->name++; - } - - for (i = strlen(new_option->name); i > 0; i--) { - if (!isspace(new_option->name[i - 1])) break; - } - - new_option->name[i] = '\0'; - new_option->name = strdup(new_option->name); - - new_option->value = strtok(NULL, "="); - - if (new_option->value != NULL) { - - while(isspace(*new_option->value)) { - new_option->value++; - } - - for (i = strlen(new_option->value); i > 0; i--) { - if (!isspace(new_option->value[i - 1])) break; - } - - new_option->value[i] = '\0'; - new_option->value = strdup(new_option->value); - } - - /* Add to list */ - - DLIST_ADD(*options, new_option); - - return True; -} - -#endif - - /******************************************************************* A wrapper for vfs_chdir(). ********************************************************************/ @@ -741,9 +608,9 @@ int vfs_ChDir(connection_struct *conn, const char *path) if (*path == '/' && strcsequal(LastDir,path)) return(0); - DEBUG(3,("vfs_ChDir to %s\n",path)); + DEBUG(4,("vfs_ChDir to %s\n",path)); - res = vfs_chdir(conn,path); + res = SMB_VFS_CHDIR(conn,path); if (!res) pstrcpy(LastDir,path); return(res); @@ -800,7 +667,7 @@ char *vfs_GetWd(connection_struct *conn, char *path) *s = 0; if (!use_getwd_cache) - return(vfs_getwd(conn,path)); + return(SMB_VFS_GETWD(conn,path)); /* init the cache */ if (!getwd_cache_init) { @@ -814,9 +681,9 @@ char *vfs_GetWd(connection_struct *conn, char *path) /* Get the inode of the current directory, if this doesn't work we're in trouble :-) */ - if (vfs_stat(conn, ".",&st) == -1) { + if (SMB_VFS_STAT(conn, ".",&st) == -1) { DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path)); - return(vfs_getwd(conn,path)); + return(SMB_VFS_GETWD(conn,path)); } @@ -830,7 +697,7 @@ char *vfs_GetWd(connection_struct *conn, char *path) the same...) */ if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) { - if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0) { + if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) { if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev && (st2.st_mode & S_IFMT) == S_IFDIR) { pstrcpy (path, ino_list[i].dos_path); @@ -852,8 +719,8 @@ char *vfs_GetWd(connection_struct *conn, char *path) The very slow getcwd, which spawns a process on some systems, or the not quite so bad getwd. */ - if (!vfs_getwd(conn,s)) { - DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno))); + if (!SMB_VFS_GETWD(conn,s)) { + DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno))); return (NULL); } @@ -909,7 +776,7 @@ static BOOL readlink_check(connection_struct *conn, const char *dir, char *name) realdir[reallen] = 0; } - if (conn->vfs_ops.readlink(conn, name, flink, sizeof(pstring) -1) != -1) { + if (SMB_VFS_READLINK(conn, name, flink, sizeof(pstring) -1) != -1) { DEBUG(3,("reduce_name: file path name %s is a symlink\nChecking it's path\n", name)); if (*flink == '/') { pstrcpy(cleanlink, flink); |