diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/blocking.c | 2 | ||||
-rw-r--r-- | source3/smbd/change_trust_pw.c | 5 | ||||
-rw-r--r-- | source3/smbd/chgpasswd.c | 113 | ||||
-rw-r--r-- | source3/smbd/fileio.c | 22 | ||||
-rw-r--r-- | source3/smbd/filename.c | 4 | ||||
-rw-r--r-- | source3/smbd/files.c | 28 | ||||
-rw-r--r-- | source3/smbd/lanman.c | 131 | ||||
-rw-r--r-- | source3/smbd/mangle_hash2.c | 49 | ||||
-rw-r--r-- | source3/smbd/message.c | 2 | ||||
-rw-r--r-- | source3/smbd/notify.c | 2 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 189 | ||||
-rw-r--r-- | source3/smbd/open.c | 13 | ||||
-rw-r--r-- | source3/smbd/password.c | 5 | ||||
-rw-r--r-- | source3/smbd/process.c | 17 | ||||
-rw-r--r-- | source3/smbd/reply.c | 307 | ||||
-rw-r--r-- | source3/smbd/sec_ctx.c | 2 | ||||
-rw-r--r-- | source3/smbd/server.c | 2 | ||||
-rw-r--r-- | source3/smbd/service.c | 9 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 22 | ||||
-rw-r--r-- | source3/smbd/statcache.c | 15 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 253 | ||||
-rw-r--r-- | source3/smbd/uid.c | 465 | ||||
-rw-r--r-- | source3/smbd/utmp.c | 10 | ||||
-rw-r--r-- | source3/smbd/vfs-wrap.c | 66 | ||||
-rw-r--r-- | source3/smbd/vfs.c | 6 |
25 files changed, 914 insertions, 825 deletions
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index fed3a51b88..8fa2a6494e 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -148,7 +148,7 @@ for fnum = %d, name = %s\n", length, (int)blr->expire_time, lock_timeout, blr->fsp->fnum, blr->fsp->fsp_name )); /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(inbuf,smb_mid)); + srv_defer_sign_response(SVAL(inbuf,smb_mid), True); return True; } diff --git a/source3/smbd/change_trust_pw.c b/source3/smbd/change_trust_pw.c index 2eff77b1f7..80c9fcb258 100644 --- a/source3/smbd/change_trust_pw.c +++ b/source3/smbd/change_trust_pw.c @@ -35,6 +35,9 @@ NTSTATUS change_trust_account_password( const char *domain, const char *remote_m fstring dc_name; struct cli_state *cli; + DEBUG(5,("change_trust_account_password: Attempting to change trust account password in domain %s....\n", + domain)); + if (remote_machine == NULL || !strcmp(remote_machine, "*")) { /* Use the PDC *only* for this */ @@ -92,6 +95,8 @@ failed: DEBUG(0,("%s : change_trust_account_password: Failed to change password for domain %s.\n", timestring(False), domain)); } + else + DEBUG(5,("change_trust_account_password: sucess!\n")); return nt_status; } diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index 6bc8626d81..d99570ff7c 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -259,7 +259,7 @@ static int expect(int master, char *issue, char *expected) /* Eat leading/trailing whitespace before match. */ pstring str; pstrcpy( str, buffer); - trim_string( str, " ", " "); + trim_char( str, ' ', ' '); if ((match = (unix_wild_match(expected, str) == 0))) timeout = 200; @@ -333,19 +333,14 @@ static BOOL chat_with_program(char *passwordprogram, struct passwd *pass, int wstat; BOOL chstat = False; - if (pass == NULL) - { - DEBUG(0, - ("chat_with_program: user doesn't exist in the UNIX password database.\n")); + if (pass == NULL) { + DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n")); return False; } /* allocate a pseudo-terminal device */ - if ((master = findpty(&slavedev)) < 0) - { - DEBUG(3, - ("Cannot Allocate pty for password change: %s\n", - pass->pw_name)); + if ((master = findpty(&slavedev)) < 0) { + DEBUG(3, ("Cannot Allocate pty for password change: %s\n", pass->pw_name)); return (False); } @@ -356,39 +351,29 @@ static BOOL chat_with_program(char *passwordprogram, struct passwd *pass, CatchChildLeaveStatus(); - if ((pid = sys_fork()) < 0) - { - DEBUG(3, - ("Cannot fork() child for password change: %s\n", - pass->pw_name)); + if ((pid = sys_fork()) < 0) { + DEBUG(3, ("Cannot fork() child for password change: %s\n", pass->pw_name)); close(master); CatchChild(); return (False); } /* we now have a pty */ - if (pid > 0) - { /* This is the parent process */ - if ((chstat = talktochild(master, chatsequence)) == False) - { - DEBUG(3, - ("Child failed to change password: %s\n", - pass->pw_name)); + if (pid > 0) { /* This is the parent process */ + if ((chstat = talktochild(master, chatsequence)) == False) { + DEBUG(3, ("Child failed to change password: %s\n", pass->pw_name)); kill(pid, SIGKILL); /* be sure to end this process */ } - while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) - { - if (errno == EINTR) - { + while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { + if (errno == EINTR) { errno = 0; continue; } break; } - if (wpid < 0) - { + if (wpid < 0) { DEBUG(3, ("The process is no longer waiting!\n\n")); close(master); CatchChild(); @@ -402,29 +387,21 @@ static BOOL chat_with_program(char *passwordprogram, struct passwd *pass, close(master); - if (pid != wpid) - { - DEBUG(3, - ("We were waiting for the wrong process ID\n")); + if (pid != wpid) { + DEBUG(3, ("We were waiting for the wrong process ID\n")); return (False); } - if (WIFEXITED(wstat) == 0) - { - DEBUG(3, - ("The process exited while we were waiting\n")); + if (WIFEXITED(wstat) == 0) { + DEBUG(3, ("The process exited while we were waiting\n")); return (False); } - if (WEXITSTATUS(wstat) != 0) - { - DEBUG(3, - ("The status of the process exiting was %d\n", + if (WEXITSTATUS(wstat) != 0) { + DEBUG(3, ("The status of the process exiting was %d\n", wstat)); return (False); } - } - else - { + } else { /* CHILD */ /* @@ -438,12 +415,9 @@ static BOOL chat_with_program(char *passwordprogram, struct passwd *pass, if (as_root) become_root(); - DEBUG(3, - ("Dochild for user %s (uid=%d,gid=%d)\n", pass->pw_name, - (int)getuid(), (int)getgid())); - chstat = - dochild(master, slavedev, pass, passwordprogram, - as_root); + DEBUG(3, ("Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name, + (int)getuid(), (int)getgid(), BOOLSTR(as_root) )); + chstat = dochild(master, slavedev, pass, passwordprogram, as_root); if (as_root) unbecome_root(); @@ -452,20 +426,16 @@ static BOOL chat_with_program(char *passwordprogram, struct passwd *pass, * The child should never return from dochild() .... */ - DEBUG(0, - ("chat_with_program: Error: dochild() returned %d\n", - chstat)); + DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat)); exit(1); } if (chstat) - DEBUG(3, - ("Password change %ssuccessful for user %s\n", + DEBUG(3, ("Password change %ssuccessful for user %s\n", (chstat ? "" : "un"), pass->pw_name)); return (chstat); } - BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root) { pstring passwordprogram; @@ -489,7 +459,7 @@ BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL oldpass = ""; } - DEBUG(3, ("Password change for user: %s\n", name)); + DEBUG(3, ("Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name)); #if DEBUG_PASSWORD DEBUG(100, ("Passwords: old=%s new=%s\n", oldpass, newpass)); @@ -519,8 +489,7 @@ BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL len = strlen(oldpass); for (i = 0; i < len; i++) { if (iscntrl((int)oldpass[i])) { - DEBUG(0, - ("chat_with_program: oldpass contains control characters (disallowed).\n")); + DEBUG(0, ("chat_with_program: oldpass contains control characters (disallowed).\n")); return False; } } @@ -528,8 +497,7 @@ BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL len = strlen(newpass); for (i = 0; i < len; i++) { if (iscntrl((int)newpass[i])) { - DEBUG(0, - ("chat_with_program: newpass contains control characters (disallowed).\n")); + DEBUG(0, ("chat_with_program: newpass contains control characters (disallowed).\n")); return False; } } @@ -556,11 +524,8 @@ BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL /* A non-PAM password change just doen't make sense without a valid local user */ - if (pass == NULL) - { - DEBUG(0, - ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", - name)); + if (pass == NULL) { + DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name)); return False; } @@ -746,7 +711,6 @@ NTSTATUS pass_oem_change(char *user, uchar * ntdata, uchar * nthash) { fstring new_passwd; - const char *unix_user; SAM_ACCOUNT *sampass = NULL; NTSTATUS nt_status = check_oem_password(user, lmdata, lmhash, ntdata, nthash, &sampass, new_passwd, sizeof(new_passwd)); @@ -754,20 +718,9 @@ NTSTATUS pass_oem_change(char *user, if (!NT_STATUS_IS_OK(nt_status)) return nt_status; - /* - * At this point we have the new case-sensitive plaintext - * password in the fstring new_passwd. If we wanted to synchronise - * with UNIX passwords we would call a UNIX password changing - * function here. However it would have to be done as root - * as the plaintext of the old users password is not - * available. JRA. - */ - - unix_user = pdb_get_username(sampass); - /* We've already checked the old password here.... */ become_root(); - nt_status = change_oem_password(sampass, NULL, new_passwd); + nt_status = change_oem_password(sampass, NULL, new_passwd, True); unbecome_root(); memset(new_passwd, 0, sizeof(new_passwd)); @@ -949,7 +902,7 @@ static NTSTATUS check_oem_password(const char *user, is correct before calling. JRA. ************************************************************/ -NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd) +NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd, BOOL as_root) { BOOL ret; uint32 min_len; @@ -993,7 +946,7 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw */ if(lp_unix_password_sync() && - !chgpasswd(pdb_get_username(hnd), old_passwd, new_passwd, False)) { + !chgpasswd(pdb_get_username(hnd), old_passwd, new_passwd, as_root)) { return NT_STATUS_ACCESS_DENIED; } diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index 6be5f6af7d..6cf7014846 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -87,8 +87,11 @@ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) * Serve from write cache if we can. */ - if(read_from_write_cache(fsp, data, pos, n)) + if(read_from_write_cache(fsp, data, pos, n)) { + fsp->pos = pos + n; + fsp->position_information = fsp->pos; return n; + } flush_write_cache(fsp, READ_FLUSH); @@ -123,6 +126,9 @@ tryagain: DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n", fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); + fsp->pos += ret; + fsp->position_information = fsp->pos; + return(ret); } @@ -145,6 +151,16 @@ static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_ DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n", fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); + if (ret != -1) { + fsp->pos += ret; + +/* Yes - this is correct - writes don't update this. JRA. */ +/* Found by Samba4 tests. */ +#if 0 + fsp->position_information = fsp->pos; +#endif + } + return ret; } @@ -244,7 +260,7 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", if(!wcp) { DO_PROFILE_INC(writecache_direct_writes); total_written = real_write_file(fsp, data, pos, n); - if ((total_written != -1) && (pos + total_written > (SMB_OFF_T)fsp->size)) + if ((total_written != -1) && (pos + total_written > (SMB_OFF_T)fsp->size)) fsp->size = (SMB_BIG_UINT)(pos + total_written); return total_written; } @@ -252,6 +268,8 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n", fsp->fsp_name, fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); + fsp->pos = pos + n; + /* * If we have active cache and it isn't contiguous then we flush. * NOTE: There is a small problem with running out of disk .... diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index ad107f9c3e..643e315c06 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -125,7 +125,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * also trim trailing /'s. */ - trim_string(name,"/","/"); + trim_char(name,'/','/'); /* * If we trimmed down to a single '\0' character @@ -164,7 +164,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen return(True); start = name; - while (strncmp(start,"./",2) == 0) + while (start[0] == '.' && start[1] == '/') start += 2; pstrcpy(orig_path, name); diff --git a/source3/smbd/files.c b/source3/smbd/files.c index f0fd6b7a73..1fe6f250e5 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -143,6 +143,22 @@ void file_close_conn(connection_struct *conn) } /**************************************************************************** + Close all open files for a pid. +****************************************************************************/ + +void file_close_pid(uint16 smbpid) +{ + files_struct *fsp, *next; + + for (fsp=Files;fsp;fsp=next) { + next = fsp->next; + if (fsp->file_pid == smbpid) { + close_file(fsp,False); + } + } +} + +/**************************************************************************** Initialise file structures. ****************************************************************************/ @@ -200,6 +216,18 @@ void file_close_user(int vuid) } } +void file_dump_open_table(void) +{ + int count=0; + files_struct *fsp; + + for (fsp=Files;fsp;fsp=fsp->next,count++) { + DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, fileid = %lu, dev = %x, inode = %.0f\n", + count, fsp->fnum, fsp->fsp_name, fsp->fd, (unsigned long)fsp->file_id, + (unsigned int)fsp->dev, (double)fsp->inode )); + } +} + /**************************************************************************** Find a fsp given a file descriptor. ****************************************************************************/ diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index a5f7a7b2ea..b27ccc23ef 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -1706,13 +1706,24 @@ static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *para int uLevel = SVAL(p,0); const char *level_string; int count=0; + SAM_ACCOUNT *sampw = NULL; + BOOL ret = False; + DOM_GID *gids = NULL; + int num_groups = 0; + int i; + fstring grp_domain; + fstring grp_name; + enum SID_NAME_USE grp_type; + DOM_SID sid, dom_sid; *rparam_len = 8; *rparam = REALLOC(*rparam,*rparam_len); /* check it's a supported varient */ - if (!strcmp(str1,"zWrLeh")) + + if ( strcmp(str1,"zWrLeh") != 0 ) return False; + switch( uLevel ) { case 0: level_string = "B21"; @@ -1732,18 +1743,59 @@ static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *para p = *rdata; - /* XXXX we need a real SAM database some day */ - pstrcpy(p,"Users"); p += 21; count++; - pstrcpy(p,"Domain Users"); p += 21; count++; - pstrcpy(p,"Guests"); p += 21; count++; - pstrcpy(p,"Domain Guests"); p += 21; count++; + /* Lookup the user information; This should only be one of + our accounts (not remote domains) */ + + pdb_init_sam( &sampw ); + + become_root(); /* ROOT BLOCK */ + + if ( !pdb_getsampwnam(sampw, UserName) ) + goto out; + + /* this next set of code is horribly inefficient, but since + it is rarely called, I'm going to leave it like this since + it easier to follow --jerry */ + + /* get the list of group SIDs */ + + if ( !get_domain_user_groups(conn->mem_ctx, &num_groups, &gids, sampw) ) { + DEBUG(1,("api_NetUserGetGroups: get_domain_user_groups() failed!\n")); + goto out; + } + /* convert to names (we don't support universal groups so the domain + can only be ours) */ + + sid_copy( &dom_sid, get_global_sam_sid() ); + for (i=0; i<num_groups; i++) { + + /* make the DOM_GID into a DOM_SID and then lookup + the name */ + + sid_copy( &sid, &dom_sid ); + sid_append_rid( &sid, gids[i].g_rid ); + + if ( lookup_sid(&sid, grp_domain, grp_name, &grp_type) ) { + pstrcpy(p, grp_name); + p += 21; + count++; + } + } + *rdata_len = PTR_DIFF(p,*rdata); SSVAL(*rparam,4,count); /* is this right?? */ SSVAL(*rparam,6,count); /* is this right?? */ - return(True); + ret = True; + +out: + unbecome_root(); /* END ROOT BLOCK */ + + pdb_free_sam( &sampw ); + + return ret; } /******************************************************************* @@ -1932,7 +1984,7 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) { become_root(); - if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2))) { + if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False))) { SSVAL(*rparam,0,NERR_Success); } unbecome_root(); @@ -1957,7 +2009,7 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) { become_root(); - if (change_lanman_password(hnd,pass2)) { + if (change_lanman_password(hnd,(uchar *)pass2)) { SSVAL(*rparam,0,NERR_Success); } unbecome_root(); @@ -1980,47 +2032,46 @@ static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char * char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - fstring user; - char *p = param + 2; - *rparam_len = 2; - *rparam = REALLOC(*rparam,*rparam_len); + fstring user; + char *p = param + 2; + *rparam_len = 2; + *rparam = REALLOC(*rparam,*rparam_len); - *rdata_len = 0; + *rdata_len = 0; - SSVAL(*rparam,0,NERR_badpass); + SSVAL(*rparam,0,NERR_badpass); - /* - * Check the parameter definition is correct. - */ - if(!strequal(param + 2, "zsT")) { - DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2)); - return False; - } - p = skip_string(p, 1); + /* + * Check the parameter definition is correct. + */ - if(!strequal(p, "B516B16")) { - DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p)); - return False; - } - p = skip_string(p,1); + if(!strequal(param + 2, "zsT")) { + DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2)); + return False; + } + p = skip_string(p, 1); - p += pull_ascii_fstring(user,p); + if(!strequal(p, "B516B16")) { + DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p)); + return False; + } + p = skip_string(p,1); + p += pull_ascii_fstring(user,p); - DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user)); + DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user)); - /* - * Pass the user through the NT -> unix user mapping - * function. - */ + /* + * Pass the user through the NT -> unix user mapping + * function. + */ - (void)map_username(user); + (void)map_username(user); - if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))) - { - SSVAL(*rparam,0,NERR_Success); - } + if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))) { + SSVAL(*rparam,0,NERR_Success); + } - return(True); + return(True); } /**************************************************************************** diff --git a/source3/smbd/mangle_hash2.c b/source3/smbd/mangle_hash2.c index cdce28e1bd..9cd0438d51 100644 --- a/source3/smbd/mangle_hash2.c +++ b/source3/smbd/mangle_hash2.c @@ -201,22 +201,24 @@ static const char *cache_lookup(u32 hash) In this algorithm, mangled names use only pure ascii characters (no multi-byte) so we can avoid doing a UCS2 conversion */ -static BOOL is_mangled_component(const char *name) +static BOOL is_mangled_component(const char *name, size_t len) { - unsigned int len, i; + unsigned int i; - M_DEBUG(10,("is_mangled_component %s ?\n", name)); + M_DEBUG(10,("is_mangled_component %s (len %u) ?\n", name, (unsigned int)len)); /* check the length */ - len = strlen(name); - if (len > 12 || len < 8) return False; + if (len > 12 || len < 8) + return False; /* the best distinguishing characteristic is the ~ */ - if (name[6] != '~') return False; + if (name[6] != '~') + return False; /* check extension */ if (len > 8) { - if (name[8] != '.') return False; + if (name[8] != '.') + return False; for (i=9; name[i]; i++) { if (! FLAG_CHECK(name[i], FLAG_ASCII)) { return False; @@ -241,7 +243,7 @@ static BOOL is_mangled_component(const char *name) } } - M_DEBUG(10,("is_mangled %s -> yes\n", name)); + M_DEBUG(10,("is_mangled_component %s (len %u) -> yes\n", name, (unsigned int)len)); return True; } @@ -267,16 +269,13 @@ static BOOL is_mangled(const char *name) M_DEBUG(10,("is_mangled %s ?\n", name)); for (s=name; (p=strchr(s, '/')); s=p+1) { - char *component = strndup(s, PTR_DIFF(p, s)); - if (is_mangled_component(component)) { - free(component); + if (is_mangled_component(s, PTR_DIFF(p, s))) { return True; } - free(component); } /* and the last part ... */ - return is_mangled_component(s); + return is_mangled_component(s,strlen(s)); } @@ -305,7 +304,8 @@ static BOOL is_8_3(const char *name, BOOL check_case, BOOL allow_wildcards) the result we need in this case. Using strlen_m would not only be slower, it would be incorrect */ len = strlen(name); - if (len > 12) return False; + if (len > 12) + return False; /* find the '.'. Note that once again we use the non-multibyte function */ @@ -449,6 +449,27 @@ static BOOL is_legal_name(const char *name) size_t numdots = 0; while (*name) { + if (((unsigned int)name[0]) > 128 && (name[1] != 0)) { + /* Possible start of mb character. */ + char mbc[2]; + /* + * We know the following will return 2 bytes. What + * we need to know was if errno was set. + * Note that if CH_UNIX is utf8 a string may be 3 + * bytes, but this is ok as mb utf8 characters don't + * contain embedded ascii bytes. We are really checking + * for mb UNIX asian characters like Japanese (SJIS) here. + * JRA. + */ + errno = 0; + convert_string(CH_UNIX, CH_UCS2, name, 2, mbc, 2); + if (!errno) { + /* Was a good mb string. */ + name += 2; + continue; + } + } + if (FLAG_CHECK(name[0], FLAG_ILLEGAL)) { return False; } diff --git a/source3/smbd/message.c b/source3/smbd/message.c index 233848d2d6..88f833e468 100644 --- a/source3/smbd/message.c +++ b/source3/smbd/message.c @@ -64,7 +64,7 @@ static void msg_deliver(void) * Incoming message is in DOS codepage format. Convert to UNIX. */ - if ((len = convert_string_allocate(CH_DOS, CH_UNIX, msgbuf, msgpos, (void **) &msg)) < 0 || !msg) { + if ((len = convert_string_allocate(NULL,CH_DOS, CH_UNIX, msgbuf, msgpos, (void **) &msg)) < 0 || !msg) { DEBUG(3,("Conversion failed, delivering message in DOS codepage format\n")); for (i = 0; i < msgpos;) { if (msgbuf[i] == '\r' && i < (msgpos-1) && msgbuf[i+1] == '\n') { diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index 9adf827c79..ca6f2b783f 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -199,7 +199,7 @@ BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, DLIST_ADD(change_notify_list, cnbp); /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(inbuf,smb_mid)); + srv_defer_sign_response(SVAL(inbuf,smb_mid), True); return True; } diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 3ffa6efa77..f8bd3ae15f 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -762,9 +762,8 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib restore_case_semantics(file_attributes); if(!fsp) { - set_bad_path_error(errno, bad_path); END_PROFILE(SMBntcreateX); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } else { /* @@ -838,16 +837,14 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib if(!fsp) { restore_case_semantics(file_attributes); - set_bad_path_error(errno, bad_path); END_PROFILE(SMBntcreateX); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } else { restore_case_semantics(file_attributes); - set_bad_path_error(errno, bad_path); END_PROFILE(SMBntcreateX); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } } @@ -1279,8 +1276,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o if(!fsp) { restore_case_semantics(file_attributes); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } else { @@ -1312,13 +1308,11 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o if(!fsp) { restore_case_semantics(file_attributes); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } else { restore_case_semantics(file_attributes); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } @@ -1724,7 +1718,11 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou char **ppparams, uint32 parameter_count, char **ppdata, uint32 data_count) { - unsigned fnum, control; + uint32 function; + uint16 fidnum; + files_struct *fsp; + uint8 isFSctl; + uint8 compfilter; static BOOL logged_message; char *pdata = *ppdata; @@ -1733,19 +1731,26 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } - fnum = SVAL(*ppsetup, 4); - control = IVAL(*ppsetup, 0); + function = IVAL(*ppsetup, 0); + fidnum = SVAL(*ppsetup, 4); + isFSctl = CVAL(*ppsetup, 6); + compfilter = CVAL(*ppsetup, 7); + + DEBUG(10,("call_nt_transact_ioctl: function[0x%08X] FID[0x%04X] isFSctl[0x%02X] compfilter[0x%02X]\n", + function, fidnum, isFSctl, compfilter)); - DEBUG(10,("call_nt_transact_ioctl: fnum=%d control=0x%08x\n", - fnum, control)); + fsp=file_fsp(*ppsetup, 4); + /* this check is done in each implemented function case for now + because I don't want to break anything... --metze + FSP_BELONGS_CONN(fsp,conn);*/ - switch (control) { + switch (function) { 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)); + DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum)); send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); return -1; @@ -1754,7 +1759,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou but works ok like this --metze */ - DEBUG(10,("FSCTL_GET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control)); + DEBUG(10,("FSCTL_0x000900C0: called on FID[0x%04X](but not implemented)\n",fidnum)); send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); return -1; @@ -1763,7 +1768,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou * --metze */ - DEBUG(10,("FSCTL_GET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control)); + DEBUG(10,("FSCTL_GET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0); return -1; @@ -1772,10 +1777,125 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou * --metze */ - DEBUG(10,("FSCTL_SET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control)); + DEBUG(10,("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0); return -1; + case FSCTL_GET_SHADOW_COPY_DATA: /* don't know if this name is right...*/ + { + /* + * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots) + * and return their volume names. If max_data_count is 16, then it is just + * asking for the number of volumes and length of the combined names. + * + * pdata is the data allocated by our caller, but that uses + * total_data_count (which is 0 in our case) rather than max_data_count. + * Allocate the correct amount and return the pointer to let + * it be deallocated when we return. + */ + uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); + SHADOW_COPY_DATA *shadow_data = NULL; + TALLOC_CTX *shadow_mem_ctx = NULL; + BOOL labels = False; + uint32 labels_data_count = 0; + uint32 i; + char *cur_pdata; + + FSP_BELONGS_CONN(fsp,conn); + + if (max_data_count < 16) { + DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n", + max_data_count)); + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); + } + + if (max_data_count > 16) { + labels = True; + } + + shadow_mem_ctx = talloc_init("SHADOW_COPY_DATA"); + if (shadow_mem_ctx == NULL) { + DEBUG(0,("talloc_init(SHADOW_COPY_DATA) failed!\n")); + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + shadow_data = (SHADOW_COPY_DATA *)talloc_zero(shadow_mem_ctx,sizeof(SHADOW_COPY_DATA)); + if (shadow_data == NULL) { + DEBUG(0,("talloc_zero() failed!\n")); + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + shadow_data->mem_ctx = shadow_mem_ctx; + + /* + * Call the VFS routine to actually do the work. + */ + if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) { + talloc_destroy(shadow_data->mem_ctx); + if (errno == ENOSYS) { + DEBUG(5,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, not supported.\n", + conn->connectpath)); + return ERROR_NT(NT_STATUS_NOT_SUPPORTED); + } else { + DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, failed.\n", + conn->connectpath)); + return ERROR_NT(NT_STATUS_UNSUCCESSFUL); + } + } + + labels_data_count = (shadow_data->num_volumes*2*sizeof(SHADOW_COPY_LABEL))+2; + + if (!labels) { + data_count = 16; + } else { + data_count = 12+labels_data_count+4; + } + + if (max_data_count<data_count) { + DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n", + max_data_count,data_count)); + talloc_destroy(shadow_data->mem_ctx); + return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL); + } + + pdata = nttrans_realloc(ppdata, data_count); + if (pdata == NULL) { + talloc_destroy(shadow_data->mem_ctx); + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + cur_pdata = pdata; + + /* num_volumes 4 bytes */ + SIVAL(pdata,0,shadow_data->num_volumes); + + if (labels) { + /* num_labels 4 bytes */ + SIVAL(pdata,4,shadow_data->num_volumes); + } + + /* needed_data_count 4 bytes */ + SIVAL(pdata,8,labels_data_count); + + cur_pdata+=12; + + DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n", + shadow_data->num_volumes,fsp->fsp_name)); + if (labels && shadow_data->labels) { + for (i=0;i<shadow_data->num_volumes;i++) { + srvstr_push(outbuf, cur_pdata, shadow_data->labels[i], 2*sizeof(SHADOW_COPY_LABEL), STR_UNICODE|STR_TERMINATE); + cur_pdata+=2*sizeof(SHADOW_COPY_LABEL); + DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i])); + } + } + + talloc_destroy(shadow_data->mem_ctx); + + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, pdata, data_count); + + return -1; + } + case FSCTL_FIND_FILES_BY_SID: /* I hope this name is right */ { /* pretend this succeeded - @@ -1783,24 +1903,24 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou * 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)); + size_t sid_len = MIN(data_count-4,SID_MAX_SIZE); - /* 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));*/ + DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n",fidnum)); + + FSP_BELONGS_CONN(fsp,conn); + + /* unknown 4 bytes: this is not the length of the sid :-( */ + /*unknown = IVAL(pdata,0);*/ sid_parse(pdata+4,sid_len,&sid); - DEBUGADD(10,("SID: %s\n",sid_string_static(&sid))); + DEBUGADD(10,("for 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))); + DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%u]\n", + sid_string_static(&sid),sid_len)); uid = (-1); } @@ -1813,6 +1933,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou * for each file * * but I don't know how to deal with the paged results + * (maybe we can hang the result anywhere in the fsp struct) * * we don't send all files at once * and at the next we should *not* start from the beginning, @@ -1829,7 +1950,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou if (!logged_message) { logged_message = True; /* Only print this once... */ DEBUG(0,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n", - control)); + function)); } } diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 5f49640aa4..71af23aaf9 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -23,6 +23,7 @@ extern userdom_struct current_user_info; extern uint16 global_oplock_port; +extern uint16 global_smbpid; extern BOOL global_client_failed_oplock_break; /**************************************************************************** @@ -226,8 +227,8 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, fsp->inode = psbuf->st_ino; fsp->dev = psbuf->st_dev; fsp->vuid = current_user.vuid; + fsp->file_pid = global_smbpid; fsp->size = psbuf->st_size; - fsp->pos = -1; fsp->can_lock = True; fsp->can_read = ((flags & O_WRONLY)==0); fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0); @@ -626,6 +627,12 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T DEBUG(5,("open_mode_check: oplock_request = %d, breaking oplock (%x) on file %s, \ dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsigned int)dev, (double)inode)); + /* Ensure the reply for the open uses the correct sequence number. */ + /* This isn't a real deferred packet as it's response will also increment + * the sequence. + */ + srv_defer_sign_response(get_current_mid(), False); + /* Oplock break - unlock to request it. */ unlock_share_entry(conn, dev, inode); @@ -1356,7 +1363,7 @@ files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_ST fsp->dev = psbuf->st_dev; fsp->size = psbuf->st_size; fsp->vuid = current_user.vuid; - fsp->pos = -1; + fsp->file_pid = global_smbpid; fsp->can_lock = True; fsp->can_read = False; fsp->can_write = False; @@ -1419,7 +1426,7 @@ files_struct *open_file_stat(connection_struct *conn, char *fname, SMB_STRUCT_ST fsp->dev = (SMB_DEV_T)0; fsp->size = psbuf->st_size; fsp->vuid = current_user.vuid; - fsp->pos = -1; + fsp->file_pid = global_smbpid; fsp->can_lock = False; fsp->can_read = False; fsp->can_write = False; diff --git a/source3/smbd/password.c b/source3/smbd/password.c index b988f2ec74..32c24b3d67 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -28,6 +28,9 @@ static user_struct *validated_users; static int next_vuid = VUID_OFFSET; static int num_validated_vuids; +extern userdom_struct current_user_info; + + /**************************************************************************** Check if a uid has been validated, and return an pointer to the user_struct if it has. NULL if not. vuid is biased by an offset. This allows us to @@ -296,7 +299,7 @@ BOOL user_ok(const char *user,int snum, gid_t *groups, size_t n_groups) if (ret && lp_valid_users(snum)) { str_list_copy(&valid, lp_valid_users(snum)); - if (valid && str_list_substitute(valid, "%S", lp_servicename(snum))) { + if ( valid && str_list_sub_basic(valid, current_user_info.smb_name) ) { ret = user_in_list(user, (const char **)valid, groups, n_groups); } } diff --git a/source3/smbd/process.c b/source3/smbd/process.c index dce1c4bc03..3c15cd1833 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -48,6 +48,15 @@ BOOL global_machine_password_needs_changing = False; extern int max_send; /**************************************************************************** + Function to return the current request mid from Inbuffer. +****************************************************************************/ + +uint16 get_current_mid(void) +{ + return SVAL(InBuffer,smb_mid); +} + +/**************************************************************************** structure to hold a linked list of queued messages. for processing. ****************************************************************************/ @@ -88,7 +97,7 @@ static BOOL push_message(ubi_slList *list_head, char *buf, int msg_len) ubi_slAddTail( list_head, msg); /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(buf,smb_mid)); + srv_defer_sign_response(SVAL(buf,smb_mid), True); return True; } @@ -710,7 +719,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize if(session_tag != UID_FIELD_INVALID) vuser = get_valid_user_struct(session_tag); if(vuser != NULL) - current_user_info = vuser->user; + set_current_user_info(&vuser->user); } /* does this protocol need to be run as root? */ @@ -1256,8 +1265,10 @@ void smbd_process(void) if ((InBuffer == NULL) || (OutBuffer == NULL)) return; +#if defined(DEVELOPER) clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size); clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer, total_buffer_size); +#endif max_recv = MIN(lp_maxxmit(),BUFFER_SIZE); @@ -1286,7 +1297,9 @@ void smbd_process(void) num_smbs = 0; /* Reset smb counter. */ } +#if defined(DEVELOPER) clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size); +#endif while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,select_timeout)) { if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time)) diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 71312295f4..6ac4cffddb 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -39,6 +39,21 @@ unsigned int smb_echo_count = 0; extern BOOL global_encrypted_passwords_negotiated; /**************************************************************************** + Ensure we check the path in the same way as W2K. +****************************************************************************/ + +static NTSTATUS check_path_syntax(const char *name) +{ + while (*name == '\\') + name++; + if (strequal(name, ".")) + return NT_STATUS_OBJECT_NAME_INVALID; + else if (strequal(name, "..")) + return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; + return NT_STATUS_OK; +} + +/**************************************************************************** Reply to a special message. ****************************************************************************/ @@ -333,7 +348,6 @@ int reply_ioctl(connection_struct *conn, uint32 ioctl_code = (device << 16) + function; int replysize, outsize; char *p; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); START_PROFILE(SMBioctl); DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code)); @@ -356,6 +370,11 @@ int reply_ioctl(connection_struct *conn, switch (ioctl_code) { case IOCTL_QUERY_JOB_INFO: { + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + if (!fsp) { + END_PROFILE(SMBioctl); + return(UNIXERROR(ERRDOS,ERRbadfid)); + } SSVAL(p,0,fsp->rap_print_jobid); /* Job number */ srvstr_push(outbuf, p+2, global_myname(), 15, STR_TERMINATE|STR_ASCII); srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII); @@ -379,10 +398,16 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size BOOL ok = False; BOOL bad_path = False; SMB_STRUCT_STAT sbuf; + NTSTATUS status; + START_PROFILE(SMBchkpth); srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE); + status = check_path_syntax(name); + if (!NT_STATUS_IS_OK(status)) + return ERROR_NT(status); + RESOLVE_DFSPATH(name, conn, inbuf, outbuf); unix_convert(name,conn,0,&bad_path,&sbuf); @@ -401,8 +426,21 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size one at a time - if a component fails it expects ERRbadpath, not ERRbadfile. */ - if(errno == ENOENT) - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + if(errno == ENOENT) { + /* + * Windows returns different error codes if + * the parent directory is valid but not the + * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND + * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND + * if the path is invalid. + */ + if (bad_path) { + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } else { + return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND); + } + } else if (errno == ENOTDIR) + return ERROR_NT(NT_STATUS_NOT_A_DIRECTORY); return(UNIXERROR(ERRDOS,ERRbadpath)); } @@ -463,9 +501,8 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size } if (!ok) { - set_bad_path_error(errno, bad_path); END_PROFILE(SMBgetatr); - return(UNIXERROR(ERRDOS,ERRbadfile)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadfile); } outsize = set_message(outbuf,10,0,True); @@ -510,20 +547,24 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size mode = SVAL(inbuf,smb_vwv0); mtime = make_unix_date3(inbuf+smb_vwv1); - if (VALID_STAT_OF_DIR(sbuf)) - mode |= aDIR; - else - mode &= ~aDIR; + if (mode != FILE_ATTRIBUTE_NORMAL) { + if (VALID_STAT_OF_DIR(sbuf)) + mode |= aDIR; + else + mode &= ~aDIR; + + if (check_name(fname,conn)) + ok = (file_chmod(conn,fname,mode,NULL) == 0); + } else { + ok = True; + } - if (check_name(fname,conn)) - ok = (file_chmod(conn,fname,mode,NULL) == 0); if (ok) ok = set_filetime(conn,fname,mtime); if (!ok) { - set_bad_path_error(errno, bad_path); END_PROFILE(SMBsetatr); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); } outsize = set_message(outbuf,0,0,True); @@ -684,9 +725,8 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid)); if (dptr_num < 0) { if(dptr_num == -2) { - set_bad_path_error(errno, bad_path); END_PROFILE(SMBsearch); - return (UNIXERROR(ERRDOS,ERRnofids)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnofids); } END_PROFILE(SMBsearch); return ERROR_DOS(ERRDOS,ERRnofids); @@ -732,21 +772,23 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size SearchEmpty: - if (numentries == 0 || !ok) { - SCVAL(outbuf,smb_rcls,ERRDOS); - SSVAL(outbuf,smb_err,ERRnofiles); - dptr_close(&dptr_num); - } - /* If we were called as SMBffirst with smb_search_id == NULL and no entries were found then return error and close dirptr (X/Open spec) */ if(ok && expect_close && numentries == 0 && status_len == 0) { - SCVAL(outbuf,smb_rcls,ERRDOS); - SSVAL(outbuf,smb_err,ERRnofiles); + if (Protocol < PROTOCOL_NT1) { + SCVAL(outbuf,smb_rcls,ERRDOS); + SSVAL(outbuf,smb_err,ERRnofiles); + } /* Also close the dptr - we know it's gone */ dptr_close(&dptr_num); + } else if (numentries == 0 || !ok) { + if (Protocol < PROTOCOL_NT1) { + SCVAL(outbuf,smb_rcls,ERRDOS); + SSVAL(outbuf,smb_err,ERRnofiles); + } + dptr_close(&dptr_num); } /* If we were called as SMBfunique, then we can close the dirptr now ! */ @@ -851,9 +893,8 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, unixmode, oplock_request,&rmode,NULL); if (!fsp) { - set_bad_path_error(errno, bad_path); END_PROFILE(SMBopen); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); } size = sbuf.st_size; @@ -939,9 +980,8 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt oplock_request, &rmode,&smb_action); if (!fsp) { - set_bad_path_error(errno, bad_path); END_PROFILE(SMBopenX); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); } size = sbuf.st_size; @@ -1063,9 +1103,8 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, ofun, unixmode, oplock_request, NULL, NULL); if (!fsp) { - set_bad_path_error(errno, bad_path); END_PROFILE(SMBcreate); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); } outsize = set_message(outbuf,1,0,True); @@ -1132,9 +1171,8 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, close(tmpfd); if (!fsp) { - set_bad_path_error(errno, bad_path); END_PROFILE(SMBctemp); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess); } outsize = set_message(outbuf,1,0,True); @@ -1215,6 +1253,9 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) int access_mode; files_struct *fsp; + DEBUG(10,("can_delete: %s, dirtype = %d\n", + fname, dirtype )); + if (!CAN_WRITE(conn)) return NT_STATUS_MEDIA_WRITE_PROTECTED; @@ -1222,14 +1263,21 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) return NT_STATUS_OBJECT_NAME_NOT_FOUND; fmode = dos_mode(conn,fname,&sbuf); + + /* Can't delete a directory. */ if (fmode & aDIR) return NT_STATUS_FILE_IS_A_DIRECTORY; +#if 0 /* JRATEST */ + else if (dirtype & aDIR) /* Asked for a directory and it isn't. */ + return NT_STATUS_OBJECT_NAME_INVALID; +#endif /* JRATEST */ + if (!lp_delete_readonly(SNUM(conn))) { if (fmode & aRONLY) return NT_STATUS_CANNOT_DELETE; } if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) - return NT_STATUS_CANNOT_DELETE; + return NT_STATUS_NO_SUCH_FILE; /* We need a better way to return NT status codes from open... */ unix_ERR_class = 0; @@ -1329,7 +1377,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) */ if (dirptr) { - error = NT_STATUS_OBJECT_NAME_NOT_FOUND; + error = NT_STATUS_NO_SUCH_FILE; if (strequal(mask,"????????.???")) pstrcpy(mask,"*"); @@ -1377,6 +1425,10 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE); + status = check_path_syntax(name); + if (!NT_STATUS_IS_OK(status)) + return ERROR_NT(status); + RESOLVE_DFSPATH(name, conn, inbuf, outbuf); DEBUG(3,("reply_unlink : %s\n",name)); @@ -2262,39 +2314,25 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int switch (mode) { case 0: umode = SEEK_SET; + res = startpos; break; case 1: umode = SEEK_CUR; + res = fsp->pos + startpos; break; case 2: umode = SEEK_END; break; default: umode = SEEK_SET; + res = startpos; break; } - 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, - * section 4.2.7. - */ - - if(errno == EINVAL) { - SMB_OFF_T current_pos = startpos; - - if(umode == SEEK_CUR) { - - if((current_pos = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_CUR)) == -1) { - END_PROFILE(SMBlseek); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - current_pos += startpos; - - } else if (umode == SEEK_END) { - + if (umode == SEEK_END) { + if((res = SMB_VFS_LSEEK(fsp,fsp->fd,startpos,umode)) == -1) { + if(errno == EINVAL) { + SMB_OFF_T current_pos = startpos; SMB_STRUCT_STAT sbuf; if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1) { @@ -2303,10 +2341,9 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int } current_pos += sbuf.st_size; + if(current_pos < 0) + res = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_SET); } - - if(current_pos < 0) - res = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_SET); } if(res == -1) { @@ -2334,10 +2371,12 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { int outsize = set_message(outbuf,0,0,True); + uint16 fnum = SVAL(inbuf,smb_vwv0); files_struct *fsp = file_fsp(inbuf,smb_vwv0); START_PROFILE(SMBflush); - CHECK_FSP(fsp,conn); + if (fnum != 0xFFFF) + CHECK_FSP(fsp,conn); if (!fsp) { file_sync_all(conn); @@ -2359,6 +2398,9 @@ int reply_exit(connection_struct *conn, { int outsize; START_PROFILE(SMBexit); + + file_close_pid(SVAL(inbuf,smb_pid)); + outsize = set_message(outbuf,0,0,True); DEBUG(3,("exit\n")); @@ -2704,7 +2746,7 @@ int reply_printclose(connection_struct *conn, if (!CAN_PRINT(conn)) { END_PROFILE(SMBsplclose); - return ERROR_DOS(ERRDOS,ERRnoaccess); + return ERROR_NT(NT_STATUS_UNSUCCESSFUL); } DEBUG(3,("printclose fd=%d fnum=%d\n", @@ -2849,7 +2891,17 @@ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory) ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory)); if (ret == -1) { - NTSTATUS nterr = set_bad_path_error(errno, bad_path); + NTSTATUS nterr = NT_STATUS_OK; + if(errno == ENOENT) { + unix_ERR_class = ERRDOS; + if (bad_path) { + unix_ERR_code = ERRbadpath; + nterr = NT_STATUS_OBJECT_PATH_NOT_FOUND; + } else { + unix_ERR_code = ERRbadfile; + nterr = NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + } if (!NT_STATUS_IS_OK(nterr)) return nterr; return map_nt_error_from_unix(errno); @@ -3044,9 +3096,8 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, } if (!ok) { - set_bad_path_error(errno, bad_path); END_PROFILE(SMBrmdir); - return(UNIXERROR(ERRDOS,ERRbadpath)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRbadpath); } outsize = set_message(outbuf,0,0,True); @@ -3130,6 +3181,130 @@ static BOOL resolve_wildcards(const char *name1, char *name2) } /**************************************************************************** + Ensure open files have their names updates. +****************************************************************************/ + +static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode, char *newname) +{ + files_struct *fsp; + BOOL did_rename = False; + + for(fsp = file_find_di_first(dev, inode); fsp; fsp = file_find_di_next(fsp)) { + DEBUG(10,("rename_open_files: renaming file fnum %d (dev = %x, inode = %.0f) from %s -> %s\n", + fsp->fnum, (unsigned int)fsp->dev, (double)fsp->inode, + fsp->fsp_name, newname )); + string_set(&fsp->fsp_name, newname); + did_rename = True; + } + + if (!did_rename) + DEBUG(10,("rename_open_files: no open files on dev %x, inode %.0f for %s\n", + (unsigned int)dev, (double)inode, newname )); +} + +/**************************************************************************** + Rename an open file - given an fsp. +****************************************************************************/ + +NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, BOOL replace_if_exists) +{ + SMB_STRUCT_STAT sbuf; + BOOL bad_path = False; + pstring newname_last_component; + NTSTATUS error = NT_STATUS_OK; + BOOL dest_exists; + + ZERO_STRUCT(sbuf); + unix_convert(newname,conn,newname_last_component,&bad_path,&sbuf); + + /* Ensure newname contains a '/' */ + if(strrchr_m(newname,'/') == 0) { + pstring tmpstr; + + pstrcpy(tmpstr, "./"); + pstrcat(tmpstr, newname); + pstrcpy(newname, tmpstr); + } + + /* + * Check for special case with case preserving and not + * case sensitive. If the old last component differs from the original + * last component only by case, then we should allow + * the rename (user is trying to change the case of the + * filename). + */ + + if((case_sensitive == False) && (case_preserve == True) && + strequal(newname, fsp->fsp_name)) { + char *p; + pstring newname_modified_last_component; + + /* + * Get the last component of the modified name. + * Note that we guarantee that newname contains a '/' + * character above. + */ + p = strrchr_m(newname,'/'); + pstrcpy(newname_modified_last_component,p+1); + + if(strcsequal(newname_modified_last_component, + newname_last_component) == False) { + /* + * Replace the modified last component with + * the original. + */ + pstrcpy(p+1, newname_last_component); + } + } + + /* + * If the src and dest names are identical - including case, + * don't do the rename, just return success. + */ + + if (strcsequal(fsp->fsp_name, newname)) { + DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n", + newname)); + return NT_STATUS_OK; + } + + dest_exists = vfs_object_exist(conn,newname,NULL); + + if(!replace_if_exists && dest_exists) { + DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n", + fsp->fsp_name,newname)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + error = can_rename(newname,conn,&sbuf); + + if (dest_exists && !NT_STATUS_IS_OK(error)) { + DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", + nt_errstr(error), fsp->fsp_name,newname)); + if (NT_STATUS_EQUAL(error,NT_STATUS_SHARING_VIOLATION)) + error = NT_STATUS_ACCESS_DENIED; + return error; + } + + if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) { + DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n", + fsp->fsp_name,newname)); + rename_open_files(conn, fsp->dev, fsp->inode, newname); + return NT_STATUS_OK; + } + + if (errno == ENOTDIR || errno == EISDIR) + error = NT_STATUS_OBJECT_NAME_COLLISION; + else + error = map_nt_error_from_unix(errno); + + DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n", + nt_errstr(error), fsp->fsp_name,newname)); + + return error; +} + +/**************************************************************************** The guts of the rename command, split out so it may be called by the NT SMB code. ****************************************************************************/ @@ -3150,6 +3325,8 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO *directory = *mask = 0; + ZERO_STRUCT(sbuf1); + ZERO_STRUCT(sbuf2); rc = unix_convert(name,conn,0,&bad_path1,&sbuf1); unix_convert(newname,conn,newname_last_component,&bad_path2,&sbuf2); @@ -3290,6 +3467,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", */ if (strcsequal(directory, newname)) { + rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname); DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory)); return NT_STATUS_OK; } @@ -3303,6 +3481,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", if(SMB_VFS_RENAME(conn,directory, newname) == 0) { DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n", directory,newname)); + rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname); return NT_STATUS_OK; } @@ -3367,8 +3546,10 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", continue; } - if (!SMB_VFS_RENAME(conn,fname,destname)) + if (!SMB_VFS_RENAME(conn,fname,destname)) { + rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname); count++; + } DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); } CloseDir(dirptr); diff --git a/source3/smbd/sec_ctx.c b/source3/smbd/sec_ctx.c index 411ece5249..8a85792ead 100644 --- a/source3/smbd/sec_ctx.c +++ b/source3/smbd/sec_ctx.c @@ -199,7 +199,7 @@ BOOL initialise_groups(char *user, uid_t uid, gid_t gid) /* Call initgroups() to get user groups */ - if (initgroups(user,gid) == -1) { + if (winbind_initgroups(user,gid) == -1) { DEBUG(0,("Unable to initgroups. Error was %s\n", strerror(errno) )); if (getuid() == 0) { if (gid < 0 || gid > 32767 || uid < 0 || uid > 32767) { diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 453ff54e4b..8b890549ea 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -744,7 +744,7 @@ void build_options(BOOL screen); reopen_logs(); - DEBUG(0,( "smbd version %s started.\n", VERSION)); + DEBUG(0,( "smbd version %s started.\n", SAMBA_VERSION_STRING)); DEBUGADD(0,( "Copyright Andrew Tridgell and the Samba Team 1992-2003\n")); DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n", diff --git a/source3/smbd/service.c b/source3/smbd/service.c index c2855487a5..70126b9e7f 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -273,7 +273,7 @@ static void set_read_only(connection_struct *conn, gid_t *groups, size_t n_group str_list_copy(&list, lp_readlist(conn->service)); if (list) { - if (!str_list_substitute(list, "%S", service)) { + if ( !str_list_sub_basic(list, current_user_info.smb_name) ) { DEBUG(0, ("ERROR: read list substitution failed\n")); } if (user_in_list(conn->user, (const char **)list, groups, n_groups)) @@ -283,7 +283,7 @@ static void set_read_only(connection_struct *conn, gid_t *groups, size_t n_group str_list_copy(&list, lp_writelist(conn->service)); if (list) { - if (!str_list_substitute(list, "%S", service)) { + if ( !str_list_sub_basic(list, current_user_info.smb_name) ) { DEBUG(0, ("ERROR: write list substitution failed\n")); } if (user_in_list(conn->user, (const char **)list, groups, n_groups)) @@ -642,6 +642,10 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, return NULL; } } + +#ifdef WITH_FAKE_KASERVER + afs_login(user); +#endif #if CHECK_PATH_ON_TCONX /* win2000 does not check the permissions on the directory @@ -691,6 +695,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) { dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address ); + dbgtext( "%s", srv_is_signing_active() ? "signed " : ""); dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) ); dbgtext( "initially as user %s ", user ); dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() ); diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 88b442215d..427caa3ba1 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -62,7 +62,7 @@ static int add_signature(char *outbuf, char *p) char *start = p; fstring lanman; - fstr_sprintf( lanman, "Samba %s", VERSION ); + fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING); p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE); p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE); @@ -149,7 +149,6 @@ static int reply_spnego_kerberos(connection_struct *conn, DATA_BLOB auth_data; DATA_BLOB ap_rep, ap_rep_wrapped, response; auth_serversupplied_info *server_info = NULL; - ADS_STRUCT *ads; uint8 session_key[16]; uint8 tok_id[2]; BOOL foreign = False; @@ -165,18 +164,12 @@ static int reply_spnego_kerberos(connection_struct *conn, return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - ads = ads_init_simple(); + ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, session_key); - if (!ads) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } + data_blob_free(&ticket); - ads->auth.realm = strdup(lp_realm()); - - ret = ads_verify_ticket(ads, &ticket, &client, &auth_data, &ap_rep, session_key); if (!NT_STATUS_IS_OK(ret)) { DEBUG(1,("Failed to verify incoming ticket!\n")); - ads_destroy(&ads); return ERROR_NT(NT_STATUS_LOGON_FAILURE); } @@ -187,16 +180,17 @@ static int reply_spnego_kerberos(connection_struct *conn, p = strchr_m(client, '@'); if (!p) { DEBUG(3,("Doesn't look like a valid principal\n")); - ads_destroy(&ads); data_blob_free(&ap_rep); + SAFE_FREE(client); return ERROR_NT(NT_STATUS_LOGON_FAILURE); } *p = 0; - if (strcasecmp(p+1, ads->auth.realm) != 0) { + if (strcasecmp(p+1, lp_realm()) != 0) { DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1)); if (!lp_allow_trusted_domains()) { data_blob_free(&ap_rep); + SAFE_FREE(client); return ERROR_NT(NT_STATUS_LOGON_FAILURE); } foreign = True; @@ -213,7 +207,7 @@ static int reply_spnego_kerberos(connection_struct *conn, user = smb_xstrdup(client); } - ads_destroy(&ads); + SAFE_FREE(client); /* setup the string used by %U */ sub_set_smb_name(user); @@ -223,7 +217,7 @@ static int reply_spnego_kerberos(connection_struct *conn, if (!pw) { DEBUG(1,("Username %s is invalid on this system\n",user)); data_blob_free(&ap_rep); - return ERROR_NT(NT_STATUS_NO_SUCH_USER); + return ERROR_NT(NT_STATUS_LOGON_FAILURE); } if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) { diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c index fbebdb240f..948173687d 100644 --- a/source3/smbd/statcache.c +++ b/source3/smbd/statcache.c @@ -66,11 +66,12 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat return; /* - * Don't cache trivial valid directory entries. + * Don't cache trivial valid directory entries such as . and .. */ - if((*full_orig_name == '\0') || (strcmp(full_orig_name, ".") == 0) || - (strcmp(full_orig_name, "..") == 0)) + if((*full_orig_name == '\0') || (full_orig_name[0] == '.' && + ((full_orig_name[1] == '\0') || + (full_orig_name[1] == '.' && full_orig_name[1] == '\0')))) return; /* @@ -216,10 +217,10 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath, /* * Don't lookup trivial valid directory entries. */ - if((*name == '\0') || (strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) { - DO_PROFILE_INC(statcache_misses); + if((*name == '\0') || (name[0] == '.' && + ((name[1] == '\0') || + (name[1] == '.' && name[1] == '\0')))) return False; - } if (case_sensitive) { chk_name = strdup(name); @@ -247,6 +248,7 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath, while (1) { hash_elem = hash_lookup(&stat_cache, chk_name); if(hash_elem == NULL) { + DEBUG(10,("stat_cache_lookup: lookup failed for name [%s]\n", chk_name )); /* * Didn't find it - remove last component for next try. */ @@ -276,6 +278,7 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath, } } else { scp = (stat_cache_entry *)(hash_elem->value); + DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] -> [%s]\n", chk_name, scp->translated_path )); 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. */ diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 86906fa5be..033e76a33e 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1,7 +1,7 @@ /* Unix SMB/CIFS implementation. SMB transaction2 handling - Copyright (C) Jeremy Allison 1994-2001 + Copyright (C) Jeremy Allison 1994-2003 Copyright (C) Stefan (metze) Metzmacher 2003 Extensively modified by Andrew Tridgell, 1995 @@ -261,8 +261,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i unix_convert(fname,conn,0,&bad_path,&sbuf); if (!check_name(fname,conn)) { - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } unixmode = unix_mode(conn,open_attr | aARCH, fname); @@ -271,8 +270,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i oplock_request, &rmode,&smb_action); if (!fsp) { - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } size = get_file_size(sbuf); @@ -441,9 +439,9 @@ static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *ps } /**************************************************************************** -checks for SMB_TIME_NO_CHANGE and if not found -calls interpret_long_date + Checks for SMB_TIME_NO_CHANGE and if not found calls interpret_long_date. ****************************************************************************/ + time_t interpret_long_unix_date(char *p) { DEBUG(1,("interpret_long_unix_date\n")); @@ -763,6 +761,70 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, p = pdata + len; break; + case SMB_FIND_FILE_LEVEL_261: + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date(p,cdate); p += 8; + put_long_date(p,adate); p += 8; + put_long_date(p,mdate); p += 8; + put_long_date(p,mdate); p += 8; + SOFF_T(p,0,file_size); + SOFF_T(p,8,allocation_size); + p += 16; + SIVAL(p,0,nt_extmode); + p += 4; + len = srvstr_push(outbuf, p + 20, fname, -1, STR_TERMINATE_ASCII); + SIVAL(p, 0, len); + memset(p+4,'\0',16); /* EA size. Unknown 0 1 2 */ + p += 20 + len; /* Strlen, EA size. Unknown 0 1 2, string itself */ + len = PTR_DIFF(p, pdata); + len = (len + 3) & ~3; + SIVAL(pdata,0,len); + p = pdata + len; + break; + + case SMB_FIND_FILE_LEVEL_262: + was_8_3 = mangle_is_8_3(fname, True); + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date(p,cdate); p += 8; + put_long_date(p,adate); p += 8; + put_long_date(p,mdate); p += 8; + put_long_date(p,mdate); p += 8; + SOFF_T(p,0,file_size); + SOFF_T(p,8,allocation_size); + p += 16; + SIVAL(p,0,nt_extmode); p += 4; + q = p; p += 4; + SIVAL(p,0,0); p += 4; + /* Clear the short name buffer. This is + * IMPORTANT as not doing so will trigger + * a Win2k client bug. JRA. + */ + memset(p,'\0',26); + if (!was_8_3) { + pstring mangled_name; + pstrcpy(mangled_name, fname); + mangle_map(mangled_name,True,True,SNUM(conn)); + mangled_name[12] = 0; + 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; + memset(p, '\0', 10); /* 2 4 byte unknowns plus a zero reserved. */ + p += 10; + len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII); + SIVAL(q,0,len); + p += len; + len = PTR_DIFF(p, pdata); + len = (len + 3) & ~3; + SIVAL(pdata,0,len); + p = pdata + len; + break; + /* CIFS UNIX Extension. */ case SMB_FIND_FILE_UNIX: @@ -895,6 +957,8 @@ close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n", case SMB_FIND_FILE_FULL_DIRECTORY_INFO: case SMB_FIND_FILE_NAMES_INFO: case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + case SMB_FIND_FILE_LEVEL_261: + case SMB_FIND_FILE_LEVEL_262: break; case SMB_FIND_FILE_UNIX: if (!lp_unix_extensions()) @@ -910,8 +974,7 @@ close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n", unix_convert(directory,conn,0,&bad_path,&sbuf); if(!check_name(directory,conn)) { - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } p = strrchr_m(directory,'/'); @@ -1365,7 +1428,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, 0); + len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, STR_NOALIGN); SCVAL(pdata,l2_vol_cch,len); data_len = l2_vol_szVolLabel + len; DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", @@ -1716,14 +1779,22 @@ static int call_trans2setfsinfo(connection_struct *conn, * Utility function to set bad path error. ****************************************************************************/ -NTSTATUS set_bad_path_error(int err, BOOL bad_path) +int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint32 def_code) { - if((err == ENOENT) && bad_path) { + DEBUG(10,("set_bad_path_error: err = %d bad_path = %d\n", + err, (int)bad_path )); + + if(err == ENOENT) { unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - return NT_STATUS_OBJECT_PATH_NOT_FOUND; + if (bad_path) { + unix_ERR_code = ERRbadpath; + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } else { + unix_ERR_code = ERRbadfile; + return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND); + } } - return NT_STATUS_OK; + return UNIXERROR(def_class,def_code); } /**************************************************************************** @@ -1778,8 +1849,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, 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)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } } else if(fsp && (fsp->is_directory || fsp->fd == -1)) { @@ -1792,21 +1862,18 @@ static int call_trans2qfilepathinfo(connection_struct *conn, unix_convert(fname,conn,0,&bad_path,&sbuf); if (!check_name(fname,conn)) { DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } } 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)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } delete_pending = fsp->directory_delete_on_close; @@ -1821,9 +1888,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadfid)); } - if((pos = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_CUR)) == -1) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - + pos = fsp->position_information; delete_pending = fsp->delete_on_close; } } else { @@ -1842,29 +1907,26 @@ static int call_trans2qfilepathinfo(connection_struct *conn, unix_convert(fname,conn,0,&bad_path,&sbuf); if (!check_name(fname,conn)) { DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } } 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)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } } if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) return ERROR_DOS(ERRDOS,ERRunknownlevel); - DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n", - fname,info_level,tran_call,total_data)); + DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n", + fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data)); p = strrchr_m(fname,'/'); if (!p) @@ -1873,6 +1935,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, base_name = p+1; mode = dos_mode(conn,fname,&sbuf); + if (!mode) + mode = FILE_ATTRIBUTE_NORMAL; + fullpathname = fname; file_size = get_file_size(sbuf); allocation_size = get_allocation_size(fsp,&sbuf); @@ -1985,7 +2050,10 @@ static int call_trans2qfilepathinfo(connection_struct *conn, data_size = 24; SOFF_T(pdata,0,allocation_size); SOFF_T(pdata,8,file_size); - SIVAL(pdata,16,sbuf.st_nlink); + if (delete_pending & sbuf.st_nlink) + SIVAL(pdata,16,sbuf.st_nlink - 1); + else + SIVAL(pdata,16,sbuf.st_nlink); SCVAL(pdata,20,0); SCVAL(pdata,21,(mode&aDIR)?1:0); break; @@ -2043,7 +2111,10 @@ static int call_trans2qfilepathinfo(connection_struct *conn, pdata += 40; SOFF_T(pdata,0,allocation_size); SOFF_T(pdata,8,file_size); - SIVAL(pdata,16,sbuf.st_nlink); + if (delete_pending && sbuf.st_nlink) + SIVAL(pdata,16,sbuf.st_nlink - 1); + else + SIVAL(pdata,16,sbuf.st_nlink); SCVAL(pdata,20,delete_pending); SCVAL(pdata,21,(mode&aDIR)?1:0); pdata += 24; @@ -2415,8 +2486,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, unix_convert(fname,conn,0,&bad_path,&sbuf); if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) { DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } } else if (fsp && fsp->print_file) { /* @@ -2455,8 +2525,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, srvstr_pull(inbuf, fname, ¶ms[6], sizeof(fname), -1, STR_TERMINATE); unix_convert(fname,conn,0,&bad_path,&sbuf); if(!check_name(fname, conn)) { - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } /* @@ -2465,8 +2534,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, if(!VALID_STAT(sbuf) && !INFO_LEVEL_IS_UNIX(info_level)) { DEBUG(3,("call_trans2setfilepathinfo: stat of %s failed (%s)\n", fname, strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRbadpath)); + return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND); } } @@ -2479,8 +2547,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn, if (VALID_STAT(sbuf)) unixmode = sbuf.st_mode; - DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n", - tran_call,fname,info_level,total_data)); + DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n", + tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data)); /* Realloc the parameter and data sizes */ params = Realloc(*pparams,2); @@ -2507,18 +2575,13 @@ static int call_trans2setfilepathinfo(connection_struct *conn, switch (info_level) { case SMB_INFO_STANDARD: { - if (total_data < l1_cbFile+4) + if (total_data < 12) return(ERROR_DOS(ERRDOS,ERRinvalidparam)); /* access time */ tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess); - /* write time */ tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite); - - dosmode = SVAL(pdata,l1_attrFile); - size = IVAL(pdata,l1_cbFile); - break; } @@ -2677,14 +2740,17 @@ static int call_trans2setfilepathinfo(connection_struct *conn, case SMB_FILE_DISPOSITION_INFORMATION: case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */ { - BOOL delete_on_close = (CVAL(pdata,0) ? True : False); + BOOL delete_on_close; NTSTATUS status; if (total_data < 1) return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + delete_on_close = (CVAL(pdata,0) ? True : False); + + /* Just ignore this set on a path. */ if (tran_call != TRANSACT2_SETFILEINFO) - return ERROR_DOS(ERRDOS,ERRunknownlevel); + break; if (fsp == NULL) return(UNIXERROR(ERRDOS,ERRbadfid)); @@ -2702,6 +2768,27 @@ static int call_trans2setfilepathinfo(connection_struct *conn, break; } + case SMB_FILE_POSITION_INFORMATION: + { + SMB_BIG_UINT position_information; + + if (total_data < 8) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + position_information = (SMB_BIG_UINT)IVAL(pdata,0); +#ifdef LARGE_SMB_OFF_T + position_information |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32); +#else /* LARGE_SMB_OFF_T */ + if (IVAL(pdata,4) != 0) /* more than 32 bits? */ + return ERROR_DOS(ERRDOS,ERRunknownlevel); +#endif /* LARGE_SMB_OFF_T */ + DEBUG(10,("call_trans2setfilepathinfo: Set file position information for file %s to %.0f\n", + fname, (double)position_information )); + if (fsp) + fsp->position_information = position_information; + break; + } + /* * CIFS UNIX extensions. */ @@ -2881,6 +2968,55 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", return(-1); } + case SMB_FILE_RENAME_INFORMATION: + { + BOOL overwrite; + uint32 root_fid; + uint32 len; + pstring newname; + pstring base_name; + char *p; + NTSTATUS status; + + if (total_data < 12) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + overwrite = (CVAL(pdata,0) ? True : False); + root_fid = IVAL(pdata,4); + len = IVAL(pdata,8); + srvstr_pull(inbuf, newname, &pdata[12], sizeof(newname), len, 0); + + /* Check the new name has no '\' characters. */ + if (strchr_m(newname, '\\') || strchr_m(newname, '/')) + return ERROR_NT(NT_STATUS_NOT_SUPPORTED); + + RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); + + /* Create the base directory. */ + pstrcpy(base_name, fname); + p = strrchr_m(base_name, '/'); + if (p) + *p = '\0'; + /* Append the new name. */ + pstrcat(base_name, "/"); + pstrcat(base_name, newname); + + if (fsp) { + DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", + fsp->fnum, fsp->fsp_name, base_name )); + status = rename_internals_fsp(conn, fsp, base_name, overwrite); + } else { + DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION %s -> %s\n", + fname, newname )); + status = rename_internals(conn, fname, base_name, overwrite); + } + if (!NT_STATUS_IS_OK(status)) + return ERROR_NT(status); + process_pending_change_notify_queue((time_t)0); + SSVAL(params,0,0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + return(-1); + } default: return ERROR_DOS(ERRDOS,ERRunknownlevel); } @@ -2896,10 +3032,12 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", DEBUG(6,("modtime: %s ", ctime(&tvs.modtime))); DEBUG(6,("size: %.0f ", (double)size)); - if (S_ISDIR(sbuf.st_mode)) - dosmode |= aDIR; - else - dosmode &= ~aDIR; + if (dosmode) { + if (S_ISDIR(sbuf.st_mode)) + dosmode |= aDIR; + else + dosmode &= ~aDIR; + } DEBUG(6,("dosmode: %x\n" , dosmode)); @@ -3030,8 +3168,7 @@ static int call_trans2mkdir(connection_struct *conn, if(ret < 0) { DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } /* Realloc the parameter and data sizes */ diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 8d3e7cd9be..7979ffe854 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -370,7 +370,7 @@ BOOL unbecome_user(void) } /***************************************************************** - Convert the suplimentary SIDs returned in a netlogon into UNIX + Convert the supplementary SIDs returned in a netlogon into UNIX group gid_t's. Add to the total group array. *****************************************************************/ @@ -437,467 +437,4 @@ void add_supplementary_nt_login_groups(int *n_groups, gid_t **pp_groups, NT_USER *pptok = new_tok; } -/***************************************************************** - *THE CANONICAL* convert name to SID function. - Tries local lookup first - for local domains - then uses winbind. -*****************************************************************/ - -BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type) -{ - fstring sid; - BOOL local_lookup = False; - - *name_type = SID_NAME_UNKNOWN; - - /* If we are looking up a domain user, make sure it is - for the local machine only */ - - if (strequal(global_myname(), domain)) { - local_lookup = True; - } else if (lp_server_role() == ROLE_DOMAIN_PDC || - lp_server_role() == ROLE_DOMAIN_BDC) { - if (strequal(domain, lp_workgroup())) { - local_lookup = True; - } - } - - if (local_lookup) { - if (local_lookup_name(name, psid, name_type)) { - DEBUG(10, - ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n", - domain, name, sid_to_string(sid,psid), - sid_type_lookup(*name_type), (unsigned int)*name_type)); - return True; - } - } else { - /* Remote */ - if (winbind_lookup_name(domain, name, psid, name_type)) { - - DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n", - domain, name, sid_to_string(sid, psid), - (unsigned int)*name_type)); - return True; - } - } - - DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n", - local_lookup ? "local" : "winbind", domain, name)); - - return False; -} - -/***************************************************************** - *THE CANONICAL* convert SID to name function. - Tries local lookup first - for local sids, then tries winbind. -*****************************************************************/ - -BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type) -{ - if (!name_type) - return False; - - *name_type = SID_NAME_UNKNOWN; - - /* Check if this is our own sid. This should perhaps be done by - winbind? For the moment handle it here. */ - - if (sid->num_auths == 5) { - DOM_SID tmp_sid; - uint32 rid; - - sid_copy(&tmp_sid, sid); - sid_split_rid(&tmp_sid, &rid); - - if (sid_equal(get_global_sam_sid(), &tmp_sid)) { - - return map_domain_sid_to_name(&tmp_sid, dom_name) && - local_lookup_sid(sid, name, name_type); - } - } - - if (!winbind_lookup_sid(sid, dom_name, name, name_type)) { - fstring sid_str; - DOM_SID tmp_sid; - uint32 rid; - - DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) )); - - sid_copy(&tmp_sid, sid); - sid_split_rid(&tmp_sid, &rid); - return map_domain_sid_to_name(&tmp_sid, dom_name) && - lookup_known_rid(&tmp_sid, rid, name, name_type); - } - 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 6ff2f586ba..a521d0113d 100644 --- a/source3/smbd/utmp.c +++ b/source3/smbd/utmp.c @@ -217,13 +217,13 @@ static void uw_pathname(pstring fname, const char *uw_name, const char *uw_defau /* For w-files, first look for explicit "wtmp dir" */ if (uw_name[0] == 'w') { pstrcpy(dirname,lp_wtmpdir()); - trim_string(dirname,"","/"); + trim_char(dirname,'\0','/'); } /* For u-files and non-explicit w-dir, look for "utmp dir" */ if (dirname == 0 || strlen(dirname) == 0) { pstrcpy(dirname,lp_utmpdir()); - trim_string(dirname,"","/"); + trim_char(dirname,'\0','/'); } /* If explicit directory above, use it */ @@ -283,8 +283,12 @@ static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim) * man page appears not to specify (hints non-NULL) * A correspondent suggest at least ut_name should be NULL */ +#if defined(HAVE_UT_UT_NAME) memset((char *)&u->ut_name, '\0', sizeof(u->ut_name)); +#endif +#if defined(HAVE_UT_UT_HOST) memset((char *)&u->ut_host, '\0', sizeof(u->ut_host)); +#endif } /* Stolen from logwtmp function in libutil. * May be more locking/blocking is needed? @@ -406,7 +410,9 @@ static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim) else ux.ut_syslen = 0; #endif +#if defined(HAVE_UT_UT_HOST) utmp_strcpy(ux.ut_host, hostname, sizeof(ux.ut_host)); +#endif uw_pathname(uname, "utmpx", ux_pathname); uw_pathname(wname, "wtmpx", wx_pathname); diff --git a/source3/smbd/vfs-wrap.c b/source3/smbd/vfs-wrap.c index 8d44a1a0fa..a76a7a6abd 100644 --- a/source3/smbd/vfs-wrap.c +++ b/source3/smbd/vfs-wrap.c @@ -49,6 +49,42 @@ SMB_BIG_UINT vfswrap_disk_free(vfs_handle_struct *handle, connection_struct *con result = sys_disk_free(path, small_query, bsize, dfree, dsize); return result; } + +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 +} + +int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, BOOL labels) +{ + errno = ENOSYS; + return -1; /* Not implemented. */ +} /* Directory operations */ @@ -756,36 +792,6 @@ int vfswrap_sys_acl_free_qualifier(vfs_handle_struct *handle, connection_struct 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. *****************************************************************/ diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 5f3abe7efe..753db4cece 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -56,6 +56,7 @@ static struct vfs_ops default_vfs = { vfswrap_disk_free, vfswrap_get_quota, vfswrap_set_quota, + vfswrap_get_shadow_copy_data, /* Directory operations */ @@ -140,7 +141,6 @@ static struct vfs_ops default_vfs = { vfswrap_setxattr, vfswrap_lsetxattr, vfswrap_fsetxattr - } }; @@ -233,10 +233,10 @@ BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object) if (p) { *p = 0; module_param = p+1; - trim_string(module_param, " ", " "); + trim_char(module_param, ' ', ' '); } - trim_string(module_name, " ", " "); + trim_char(module_name, ' ', ' '); /* First, try to load the module with the new module system */ if((entry = vfs_find_backend_entry(module_name)) || |