diff options
Diffstat (limited to 'source3/smbd')
37 files changed, 4406 insertions, 3460 deletions
diff --git a/source3/smbd/build_options.c b/source3/smbd/build_options.c index 1d18f534b13..f52c53dda53 100644 --- a/source3/smbd/build_options.c +++ b/source3/smbd/build_options.c @@ -89,6 +89,12 @@ void build_options(BOOL screen) #ifdef HAVE_KRB5 output(screen," HAVE_KRB5"); #endif +#ifdef HAVE_GSSAPI + output(screen," HAVE_GSSAPI"); +#endif +#ifdef HAVE_LDAP + output(screen," HAVE_LDAP"); +#endif #ifdef WITH_AUTOMOUNT output(screen," WITH_AUTOMOUNT\n"); #endif @@ -101,9 +107,6 @@ void build_options(BOOL screen) #ifdef WITH_TDB_SAM output(screen," WITH_TDB_SAM\n"); #endif -#ifdef WITH_LDAP_SAM - output(screen," WITH_LDAP_SAM\n"); -#endif #ifdef WITH_SMBPASSWD_SAM output(screen," WITH_SMBPASSWD_SAM\n"); #endif @@ -113,12 +116,6 @@ void build_options(BOOL screen) #ifdef WITH_NISPLUS_HOME output(screen," WITH_NISPLUS_HOME\n"); #endif -#ifdef WITH_SSL - output(screen," WITH_SSL\n"); -#endif -#ifdef SSL_DIR - output(screen," SSL_DIR: %s\n",SSL_DIR); -#endif #ifdef WITH_SYSLOG output(screen," WITH_SYSLOG\n"); #endif @@ -220,8 +217,17 @@ void build_options(BOOL screen) #ifdef HAVE_CUPS_LANGUAGE_H output(screen," HAVE_CUPS_LANGUAGE_H\n"); #endif -#ifdef HAVE_LIBDL - output(screen," HAVE_LIBDL\n"); +#ifdef HAVE_DLOPEN + output(screen," HAVE_DLOPEN\n"); +#endif +#ifdef HAVE_DLCLOSE + output(screen," HAVE_DLCLOSE\n"); +#endif +#ifdef HAVE_DLSYM + output(screen," HAVE_DLSYM\n"); +#endif +#ifdef HAVE_DLERROR + output(screen," HAVE_DLERROR\n"); #endif #ifdef HAVE_UNIXSOCKET output(screen," HAVE_UNIXSOCKET\n"); diff --git a/source3/smbd/change_trust_pw.c b/source3/smbd/change_trust_pw.c index 0d80d5718fa..0c468699b4c 100644 --- a/source3/smbd/change_trust_pw.c +++ b/source3/smbd/change_trust_pw.c @@ -35,7 +35,6 @@ static NTSTATUS modify_trust_password( char *domain, char *remote_machine, { struct cli_state *cli; DOM_SID domain_sid; - struct in_addr dest_ip; NTSTATUS nt_status; /* @@ -43,17 +42,12 @@ static NTSTATUS modify_trust_password( char *domain, char *remote_machine, */ if (!secrets_fetch_domain_sid(domain, &domain_sid)) { - DEBUG(0, ("domain_client_validate: unable to fetch domain sid.\n")); + DEBUG(0, ("modify_trust_password: unable to fetch domain sid.\n")); return NT_STATUS_UNSUCCESSFUL; } - if(!resolve_name( remote_machine, &dest_ip, 0x20)) { - DEBUG(0,("modify_trust_password: Can't resolve address for %s\n", remote_machine)); - return NT_STATUS_UNSUCCESSFUL; - } - if (!NT_STATUS_IS_OK(cli_full_connection(&cli, global_myname, remote_machine, - &dest_ip, 0, + NULL, 0, "IPC$", "IPC", "", "", "", 0))) { diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index eed535cf117..68871deb90c 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -472,6 +472,10 @@ BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL struct passwd *pass; + if (!name) { + DEBUG(1, ("NULL username specfied to chgpasswd()!\n")); + } + DEBUG(3, ("Password change for user: %s\n", name)); #if DEBUG_PASSWORD diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c index f552d4a2243..c0aa4470160 100644 --- a/source3/smbd/conn.c +++ b/source3/smbd/conn.c @@ -166,7 +166,7 @@ void conn_free(connection_struct *conn) if (conn->dl_handle != NULL) { /* Close dlopen() handle */ - dlclose(conn->dl_handle); + sys_dlclose(conn->dl_handle); } DLIST_REMOVE(Connections, conn); diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index f56e0e9ef00..7dd425ef8a5 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -558,6 +558,12 @@ BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int di return True; } +static BOOL mangle_mask_match(connection_struct *conn, char *filename, char *mask) +{ + mangle_map(filename,True,False,SNUM(conn)); + return mask_match(filename,mask,False); +} + /**************************************************************************** Get an 8.3 directory entry. ****************************************************************************/ @@ -603,8 +609,7 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname, */ if ((strcmp(mask,"*.*") == 0) || mask_match(filename,mask,False) || - (mangle_map(filename,True,False,SNUM(conn)) && - mask_match(filename,mask,False))) + mangle_mask_match(conn,filename,mask)) { if (isrootdir && (strequal(filename,"..") || strequal(filename,"."))) continue; @@ -680,7 +685,15 @@ static BOOL user_can_read_file(connection_struct *conn, char *name) ZERO_STRUCT(ste); - /* if we can't stat it does not show it */ + /* + * If user is a member of the Admin group + * we never hide files from them. + */ + + if (conn->admin_user) + return True; + + /* If we can't stat it does not show it */ if (vfs_stat(conn, name, &ste) != 0) return False; @@ -714,73 +727,80 @@ static BOOL user_can_read_file(connection_struct *conn, char *name) void *OpenDir(connection_struct *conn, char *name, BOOL use_veto) { - Dir *dirp; - char *n; - DIR *p = conn->vfs_ops.opendir(conn,name); - int used=0; - - if (!p) return(NULL); - dirp = (Dir *)malloc(sizeof(Dir)); - if (!dirp) { - DEBUG(0,("Out of memory in OpenDir\n")); - conn->vfs_ops.closedir(conn,p); - return(NULL); - } - dirp->pos = dirp->numentries = dirp->mallocsize = 0; - dirp->data = dirp->current = NULL; - - while (True) - { - int l; - - if (used == 0) { - n = "."; - } else if (used == 2) { - n = ".."; - } else { - n = vfs_readdirname(conn, p); - if (n == NULL) - break; - if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0)) - continue; - } - - l = strlen(n)+1; - - /* If it's a vetoed file, pretend it doesn't even exist */ - if (use_veto && conn && IS_VETO_PATH(conn, n)) continue; - - /* Honour _hide unreadable_ option */ - if (conn && lp_hideunreadable(SNUM(conn))) { - char *entry; - int ret=0; + Dir *dirp; + char *n; + DIR *p = conn->vfs_ops.opendir(conn,name); + int used=0; + + if (!p) + return(NULL); + dirp = (Dir *)malloc(sizeof(Dir)); + if (!dirp) { + DEBUG(0,("Out of memory in OpenDir\n")); + conn->vfs_ops.closedir(conn,p); + return(NULL); + } + dirp->pos = dirp->numentries = dirp->mallocsize = 0; + dirp->data = dirp->current = NULL; + + while (True) { + int l; + BOOL normal_entry = True; + + if (used == 0) { + n = "."; + normal_entry = False; + } else if (used == 2) { + n = ".."; + normal_entry = False; + } else { + n = vfs_readdirname(conn, p); + if (n == NULL) + break; + if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0)) + continue; + normal_entry = True; + } + + l = strlen(n)+1; + + /* If it's a vetoed file, pretend it doesn't even exist */ + if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n)) + continue; + + /* Honour _hide unreadable_ option */ + if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) { + char *entry; + int ret=0; - if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { - ret = user_can_read_file(conn, entry); - SAFE_FREE(entry); - } - if (!ret) continue; - } - - if (used + l > dirp->mallocsize) { - int s = MAX(used+l,used+2000); - char *r; - r = (char *)Realloc(dirp->data,s); - if (!r) { - DEBUG(0,("Out of memory in OpenDir\n")); - break; - } - dirp->data = r; - dirp->mallocsize = s; - dirp->current = dirp->data; - } - pstrcpy(dirp->data+used,n); - used += l; - dirp->numentries++; - } + if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { + ret = user_can_read_file(conn, entry); + SAFE_FREE(entry); + } + if (!ret) + continue; + } + + if (used + l > dirp->mallocsize) { + int s = MAX(used+l,used+2000); + char *r; + r = (char *)Realloc(dirp->data,s); + if (!r) { + DEBUG(0,("Out of memory in OpenDir\n")); + break; + } + dirp->data = r; + dirp->mallocsize = s; + dirp->current = dirp->data; + } + + pstrcpy(dirp->data+used,n); + used += l; + dirp->numentries++; + } - conn->vfs_ops.closedir(conn,p); - return((void *)dirp); + conn->vfs_ops.closedir(conn,p); + return((void *)dirp); } diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index addbcb0b3ca..710ba396d8d 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -1,7 +1,9 @@ /* - Unix SMB/CIFS implementation. + Unix SMB/Netbios implementation. + Version 1.9. read/write to a files_struct Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jeremy Allison 2000-2002. - write cache. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,31 +25,32 @@ static BOOL setup_write_cache(files_struct *, SMB_OFF_T); /**************************************************************************** -seek a file. Try to avoid the seek if possible + Seek a file. Try to avoid the seek if possible. ****************************************************************************/ -SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos) +static SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos) { - SMB_OFF_T offset = 0; - SMB_OFF_T seek_ret; + SMB_OFF_T offset = 0; + SMB_OFF_T seek_ret; - if (fsp->print_file && lp_postscript(fsp->conn->service)) - offset = 3; + if (fsp->print_file && lp_postscript(fsp->conn->service)) + offset = 3; - seek_ret = fsp->conn->vfs_ops.lseek(fsp,fsp->fd,pos+offset,SEEK_SET); + seek_ret = fsp->conn->vfs_ops.lseek(fsp,fsp->fd,pos+offset,SEEK_SET); - if(seek_ret == -1) { - DEBUG(0,("seek_file: sys_lseek failed. Error was %s\n", strerror(errno) )); - fsp->pos = -1; - return -1; - } + if(seek_ret == -1) { + DEBUG(0,("seek_file: (%s) sys_lseek failed. Error was %s\n", + fsp->fsp_name, strerror(errno) )); + fsp->pos = -1; + return -1; + } - fsp->pos = seek_ret - offset; + fsp->pos = seek_ret - offset; - DEBUG(10,("seek_file: requested pos = %.0f, new pos = %.0f\n", - (double)(pos+offset), (double)fsp->pos )); + DEBUG(10,("seek_file (%s): requested pos = %.0f, new pos = %.0f\n", + fsp->fsp_name, (double)(pos+offset), (double)fsp->pos )); - return(fsp->pos); + return(fsp->pos); } /**************************************************************************** @@ -55,25 +58,25 @@ SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos) ****************************************************************************/ -BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) +static BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) { - write_cache *wcp = fsp->wcp; + write_cache *wcp = fsp->wcp; - if(!wcp) - return False; + if(!wcp) + return False; - if(n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) - return False; + if(n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) + return False; - memcpy(data, wcp->data + (pos - wcp->offset), n); + memcpy(data, wcp->data + (pos - wcp->offset), n); - DO_PROFILE_INC(writecache_read_hits); + DO_PROFILE_INC(writecache_read_hits); - return True; + return True; } /**************************************************************************** -read from a file + Read from a file. ****************************************************************************/ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) @@ -121,6 +124,9 @@ tryagain: ret += readret; } + DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n", + fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); + return(ret); } @@ -133,10 +139,17 @@ static unsigned int allocated_write_caches; static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_t n) { - if ((pos != -1) && (seek_file(fsp,pos) == -1)) - return -1; + ssize_t ret; + + if ((pos != -1) && (seek_file(fsp,pos) == -1)) + return -1; + + ret = vfs_write_data(fsp,data,n); + + DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n", + fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); - return vfs_write_data(fsp,data,n); + return ret; } /**************************************************************************** @@ -145,367 +158,365 @@ write to a file ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n) { - write_cache *wcp = fsp->wcp; - ssize_t total_written = 0; - int write_path = -1; - - if (fsp->print_file) { - return print_job_write(fsp->print_jobid, data, n); - } - - if (!fsp->can_write) { - errno = EPERM; - return(0); - } - - if (!fsp->modified) { - SMB_STRUCT_STAT st; - fsp->modified = True; - - if (fsp->conn->vfs_ops.fstat(fsp,fsp->fd,&st) == 0) { - int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); - fsp->size = st.st_size; - if (MAP_ARCHIVE(fsp->conn) && !IS_DOS_ARCHIVE(dosmode)) { - file_chmod(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st); - } - - /* - * If this is the first write and we have an exclusive oplock then setup - * the write cache. - */ - - if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) { - setup_write_cache(fsp, st.st_size); - wcp = fsp->wcp; - } - } - } + write_cache *wcp = fsp->wcp; + ssize_t total_written = 0; + int write_path = -1; + + if (fsp->print_file) + return print_job_write(fsp->print_jobid, data, n); + + if (!fsp->can_write) { + errno = EPERM; + return(0); + } + + if (!fsp->modified) { + SMB_STRUCT_STAT st; + fsp->modified = True; + + if (fsp->conn->vfs_ops.fstat(fsp,fsp->fd,&st) == 0) { + int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); + fsp->size = st.st_size; + if (MAP_ARCHIVE(fsp->conn) && !IS_DOS_ARCHIVE(dosmode)) + file_chmod(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st); + + /* + * If this is the first write and we have an exclusive oplock then setup + * the write cache. + */ + + if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) { + setup_write_cache(fsp, st.st_size); + wcp = fsp->wcp; + } + } + } #ifdef WITH_PROFILE - DO_PROFILE_INC(writecache_total_writes); - if (!fsp->oplock_type) { - DO_PROFILE_INC(writecache_non_oplock_writes); - } + DO_PROFILE_INC(writecache_total_writes); + if (!fsp->oplock_type) { + DO_PROFILE_INC(writecache_non_oplock_writes); + } #endif - /* - * If this file is level II oplocked then we need - * to grab the shared memory lock and inform all - * other files with a level II lock that they need - * to flush their read caches. We keep the lock over - * the shared memory area whilst doing this. - */ + /* + * If this file is level II oplocked then we need + * to grab the shared memory lock and inform all + * other files with a level II lock that they need + * to flush their read caches. We keep the lock over + * the shared memory area whilst doing this. + */ - release_level_2_oplocks_on_change(fsp); + release_level_2_oplocks_on_change(fsp); #ifdef WITH_PROFILE - if (profile_p && profile_p->writecache_total_writes % 500 == 0) { - DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \ + if (profile_p && profile_p->writecache_total_writes % 500 == 0) { + DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", - profile_p->writecache_init_writes, - profile_p->writecache_abutted_writes, - profile_p->writecache_total_writes, - profile_p->writecache_non_oplock_writes, - profile_p->writecache_allocated_write_caches, - profile_p->writecache_num_write_caches, - profile_p->writecache_direct_writes, - profile_p->writecache_num_perfect_writes, - profile_p->writecache_read_hits )); - - DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n", - profile_p->writecache_flushed_writes[SEEK_FLUSH], - profile_p->writecache_flushed_writes[READ_FLUSH], - profile_p->writecache_flushed_writes[WRITE_FLUSH], - profile_p->writecache_flushed_writes[READRAW_FLUSH], - profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH], - profile_p->writecache_flushed_writes[CLOSE_FLUSH], - profile_p->writecache_flushed_writes[SYNC_FLUSH] )); - } + profile_p->writecache_init_writes, + profile_p->writecache_abutted_writes, + profile_p->writecache_total_writes, + profile_p->writecache_non_oplock_writes, + profile_p->writecache_allocated_write_caches, + profile_p->writecache_num_write_caches, + profile_p->writecache_direct_writes, + profile_p->writecache_num_perfect_writes, + profile_p->writecache_read_hits )); + + DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n", + profile_p->writecache_flushed_writes[SEEK_FLUSH], + profile_p->writecache_flushed_writes[READ_FLUSH], + profile_p->writecache_flushed_writes[WRITE_FLUSH], + profile_p->writecache_flushed_writes[READRAW_FLUSH], + profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH], + profile_p->writecache_flushed_writes[CLOSE_FLUSH], + profile_p->writecache_flushed_writes[SYNC_FLUSH] )); + } #endif - if(!wcp) { - DO_PROFILE_INC(writecache_direct_writes); - total_written = real_write_file(fsp, data, pos, n); - if ((total_written != -1) && (pos + total_written > fsp->size)) - fsp->size = pos + total_written; - return total_written; - } + if(!wcp) { + DO_PROFILE_INC(writecache_direct_writes); + total_written = real_write_file(fsp, data, pos, n); + if ((total_written != -1) && (pos + total_written > fsp->size)) + fsp->size = pos + total_written; + return total_written; + } - DEBUG(9,("write_file(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n", - fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); + DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n", + fsp->fsp_name, fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); - /* - * If we have active cache and it isn't contiguous then we flush. - * NOTE: There is a small problem with running out of disk .... - */ + /* + * If we have active cache and it isn't contiguous then we flush. + * NOTE: There is a small problem with running out of disk .... + */ - if (wcp->data_size) { + if (wcp->data_size) { - BOOL cache_flush_needed = False; + BOOL cache_flush_needed = False; - if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) { + if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) { - /* - * Start of write overlaps or abutts the existing data. - */ + /* + * Start of write overlaps or abutts the existing data. + */ - size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n); + size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n); - memcpy(wcp->data + (pos - wcp->offset), data, data_used); + memcpy(wcp->data + (pos - wcp->offset), data, data_used); - /* - * Update the current buffer size with the new data. - */ + /* + * Update the current buffer size with the new data. + */ - if(pos + data_used > wcp->offset + wcp->data_size) - wcp->data_size = pos + data_used - wcp->offset; + if(pos + data_used > wcp->offset + wcp->data_size) + wcp->data_size = pos + data_used - wcp->offset; - /* - * Update the file size if changed. - */ + /* + * Update the file size if changed. + */ - if (wcp->offset + wcp->data_size > wcp->file_size) - fsp->size = wcp->file_size = wcp->offset + wcp->data_size; + if (wcp->offset + wcp->data_size > wcp->file_size) + fsp->size = wcp->file_size = wcp->offset + wcp->data_size; - /* - * If we used all the data then - * return here. - */ + /* + * If we used all the data then + * return here. + */ - if(n == data_used) - return n; - else - cache_flush_needed = True; + if(n == data_used) + return n; + else + cache_flush_needed = True; - /* - * Move the start of data forward by the amount used, - * cut down the amount left by the same amount. - */ + /* + * Move the start of data forward by the amount used, + * cut down the amount left by the same amount. + */ - data += data_used; - pos += data_used; - n -= data_used; + data += data_used; + pos += data_used; + n -= data_used; - DO_PROFILE_INC(writecache_abutted_writes); - total_written = data_used; + DO_PROFILE_INC(writecache_abutted_writes); + total_written = data_used; - write_path = 1; + write_path = 1; - } else if ((pos < wcp->offset) && (pos + n > wcp->offset) && - (pos + n <= wcp->offset + wcp->alloc_size)) { + } else if ((pos < wcp->offset) && (pos + n > wcp->offset) && + (pos + n <= wcp->offset + wcp->alloc_size)) { - /* - * End of write overlaps the existing data. - */ + /* + * End of write overlaps the existing data. + */ - size_t data_used = pos + n - wcp->offset; + size_t data_used = pos + n - wcp->offset; - memcpy(wcp->data, data + n - data_used, data_used); + memcpy(wcp->data, data + n - data_used, data_used); - /* - * Update the current buffer size with the new data. - */ + /* + * Update the current buffer size with the new data. + */ - if(pos + n > wcp->offset + wcp->data_size) - wcp->data_size = pos + n - wcp->offset; + if(pos + n > wcp->offset + wcp->data_size) + wcp->data_size = pos + n - wcp->offset; - /* - * Update the file size if changed. - */ + /* + * Update the file size if changed. + */ - if (wcp->offset + wcp->data_size > wcp->file_size) - fsp->size = wcp->file_size = wcp->offset + wcp->data_size; + if (wcp->offset + wcp->data_size > wcp->file_size) + fsp->size = wcp->file_size = wcp->offset + wcp->data_size; - /* - * We don't need to move the start of data, but we - * cut down the amount left by the amount used. - */ + /* + * We don't need to move the start of data, but we + * cut down the amount left by the amount used. + */ - n -= data_used; + n -= data_used; - /* - * We cannot have used all the data here. - */ + /* + * We cannot have used all the data here. + */ - cache_flush_needed = True; + cache_flush_needed = True; - DO_PROFILE_INC(writecache_abutted_writes); - total_written = data_used; + DO_PROFILE_INC(writecache_abutted_writes); + total_written = data_used; - write_path = 2; + write_path = 2; - } else if ( (pos >= wcp->file_size) && - (wcp->offset + wcp->data_size == wcp->file_size) && - (pos > wcp->offset + wcp->data_size) && - (pos < wcp->offset + wcp->alloc_size) ) { + } else if ( (pos >= wcp->file_size) && + (wcp->offset + wcp->data_size == wcp->file_size) && + (pos > wcp->offset + wcp->data_size) && + (pos < wcp->offset + wcp->alloc_size) ) { - /* - * Non-contiguous write part of which fits within - * the cache buffer and is extending the file - * and the cache contents reflect the current - * data up to the current end of the file. - */ + /* + * Non-contiguous write part of which fits within + * the cache buffer and is extending the file + * and the cache contents reflect the current + * data up to the current end of the file. + */ - size_t data_used; + size_t data_used; - if(pos + n <= wcp->offset + wcp->alloc_size) - data_used = n; - else - data_used = wcp->offset + wcp->alloc_size - pos; + if(pos + n <= wcp->offset + wcp->alloc_size) + data_used = n; + else + data_used = wcp->offset + wcp->alloc_size - pos; - /* - * Fill in the non-continuous area with zeros. - */ + /* + * Fill in the non-continuous area with zeros. + */ - memset(wcp->data + wcp->data_size, '\0', - pos - (wcp->offset + wcp->data_size) ); + memset(wcp->data + wcp->data_size, '\0', + pos - (wcp->offset + wcp->data_size) ); - memcpy(wcp->data + (pos - wcp->offset), data, data_used); + memcpy(wcp->data + (pos - wcp->offset), data, data_used); - /* - * Update the current buffer size with the new data. - */ + /* + * Update the current buffer size with the new data. + */ - if(pos + data_used > wcp->offset + wcp->data_size) - wcp->data_size = pos + data_used - wcp->offset; + if(pos + data_used > wcp->offset + wcp->data_size) + wcp->data_size = pos + data_used - wcp->offset; - /* - * Update the file size if changed. - */ + /* + * Update the file size if changed. + */ - if (wcp->offset + wcp->data_size > wcp->file_size) - fsp->size = wcp->file_size = wcp->offset + wcp->data_size; + if (wcp->offset + wcp->data_size > wcp->file_size) + fsp->size = wcp->file_size = wcp->offset + wcp->data_size; - /* - * If we used all the data then - * return here. - */ + /* + * If we used all the data then + * return here. + */ - if(n == data_used) - return n; - else - cache_flush_needed = True; + if(n == data_used) + return n; + else + cache_flush_needed = True; - /* - * Move the start of data forward by the amount used, - * cut down the amount left by the same amount. - */ + /* + * Move the start of data forward by the amount used, + * cut down the amount left by the same amount. + */ - data += data_used; - pos += data_used; - n -= data_used; + data += data_used; + pos += data_used; + n -= data_used; - DO_PROFILE_INC(writecache_abutted_writes); - total_written = data_used; + DO_PROFILE_INC(writecache_abutted_writes); + total_written = data_used; - write_path = 3; + write_path = 3; - } else { + } else { - /* - * Write is bigger than buffer, or there is no overlap on the - * low or high ends. - */ + /* + * Write is bigger than buffer, or there is no overlap on the + * low or high ends. + */ - DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \ + DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \ len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size )); - /* - * Update the file size if needed. - */ + /* + * Update the file size if needed. + */ - if(pos + n > wcp->file_size) - fsp->size = wcp->file_size = pos + n; + if(pos + n > wcp->file_size) + fsp->size = wcp->file_size = pos + n; - /* - * If write would fit in the cache, and is larger than - * the data already in the cache, flush the cache and - * preferentially copy the data new data into it. Otherwise - * just write the data directly. - */ + /* + * If write would fit in the cache, and is larger than + * the data already in the cache, flush the cache and + * preferentially copy the data new data into it. Otherwise + * just write the data directly. + */ - if ( n <= wcp->alloc_size && n > wcp->data_size) { - cache_flush_needed = True; - } else { - ssize_t ret = real_write_file(fsp, data, pos, n); + if ( n <= wcp->alloc_size && n > wcp->data_size) { + cache_flush_needed = True; + } else { + ssize_t ret = real_write_file(fsp, data, pos, n); - DO_PROFILE_INC(writecache_direct_writes); - if (ret == -1) - return ret; + DO_PROFILE_INC(writecache_direct_writes); + if (ret == -1) + return ret; - if (pos + ret > wcp->file_size) - fsp->size = wcp->file_size = pos + ret; + if (pos + ret > wcp->file_size) + fsp->size = wcp->file_size = pos + ret; - return ret; - } + return ret; + } - write_path = 4; + write_path = 4; - } + } - if(wcp->data_size > wcp->file_size) - fsp->size = wcp->file_size = wcp->data_size; + if(wcp->data_size > wcp->file_size) + fsp->size = wcp->file_size = wcp->data_size; - if (cache_flush_needed) { - DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \ + if (cache_flush_needed) { + DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \ n = %u, wcp->offset=%.0f, wcp->data_size=%u\n", - write_path, fsp->fd, (double)wcp->file_size, (double)pos, (unsigned int)n, - (double)wcp->offset, (unsigned int)wcp->data_size )); + write_path, fsp->fd, (double)wcp->file_size, (double)pos, (unsigned int)n, + (double)wcp->offset, (unsigned int)wcp->data_size )); - flush_write_cache(fsp, WRITE_FLUSH); - } - } + flush_write_cache(fsp, WRITE_FLUSH); + } + } - /* - * If the write request is bigger than the cache - * size, write it all out. - */ + /* + * If the write request is bigger than the cache + * size, write it all out. + */ - if (n > wcp->alloc_size ) { - ssize_t ret = real_write_file(fsp, data, pos, n); - if (ret == -1) - return -1; + if (n > wcp->alloc_size ) { + ssize_t ret = real_write_file(fsp, data, pos, n); + if (ret == -1) + return -1; - if (pos + ret > wcp->file_size) - fsp->size = wcp->file_size = pos + n; + if (pos + ret > wcp->file_size) + fsp->size = wcp->file_size = pos + n; - DO_PROFILE_INC(writecache_direct_writes); - return total_written + n; - } + DO_PROFILE_INC(writecache_direct_writes); + return total_written + n; + } - /* - * If there's any data left, cache it. - */ + /* + * If there's any data left, cache it. + */ - if (n) { + if (n) { #ifdef WITH_PROFILE - if (wcp->data_size) { - DO_PROFILE_INC(writecache_abutted_writes); - } else { - DO_PROFILE_INC(writecache_init_writes); - } + if (wcp->data_size) { + DO_PROFILE_INC(writecache_abutted_writes); + } else { + DO_PROFILE_INC(writecache_init_writes); + } #endif - memcpy(wcp->data+wcp->data_size, data, n); - if (wcp->data_size == 0) { - wcp->offset = pos; - DO_PROFILE_INC(writecache_num_write_caches); - } - wcp->data_size += n; - - /* - * Update the file size if changed. - */ - - if (wcp->offset + wcp->data_size > wcp->file_size) - fsp->size = wcp->file_size = wcp->offset + wcp->data_size; - DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n", - (double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n)); - - total_written += n; - return total_written; /* .... that's a write :) */ - } + memcpy(wcp->data+wcp->data_size, data, n); + if (wcp->data_size == 0) { + wcp->offset = pos; + DO_PROFILE_INC(writecache_num_write_caches); + } + wcp->data_size += n; + + /* + * Update the file size if changed. + */ + + if (wcp->offset + wcp->data_size > wcp->file_size) + fsp->size = wcp->file_size = wcp->offset + wcp->data_size; + DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n", + (double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n)); + + total_written += n; + return total_written; /* .... that's a write :) */ + } - return total_written; + return total_written; } /**************************************************************************** @@ -514,24 +525,23 @@ n = %u, wcp->offset=%.0f, wcp->data_size=%u\n", void delete_write_cache(files_struct *fsp) { - write_cache *wcp; - - if(!fsp) - return; + write_cache *wcp; - if(!(wcp = fsp->wcp)) - return; + if(!fsp) + return; - DO_PROFILE_DEC(writecache_allocated_write_caches); - allocated_write_caches--; + if(!(wcp = fsp->wcp)) + return; - SMB_ASSERT(wcp->data_size == 0); + DO_PROFILE_DEC(writecache_allocated_write_caches); + allocated_write_caches--; - SAFE_FREE(wcp->data); - SAFE_FREE(fsp->wcp); + SMB_ASSERT(wcp->data_size == 0); - DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name )); + SAFE_FREE(wcp->data); + SAFE_FREE(fsp->wcp); + DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name )); } /**************************************************************************** @@ -540,41 +550,41 @@ void delete_write_cache(files_struct *fsp) static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size) { - ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn)); - write_cache *wcp; - - if (allocated_write_caches >= MAX_WRITE_CACHES) - return False; - - if(alloc_size == 0 || fsp->wcp) - return False; - - if((wcp = (write_cache *)malloc(sizeof(write_cache))) == NULL) { - DEBUG(0,("setup_write_cache: malloc fail.\n")); - return False; - } - - wcp->file_size = file_size; - wcp->offset = 0; - wcp->alloc_size = alloc_size; - wcp->data_size = 0; - if((wcp->data = malloc(wcp->alloc_size)) == NULL) { - DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n", - (unsigned int)wcp->alloc_size )); - SAFE_FREE(wcp); - return False; - } - - memset(wcp->data, '\0', wcp->alloc_size ); - - fsp->wcp = wcp; - DO_PROFILE_INC(writecache_allocated_write_caches); - allocated_write_caches++; - - DEBUG(10,("setup_write_cache: File %s allocated write cache size %u\n", + ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn)); + write_cache *wcp; + + if (allocated_write_caches >= MAX_WRITE_CACHES) + return False; + + if(alloc_size == 0 || fsp->wcp) + return False; + + if((wcp = (write_cache *)malloc(sizeof(write_cache))) == NULL) { + DEBUG(0,("setup_write_cache: malloc fail.\n")); + return False; + } + + wcp->file_size = file_size; + wcp->offset = 0; + wcp->alloc_size = alloc_size; + wcp->data_size = 0; + if((wcp->data = malloc(wcp->alloc_size)) == NULL) { + DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n", + (unsigned int)wcp->alloc_size )); + SAFE_FREE(wcp); + return False; + } + + memset(wcp->data, '\0', wcp->alloc_size ); + + fsp->wcp = wcp; + DO_PROFILE_INC(writecache_allocated_write_caches); + allocated_write_caches++; + + DEBUG(10,("setup_write_cache: File %s allocated write cache size %u\n", fsp->fsp_name, wcp->alloc_size )); - return True; + return True; } /**************************************************************************** @@ -583,17 +593,17 @@ static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size) void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size) { - fsp->size = file_size; - if(fsp->wcp) { - /* The cache *must* have been flushed before we do this. */ - if (fsp->wcp->data_size != 0) { - pstring msg; - slprintf(msg, sizeof(msg)-1, "set_filelen_write_cache: size change \ + fsp->size = file_size; + if(fsp->wcp) { + /* The cache *must* have been flushed before we do this. */ + if (fsp->wcp->data_size != 0) { + pstring msg; + slprintf(msg, sizeof(msg)-1, "set_filelen_write_cache: size change \ on file %s with write cache size = %u\n", fsp->fsp_name, fsp->wcp->data_size ); - smb_panic(msg); - } - fsp->wcp->file_size = file_size; - } + smb_panic(msg); + } + fsp->wcp->file_size = file_size; + } } /******************************************************************* @@ -602,36 +612,36 @@ on file %s with write cache size = %u\n", fsp->fsp_name, fsp->wcp->data_size ); ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason) { - write_cache *wcp = fsp->wcp; - size_t data_size; - ssize_t ret; + write_cache *wcp = fsp->wcp; + size_t data_size; + ssize_t ret; - if(!wcp || !wcp->data_size) - return 0; + if(!wcp || !wcp->data_size) + return 0; - data_size = wcp->data_size; - wcp->data_size = 0; + data_size = wcp->data_size; + wcp->data_size = 0; - DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]); + DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]); - DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n", - fsp->fd, (double)wcp->offset, (unsigned int)data_size)); + DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n", + fsp->fd, (double)wcp->offset, (unsigned int)data_size)); #ifdef WITH_PROFILE - if(data_size == wcp->alloc_size) - DO_PROFILE_INC(writecache_num_perfect_writes); + if(data_size == wcp->alloc_size) + DO_PROFILE_INC(writecache_num_perfect_writes); #endif - ret = real_write_file(fsp, wcp->data, wcp->offset, data_size); + ret = real_write_file(fsp, wcp->data, wcp->offset, data_size); - /* - * Ensure file size if kept up to date if write extends file. - */ + /* + * Ensure file size if kept up to date if write extends file. + */ - if ((ret != -1) && (wcp->offset + ret > wcp->file_size)) - wcp->file_size = wcp->offset + ret; + if ((ret != -1) && (wcp->offset + ret > wcp->file_size)) + wcp->file_size = wcp->offset + ret; - return ret; + return ret; } /******************************************************************* @@ -640,12 +650,13 @@ sync a file void sync_file(connection_struct *conn, files_struct *fsp) { - if(lp_strict_sync(SNUM(conn)) && fsp->fd != -1) { - flush_write_cache(fsp, SYNC_FLUSH); - conn->vfs_ops.fsync(fsp,fsp->fd); - } + if(lp_strict_sync(SNUM(conn)) && fsp->fd != -1) { + flush_write_cache(fsp, SYNC_FLUSH); + conn->vfs_ops.fsync(fsp,fsp->fd); + } } + /************************************************************ Perform a stat whether a valid fd or not. ************************************************************/ diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index cb6a6d31a40..e5f9b7a0ae8 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -38,54 +38,29 @@ static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL d Check if two filenames are equal. This needs to be careful about whether we are case sensitive. ****************************************************************************/ + static BOOL fname_equal(char *name1, char *name2) { - int l1 = strlen(name1); - int l2 = strlen(name2); - - /* handle filenames ending in a single dot */ - if (l1-l2 == 1 && name1[l1-1] == '.' && lp_strip_dot()) - { - BOOL ret; - name1[l1-1] = 0; - ret = fname_equal(name1,name2); - name1[l1-1] = '.'; - return(ret); - } - - if (l2-l1 == 1 && name2[l2-1] == '.' && lp_strip_dot()) - { - BOOL ret; - name2[l2-1] = 0; - ret = fname_equal(name1,name2); - name2[l2-1] = '.'; - return(ret); - } - - /* now normal filename handling */ - if (case_sensitive) - return(strcmp(name1,name2) == 0); - - return(strequal(name1,name2)); -} + /* Normal filename handling */ + if (case_sensitive) + return(strcmp(name1,name2) == 0); + return(strequal(name1,name2)); +} /**************************************************************************** Mangle the 2nd name and check if it is then equal to the first name. ****************************************************************************/ -static BOOL mangled_equal(char *name1, char *name2, int snum) + +static BOOL mangled_equal(char *name1, const char *name2, int snum) { pstring tmpname; - if (mangle_is_8_3(name2, True)) { - return False; - } pstrcpy(tmpname, name2); - return mangle_map(tmpname, True, False, snum) && - strequal(name1, tmpname); + mangle_map(tmpname, True, False, snum); + return strequal(name1, tmpname); } - /**************************************************************************** This routine is called to convert names from the dos namespace to unix namespace. It needs to handle any case conversions, mangling, format @@ -116,388 +91,391 @@ for nlinks = 0, which can never be true for any file). BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_component, BOOL *bad_path, SMB_STRUCT_STAT *pst) { - SMB_STRUCT_STAT st; - char *start, *end; - pstring dirpath; - pstring orig_path; - BOOL component_was_mangled = False; - BOOL name_has_wildcard = False; - - ZERO_STRUCTP(pst); - - *dirpath = 0; - *bad_path = False; - if(saved_last_component) - *saved_last_component = 0; - - if (conn->printer) { - /* we don't ever use the filenames on a printer share as a - filename - so don't convert them */ - return True; - } - - DEBUG(5, ("unix_convert called on file \"%s\"\n", name)); - - /* - * Convert to basic unix format - removing \ chars and cleaning it up. - */ - - unix_format(name); - unix_clean_name(name); - - /* - * Names must be relative to the root of the service - trim any leading /. - * also trim trailing /'s. - */ - - trim_string(name,"/","/"); - - /* - * If we trimmed down to a single '\0' character - * then we should use the "." directory to avoid - * searching the cache, but not if we are in a - * printing share. - */ - - if (!*name) { - name[0] = '.'; - name[1] = '\0'; - } - - /* - * Ensure saved_last_component is valid even if file exists. - */ - - if(saved_last_component) { - end = strrchr_m(name, '/'); - if(end) - pstrcpy(saved_last_component, end + 1); - else - pstrcpy(saved_last_component, name); - } - - if (!case_sensitive && - (!case_preserve || (mangle_is_8_3(name, False) && !short_case_preserve))) - strnorm(name); - - /* - * If we trimmed down to a single '\0' character - * then we will be using the "." directory. - * As we know this is valid we can return true here. - */ - - if(!*name) - return(True); - - start = name; - while (strncmp(start,"./",2) == 0) - start += 2; - - pstrcpy(orig_path, name); - - if(stat_cache_lookup(conn, name, dirpath, &start, &st)) { - *pst = st; - return True; - } - - /* - * stat the name - if it exists then we are all done! - */ - -/* ZZZ: stat1 */ if (vfs_stat(conn,name,&st) == 0) { - stat_cache_add(orig_path, name); - DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); - *pst = st; - return(True); - } - - DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", - name, dirpath, start)); - - /* - * A special case - if we don't have any mangling chars and are case - * sensitive then searching won't help. - */ - - if (case_sensitive && !mangle_is_mangled(name) && - !lp_strip_dot() && !use_mangled_map) - return(False); - - name_has_wildcard = ms_has_wild(start); - - /* - * is_mangled() was changed to look at an entire pathname, not - * just a component. JRA. - */ - - if (mangle_is_mangled(start)) - component_was_mangled = True; - - /* - * Now we need to recursively match the name against the real - * directory structure. - */ - - /* - * Match each part of the path name separately, trying the names - * as is first, then trying to scan the directory for matching names. - */ - - for (; start ; start = (end?end+1:(char *)NULL)) { - /* - * Pinpoint the end of this section of the filename. - */ - end = strchr_m(start, '/'); - - /* - * Chop the name at this point. - */ - if (end) - *end = 0; - - if(saved_last_component != 0) - pstrcpy(saved_last_component, end ? end + 1 : start); - - /* - * Check if the name exists up to this point. - */ - - if (vfs_stat(conn,name, &st) == 0) { - /* - * It exists. it must either be a directory or this must be - * the last part of the path for it to be OK. - */ - if (end && !(st.st_mode & S_IFDIR)) { - /* - * An intermediate part of the name isn't a directory. - */ - DEBUG(5,("Not a dir %s\n",start)); - *end = '/'; - return(False); - } - - } else { - pstring rest; - - /* Stat failed - ensure we don't use it. */ - ZERO_STRUCT(st); - *rest = 0; - - /* - * Remember the rest of the pathname so it can be restored - * later. - */ - - if (end) - pstrcpy(rest,end+1); - - /* - * Try to find this part of the path in the directory. - */ - - if (ms_has_wild(start) || !scan_directory(dirpath, start, conn, end?True:False)) { - if (end) { - /* - * An intermediate part of the name can't be found. - */ - DEBUG(5,("Intermediate not found %s\n",start)); - *end = '/'; - - /* - * We need to return the fact that the intermediate - * name resolution failed. This is used to return an - * error of ERRbadpath rather than ERRbadfile. Some - * Windows applications depend on the difference between - * these two errors. - */ - *bad_path = True; - return(False); - } + SMB_STRUCT_STAT st; + char *start, *end; + pstring dirpath; + pstring orig_path; + BOOL component_was_mangled = False; + BOOL name_has_wildcard = False; + + ZERO_STRUCTP(pst); + + *dirpath = 0; + *bad_path = False; + if(saved_last_component) + *saved_last_component = 0; + + if (conn->printer) { + /* we don't ever use the filenames on a printer share as a + filename - so don't convert them */ + return True; + } + + DEBUG(5, ("unix_convert called on file \"%s\"\n", name)); + + /* + * Convert to basic unix format - removing \ chars and cleaning it up. + */ + + unix_format(name); + unix_clean_name(name); + + /* + * Names must be relative to the root of the service - trim any leading /. + * also trim trailing /'s. + */ + + trim_string(name,"/","/"); + + /* + * If we trimmed down to a single '\0' character + * then we should use the "." directory to avoid + * searching the cache, but not if we are in a + * printing share. + */ + + if (!*name) { + name[0] = '.'; + name[1] = '\0'; + } + + /* + * Ensure saved_last_component is valid even if file exists. + */ + + if(saved_last_component) { + end = strrchr_m(name, '/'); + if(end) + pstrcpy(saved_last_component, end + 1); + else + pstrcpy(saved_last_component, name); + } + + if (!case_sensitive && (!case_preserve || (mangle_is_8_3(name, False) && !short_case_preserve))) + strnorm(name); + + /* + * If we trimmed down to a single '\0' character + * then we will be using the "." directory. + * As we know this is valid we can return true here. + */ + + if(!*name) + return(True); + + start = name; + while (strncmp(start,"./",2) == 0) + start += 2; + + pstrcpy(orig_path, name); + + if(stat_cache_lookup(conn, name, dirpath, &start, &st)) { + *pst = st; + return True; + } + + /* + * stat the name - if it exists then we are all done! + */ + + if (vfs_stat(conn,name,&st) == 0) { + stat_cache_add(orig_path, name); + DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); + *pst = st; + return(True); + } + + DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", name, dirpath, start)); + + /* + * A special case - if we don't have any mangling chars and are case + * sensitive then searching won't help. + */ + + if (case_sensitive && !mangle_is_mangled(name) && !use_mangled_map) + return(False); + + name_has_wildcard = ms_has_wild(start); + + /* + * is_mangled() was changed to look at an entire pathname, not + * just a component. JRA. + */ + + if (mangle_is_mangled(start)) + component_was_mangled = True; + + /* + * Now we need to recursively match the name against the real + * directory structure. + */ + + /* + * Match each part of the path name separately, trying the names + * as is first, then trying to scan the directory for matching names. + */ + + for (; start ; start = (end?end+1:(char *)NULL)) { + /* + * Pinpoint the end of this section of the filename. + */ + end = strchr_m(start, '/'); + + /* + * Chop the name at this point. + */ + if (end) + *end = 0; + + if(saved_last_component != 0) + pstrcpy(saved_last_component, end ? end + 1 : start); + + /* + * Check if the name exists up to this point. + */ + + if (vfs_stat(conn,name, &st) == 0) { + /* + * It exists. it must either be a directory or this must be + * the last part of the path for it to be OK. + */ + if (end && !(st.st_mode & S_IFDIR)) { + /* + * An intermediate part of the name isn't a directory. + */ + DEBUG(5,("Not a dir %s\n",start)); + *end = '/'; + return(False); + } + + } else { + pstring rest; + + /* Stat failed - ensure we don't use it. */ + ZERO_STRUCT(st); + *rest = 0; + + /* + * Remember the rest of the pathname so it can be restored + * later. + */ + + if (end) + pstrcpy(rest,end+1); + + /* + * Try to find this part of the path in the directory. + */ + + if (ms_has_wild(start) || !scan_directory(dirpath, start, conn, end?True:False)) { + if (end) { + /* + * An intermediate part of the name can't be found. + */ + DEBUG(5,("Intermediate not found %s\n",start)); + *end = '/'; + + /* + * We need to return the fact that the intermediate + * name resolution failed. This is used to return an + * error of ERRbadpath rather than ERRbadfile. Some + * Windows applications depend on the difference between + * these two errors. + */ + *bad_path = True; + return(False); + } - /* - * Just the last part of the name doesn't exist. - * We may need to strupper() or strlower() it in case - * this conversion is being used for file creation - * purposes. If the filename is of mixed case then - * don't normalise it. - */ - - if (!case_preserve && (!strhasupper(start) || !strhaslower(start))) - strnorm(start); - - /* - * check on the mangled stack to see if we can recover the - * base of the filename. - */ - - if (mangle_is_mangled(start)) { - mangle_check_cache( start ); - } - - DEBUG(5,("New file %s\n",start)); - return(True); - } - - /* - * Restore the rest of the string. If the string was mangled the size - * may have changed. - */ - if (end) { - end = start + strlen(start); - pstrcat(start,"/"); - pstrcat(start,rest); - *end = '\0'; - } - } /* end else */ - - /* - * Add to the dirpath that we have resolved so far. - */ - if (*dirpath) - pstrcat(dirpath,"/"); - - pstrcat(dirpath,start); - - /* - * Don't cache a name with mangled or wildcard components - * as this can change the size. - */ - - if(!component_was_mangled && !name_has_wildcard) - stat_cache_add(orig_path, dirpath); - - /* - * Restore the / that we wiped out earlier. - */ - if (end) - *end = '/'; - } + /* + * Just the last part of the name doesn't exist. + * We may need to strupper() or strlower() it in case + * this conversion is being used for file creation + * purposes. If the filename is of mixed case then + * don't normalise it. + */ + + if (!case_preserve && (!strhasupper(start) || !strhaslower(start))) + strnorm(start); + + /* + * check on the mangled stack to see if we can recover the + * base of the filename. + */ + + if (mangle_is_mangled(start)) { + mangle_check_cache( start ); + } + + DEBUG(5,("New file %s\n",start)); + return(True); + } + + /* + * Restore the rest of the string. If the string was mangled the size + * may have changed. + */ + if (end) { + end = start + strlen(start); + pstrcat(start,"/"); + pstrcat(start,rest); + *end = '\0'; + } + } /* end else */ + + /* + * Add to the dirpath that we have resolved so far. + */ + if (*dirpath) + pstrcat(dirpath,"/"); + + pstrcat(dirpath,start); + + /* + * Don't cache a name with mangled or wildcard components + * as this can change the size. + */ + + if(!component_was_mangled && !name_has_wildcard) + stat_cache_add(orig_path, dirpath); + + /* + * Restore the / that we wiped out earlier. + */ + if (end) + *end = '/'; + } - /* - * Don't cache a name with mangled or wildcard components - * as this can change the size. - */ + /* + * Don't cache a name with mangled or wildcard components + * as this can change the size. + */ - if(!component_was_mangled && !name_has_wildcard) - stat_cache_add(orig_path, name); + if(!component_was_mangled && !name_has_wildcard) + stat_cache_add(orig_path, name); - /* - * If we ended up resolving the entire path then return a valid - * stat struct if we got one. - */ + /* + * If we ended up resolving the entire path then return a valid + * stat struct if we got one. + */ - if (VALID_STAT(st) && (strlen(orig_path) == strlen(name))) - *pst = st; + if (VALID_STAT(st) && (strlen(orig_path) == strlen(name))) + *pst = st; - /* - * The name has been resolved. - */ + /* + * The name has been resolved. + */ - DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); - return(True); + DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); + return(True); } - /**************************************************************************** -check a filename - possibly caling reducename - -This is called by every routine before it allows an operation on a filename. -It does any final confirmation necessary to ensure that the filename is -a valid one for the user to access. + Check a filename - possibly caling reducename. + This is called by every routine before it allows an operation on a filename. + It does any final confirmation necessary to ensure that the filename is + a valid one for the user to access. ****************************************************************************/ + BOOL check_name(char *name,connection_struct *conn) { - BOOL ret; + BOOL ret; - errno = 0; + errno = 0; - if (IS_VETO_PATH(conn, name)) { - DEBUG(5,("file path name %s vetoed\n",name)); - return(0); - } + if (IS_VETO_PATH(conn, name)) { + if(strcmp(name, ".") && strcmp(name, "..")) { + DEBUG(5,("file path name %s vetoed\n",name)); + return(0); + } + } - ret = reduce_name(conn,name,conn->connectpath,lp_widelinks(SNUM(conn))); + ret = reduce_name(conn,name,conn->connectpath,lp_widelinks(SNUM(conn))); - /* Check if we are allowing users to follow symlinks */ - /* Patch from David Clerc <David.Clerc@cui.unige.ch> - University of Geneva */ + /* Check if we are allowing users to follow symlinks */ + /* Patch from David Clerc <David.Clerc@cui.unige.ch> + University of Geneva */ #ifdef S_ISLNK - if (!lp_symlinks(SNUM(conn))) { - SMB_STRUCT_STAT statbuf; - if ( (conn->vfs_ops.lstat(conn,name,&statbuf) != -1) && - (S_ISLNK(statbuf.st_mode)) ) { - DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name)); - ret=0; - } - } + if (!lp_symlinks(SNUM(conn))) { + SMB_STRUCT_STAT statbuf; + if ( (conn->vfs_ops.lstat(conn,name,&statbuf) != -1) && + (S_ISLNK(statbuf.st_mode)) ) { + DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name)); + ret=0; + } + } #endif - if (!ret) - DEBUG(5,("check_name on %s failed\n",name)); + if (!ret) + DEBUG(5,("check_name on %s failed\n",name)); - return(ret); + return(ret); } - /**************************************************************************** -scan a directory to find a filename, matching without case sensitivity - -If the name looks like a mangled name then try via the mangling functions + Scan a directory to find a filename, matching without case sensitivity. + If the name looks like a mangled name then try via the mangling functions ****************************************************************************/ + static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache) { - void *cur_dir; - char *dname; - BOOL mangled; - pstring name2; - - mangled = mangle_is_mangled(name); - - /* handle null paths */ - if (*path == 0) - path = "."; - - if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) { - pstrcpy(name, dname); - return(True); - } - - /* - * The incoming name can be mangled, and if we de-mangle it - * here it will not compare correctly against the filename (name2) - * read from the directory and then mangled by the mangle_map() - * call. We need to mangle both names or neither. - * (JRA). - */ - if (mangled) - mangled = !mangle_check_cache( name ); - - /* open the directory */ - if (!(cur_dir = OpenDir(conn, path, True))) { - DEBUG(3,("scan dir didn't open dir [%s]\n",path)); - return(False); - } - - /* now scan for matching names */ - while ((dname = ReadDirName(cur_dir))) { - if (*dname == '.' && (strequal(dname,".") || strequal(dname,".."))) - continue; - - pstrcpy(name2,dname); - if (!mangle_map(name2,False,True,SNUM(conn))) - continue; - - if ((mangled && mangled_equal(name,name2,SNUM(conn))) || fname_equal(name, dname)) { - /* we've found the file, change it's name and return */ - if (docache) - DirCacheAdd(path,name,dname,SNUM(conn)); - pstrcpy(name, dname); - CloseDir(cur_dir); - return(True); - } - } - - CloseDir(cur_dir); - return(False); + void *cur_dir; + char *dname; + BOOL mangled; + + mangled = mangle_is_mangled(name); + + /* handle null paths */ + if (*path == 0) + path = "."; + + if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) { + pstrcpy(name, dname); + return(True); + } + + /* + * The incoming name can be mangled, and if we de-mangle it + * here it will not compare correctly against the filename (name2) + * read from the directory and then mangled by the mangle_map() + * call. We need to mangle both names or neither. + * (JRA). + */ + if (mangled) + mangled = !mangle_check_cache( name ); + + /* open the directory */ + if (!(cur_dir = OpenDir(conn, path, True))) { + DEBUG(3,("scan dir didn't open dir [%s]\n",path)); + return(False); + } + + /* now scan for matching names */ + while ((dname = ReadDirName(cur_dir))) { + if (*dname == '.' && (strequal(dname,".") || strequal(dname,".."))) + continue; + + /* + * At this point dname is the unmangled name. + * name is either mangled or not, depending on the state of the "mangled" + * variable. JRA. + */ + + /* + * Check mangled name against mangled name, or unmangled name + * against unmangled name. + */ + + if ((mangled && mangled_equal(name,dname,SNUM(conn))) || fname_equal(name, dname)) { + /* we've found the file, change it's name and return */ + if (docache) + DirCacheAdd(path,name,dname,SNUM(conn)); + pstrcpy(name, dname); + CloseDir(cur_dir); + return(True); + } + } + + CloseDir(cur_dir); + return(False); } diff --git a/source3/smbd/groupname.c b/source3/smbd/groupname.c index 812488571a3..5147ae4b95e 100644 --- a/source3/smbd/groupname.c +++ b/source3/smbd/groupname.c @@ -21,7 +21,6 @@ #ifdef USING_GROUPNAME_MAP #include "includes.h" -extern DOM_SID global_sam_sid; /************************************************************************** Groupname map functionality. The code loads a groupname map file and @@ -160,7 +159,7 @@ Error was %s.\n", unixname, strerror(errno) )); * It's not a well known name, convert the UNIX gid_t * to a rid within this domain SID. */ - tmp_sid = global_sam_sid; + sid_copy(&tmp_sid,get_global_sam_sid()); tmp_sid.sub_auths[tmp_sid.num_auths++] = pdb_gid_to_group_rid(gid); } @@ -228,7 +227,7 @@ void map_gid_to_sid( gid_t gid, DOM_SID *psid) * If there's no map, convert the UNIX gid_t * to a rid within this domain SID. */ - *psid = global_sam_sid; + sid_copy(psid,get_global_sam_sid()); psid->sub_auths[psid->num_auths++] = pdb_gid_to_group_rid(gid); return; diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index c2f3b7b2f0b..91b221968f2 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -375,7 +375,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int START_PROFILE(SMBtrans); memset(name, '\0',sizeof(name)); - srvstr_pull(inbuf, name, smb_buf(inbuf), sizeof(name), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, name, smb_buf(inbuf), sizeof(name), STR_TERMINATE); if (dscnt > tdscnt || pscnt > tpscnt) { exit_server("invalid trans parameters"); diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index 666bbb5f618..217bb6a6133 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -71,7 +71,7 @@ static int CopyExpanded(connection_struct *conn, StrnCpy(buf,src,sizeof(buf)/2); pstring_sub(buf,"%S",lp_servicename(snum)); - standard_sub_conn(conn,buf); + standard_sub_conn(conn,buf,sizeof(buf)); l = push_ascii(*dst,buf,*n-1, STR_TERMINATE); (*dst) += l; (*n) -= l; @@ -94,7 +94,7 @@ static int StrlenExpanded(connection_struct *conn, int snum, char* s) if (!s) return(0); StrnCpy(buf,s,sizeof(buf)/2); pstring_sub(buf,"%S",lp_servicename(snum)); - standard_sub_conn(conn,buf); + standard_sub_conn(conn,buf,sizeof(buf)); return strlen(buf) + 1; } @@ -104,7 +104,7 @@ static char* Expand(connection_struct *conn, int snum, char* s) if (!s) return(NULL); StrnCpy(buf,s,sizeof(buf)/2); pstring_sub(buf,"%S",lp_servicename(snum)); - standard_sub_conn(conn,buf); + standard_sub_conn(conn,buf,sizeof(buf)); return &buf[0]; } @@ -1670,7 +1670,7 @@ static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,ch fstring comment; pstring pathname; char *command, *cmdname; - uint offset; + unsigned int offset; int snum; int res = ERRunsup; @@ -1754,82 +1754,104 @@ static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,c char **rdata,char **rparam, int *rdata_len,int *rparam_len) { + int i; + int errflags=0; + int resume_context, cli_buf_size; char *str1 = param+2; char *str2 = skip_string(str1,1); char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - char *p2; - int count=0; - if (!prefix_ok(str1,"WrLeh")) return False; - - /* check it's a supported variant */ - switch( uLevel ) - { - case 0: - p2 = "B21"; - break; - default: - return False; + GROUP_MAP *group_list; + int num_entries; + + if (strcmp(str1,"WrLeh") != 0) + return False; + + /* parameters + * W-> resume context (number of users to skip) + * r -> return parameter pointer to receive buffer + * L -> length of receive buffer + * e -> return parameter number of entries + * h -> return parameter total number of users + */ + if (strcmp("B21",str2) != 0) + return False; + + /* get list of domain groups SID_DOMAIN_GRP=2 */ + if(!enum_group_mapping(2 , &group_list, &num_entries, False, False)) { + DEBUG(3,("api_RNetGroupEnum:failed to get group list")); + return False; } - if (strcmp(p2,str2) != 0) return False; + resume_context = SVAL(p,0); + cli_buf_size=SVAL(p+2,0); + DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: %d\n", resume_context, cli_buf_size)); - *rdata_len = mdrcnt + 1024; + *rdata_len = cli_buf_size; *rdata = REALLOC(*rdata,*rdata_len); - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - 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++; + for(i=resume_context; i<num_entries; i++) { + char* name=group_list[i].nt_name; + if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) { + /* truncate the name at 21 chars. */ + memcpy(p, name, 21); + DEBUG(10,("adding entry %d group %s\n", i, p)); + p += 21; + } else { + /* set overflow error */ + DEBUG(3,("overflow on entry %d group %s\n", i, name)); + errflags=234; + break; + } + } *rdata_len = PTR_DIFF(p,*rdata); *rparam_len = 8; *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,4,count); /* is this right?? */ - SSVAL(*rparam,6,count); /* is this right?? */ - - DEBUG(3,("api_RNetGroupEnum gave %d entries\n", count)); + SSVAL(*rparam, 0, errflags); + SSVAL(*rparam, 2, 0); /* converter word */ + SSVAL(*rparam, 4, i-resume_context); /* is this right?? */ + SSVAL(*rparam, 6, num_entries); /* is this right?? */ return(True); } -/**************************************************************************** - view list of groups available - ****************************************************************************/ -static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data, +/******************************************************************* + get groups that a user is a member of + ******************************************************************/ +static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data, int mdrcnt,int mprcnt, char **rdata,char **rparam, int *rdata_len,int *rparam_len) { char *str1 = param+2; char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); + char *UserName = skip_string(str2,1); + char *p = skip_string(UserName,1); int uLevel = SVAL(p,0); char *p2; int count=0; - if (!prefix_ok(str1,"WrLeh")) return False; + *rparam_len = 8; + *rparam = REALLOC(*rparam,*rparam_len); - /* check it's a supported variant */ - switch( uLevel ) - { - case 0: - p2 = "B21"; + /* check it's a supported varient */ + if (!strcmp(str1,"zWrLeh")) + return False; + switch( uLevel ) { + case 0: + p2 = "B21"; break; - default: + default: return False; } - if (strcmp(p2,str2) != 0) return False; + if (strcmp(p2,str2) != 0) + return False; *rdata_len = mdrcnt + 1024; *rdata = REALLOC(*rdata,*rdata_len); @@ -1847,15 +1869,101 @@ static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,ch *rdata_len = PTR_DIFF(p,*rdata); + SSVAL(*rparam,4,count); /* is this right?? */ + SSVAL(*rparam,6,count); /* is this right?? */ + + return(True); +} + +/******************************************************************* + get all users + ******************************************************************/ +static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data, + int mdrcnt,int mprcnt, + char **rdata,char **rparam, + int *rdata_len,int *rparam_len) +{ + SAM_ACCOUNT *pwd=NULL; + int count_sent=0; + int count_total=0; + int errflags=0; + int resume_context, cli_buf_size; + + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *p = skip_string(str2,1); + + if (strcmp(str1,"WrLeh") != 0) + return False; + /* parameters + * W-> resume context (number of users to skip) + * r -> return parameter pointer to receive buffer + * L -> length of receive buffer + * e -> return parameter number of entries + * h -> return parameter total number of users + */ + + resume_context = SVAL(p,0); + cli_buf_size=SVAL(p+2,0); + DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n", resume_context, cli_buf_size)); + *rparam_len = 8; *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,4,count); /* is this right?? */ - SSVAL(*rparam,6,count); /* is this right?? */ + /* check it's a supported varient */ + if (strcmp("B21",str2) != 0) + return False; - DEBUG(3,("api_RNetUserEnum gave %d entries\n", count)); + *rdata_len = cli_buf_size; + *rdata = REALLOC(*rdata,*rdata_len); - return(True); + p = *rdata; + + /* to get user list enumerations for NetUserEnum in B21 format */ + pdb_init_sam(&pwd); + + /* Open the passgrp file - not for update. */ + become_root(); + if(!pdb_setsampwent(False)) { + DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n")); + unbecome_root(); + return False; + } + errflags=NERR_Success; + + while ( pdb_getsampwent(pwd) ) { + const char *name=pdb_get_username(pwd); + if ((name) && (*(name+strlen(name)-1)!='$')) { + count_total++; + if(count_total>=resume_context) { + if( ((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21) ) { + pstrcpy(p,name); + DEBUG(10,("api_RNetUserEnum:adding entry %d username %s\n",count_sent,p)); + p += 21; + count_sent++; + } else { + /* set overflow error */ + DEBUG(10,("api_RNetUserEnum:overflow on entry %d username %s\n",count_sent,name)); + errflags=234; + break; + } + } + } + } ; + + pdb_endsampwent(); + unbecome_root(); + + pdb_free_sam(&pwd); + + *rdata_len = PTR_DIFF(p,*rdata); + + SSVAL(*rparam,0,errflags); + SSVAL(*rparam,2,0); /* converter word */ + SSVAL(*rparam,4,count_sent); /* is this right?? */ + SSVAL(*rparam,6,count_total); /* is this right?? */ + + return True; } @@ -2343,7 +2451,7 @@ static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *par SIVAL(p,6,0); } else { SIVAL(p,6,PTR_DIFF(p2,*rdata)); - standard_sub_conn(conn,comment); + standard_sub_conn(conn,comment,sizeof(comment)); StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0)); p2 = skip_string(p2,1); } @@ -2685,8 +2793,7 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */ SIVALS(p,usri11_password_age,-1); /* password age */ SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */ - pstrcpy(p2, lp_logon_home()); - standard_sub_conn(conn, p2); + pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : ""); p2 = skip_string(p2,1); SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */ pstrcpy(p2,""); @@ -2722,15 +2829,13 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param SSVAL(p,42, conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */ - pstrcpy(p2,lp_logon_home()); - standard_sub_conn(conn, p2); + pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : ""); p2 = skip_string(p2,1); SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */ *p2++ = 0; SSVAL(p,52,0); /* flags */ SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */ - pstrcpy(p2,lp_logon_script()); - standard_sub_conn( conn, p2 ); + pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : ""); p2 = skip_string(p2,1); if (uLevel == 2) { @@ -2755,7 +2860,7 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param SSVALS(p,104,-1); /* num_logons */ SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */ pstrcpy(p2,"\\\\%L"); - standard_sub_conn(conn, p2); + standard_sub_conn(conn, p2,0); p2 = skip_string(p2,1); SSVAL(p,110,49); /* country_code */ SSVAL(p,112,860); /* code page */ @@ -2769,56 +2874,6 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param return(True); } -/******************************************************************* - get groups that a user is a member of - ******************************************************************/ -static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *UserName = skip_string(str2,1); - char *p = skip_string(UserName,1); - int uLevel = SVAL(p,0); - char *p2; - int count=0; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - - /* check it's a supported varient */ - if (strcmp(str1,"zWrLeh") != 0) return False; - switch( uLevel ) { - case 0: p2 = "B21"; break; - default: return False; - } - if (strcmp(p2,str2) != 0) return False; - - *rdata_len = mdrcnt + 1024; - *rdata = REALLOC(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - 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++; - - *rdata_len = PTR_DIFF(p,*rdata); - - SSVAL(*rparam,4,count); /* is this right?? */ - SSVAL(*rparam,6,count); /* is this right?? */ - - return(True); -} - - static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data, int mdrcnt,int mprcnt, char **rdata,char **rparam, @@ -2830,6 +2885,12 @@ static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param int uLevel; struct pack_desc desc; char* name; + /* With share level security vuid will always be zero. + Don't depend on vuser being non-null !!. JRA */ + user_struct *vuser = get_valid_user_struct(vuid); + if(vuser != NULL) + DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid, + vuser->user.unix_name)); uLevel = SVAL(p,0); name = p + 2; @@ -2873,15 +2934,7 @@ static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param } PACKS(&desc,"z",global_myworkgroup);/* domain */ -/* JHT - By calling lp_logon_script() and standard_sub() we have */ -/* made sure all macros are fully substituted and available */ - { - pstring logon_script; - pstrcpy(logon_script,lp_logon_script()); - standard_sub_conn( conn, logon_script ); - PACKS(&desc,"z", logon_script); /* script path */ - } -/* End of JHT mods */ + PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */ PACKI(&desc,"D",0x00000000); /* reserved */ } @@ -3030,7 +3083,7 @@ static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *pa DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name)); - /* check it's a supported varient */ + /* check it's a supported variant */ if (strcmp(str1,"zWrLeh") != 0) return False; if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */ if (!check_printjob_info(&desc,uLevel,str2)) return False; @@ -3383,38 +3436,6 @@ static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param, return(True); } -struct session_info { - char machine[31]; - char username[24]; - char clitype[24]; - int opens; - int time; -}; - -struct sessions_info { - int count; - struct session_info *session_list; -}; - -static int gather_sessioninfo(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) -{ - struct sessions_info *sinfo = state; - struct session_info *curinfo = NULL; - struct sessionid *sessid = (struct sessionid *) dbuf.dptr; - - sinfo->count += 1; - sinfo->session_list = REALLOC(sinfo->session_list, sinfo->count * sizeof(struct session_info)); - - curinfo = &(sinfo->session_list[sinfo->count - 1]); - - safe_strcpy(curinfo->machine, sessid->remote_machine, - sizeof(curinfo->machine)); - safe_strcpy(curinfo->username, uidtoname(sessid->uid), - sizeof(curinfo->username)); - DEBUG(7,("gather_sessioninfo session from %s@%s\n", - curinfo->username, curinfo->machine)); - return 0; -} /**************************************************************************** List open sessions @@ -3430,8 +3451,8 @@ static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param char *p = skip_string(str2,1); int uLevel; struct pack_desc desc; - struct sessions_info sinfo; - int i; + struct sessionid *session_list; + int i, num_sessions; memset((char *)&desc,'\0',sizeof(desc)); @@ -3445,26 +3466,20 @@ static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) return False; if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) return False; - sinfo.count = 0; - sinfo.session_list = NULL; - - if (!session_traverse(gather_sessioninfo, &sinfo)) { - DEBUG(4,("RNetSessionEnum session_traverse failed\n")); - return False; - } + num_sessions = list_sessions(&session_list); if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); memset((char *)&desc,'\0',sizeof(desc)); desc.base = *rdata; desc.buflen = mdrcnt; desc.format = str2; - if (!init_package(&desc,sinfo.count,0)) { + if (!init_package(&desc,num_sessions,0)) { return False; } - for(i=0; i<sinfo.count; i++) { - PACKS(&desc, "z", sinfo.session_list[i].machine); - PACKS(&desc, "z", sinfo.session_list[i].username); + for(i=0; i<num_sessions; i++) { + PACKS(&desc, "z", session_list[i].remote_machine); + PACKS(&desc, "z", session_list[i].username); PACKI(&desc, "W", 1); /* num conns */ PACKI(&desc, "W", 0); /* num opens */ PACKI(&desc, "W", 1); /* num users */ @@ -3480,7 +3495,7 @@ static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param *rparam = REALLOC(*rparam,*rparam_len); SSVALS(*rparam,0,desc.errcode); SSVAL(*rparam,2,0); /* converter */ - SSVAL(*rparam,4,sinfo.count); /* count */ + SSVAL(*rparam,4,num_sessions); /* count */ DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode)); return True; @@ -3540,43 +3555,47 @@ struct int id; BOOL (*fn)(connection_struct *,uint16,char *,char *, int,int,char **,char **,int *,int *); - int flags; + BOOL auth_user; /* Deny anonymous access? */ } api_commands[] = { - {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum,0}, - {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo,0}, - {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd,0}, - {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum,0}, - {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo,0}, - {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum,0}, - {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers,0}, - {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum,0}, - {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo,0}, - {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups,0}, - {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo,0}, - {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum,0}, - {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo,0}, - {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl,0}, - {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl,0}, - {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate,0}, - {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo,0}, - {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel,0}, - {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel,0}, - {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel,0}, - {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum,0}, - {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo,0}, - {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD,0}, - {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl,0}, - {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum,0}, - {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms,0}, - {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword,0}, - {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon,0}, - {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo,0}, - {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum,0}, - {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum,0}, - {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum,0}, - {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword,0}, - {NULL, -1, api_Unsupported,0}}; - + {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True}, + {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo}, + {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd}, + {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True}, + {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo}, + {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True}, + {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True}, + {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True}, + {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo}, + {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups}, + {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo}, + {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True}, + {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo}, + {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl}, + {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl}, + {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate}, + {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo}, + {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel}, + {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel}, + {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel}, + {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum}, + {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo}, + {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD}, + {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl}, + {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */ + {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms}, + {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword}, + {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon}, + {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo}, + {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum}, + {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum}, + {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum}, + {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */ + {NULL, -1, api_Unsupported}}; + +/* The following RAP calls are not implemented by Samba: + + RAP_WFileEnum2 - anon not OK +*/ /**************************************************************************** Handle remote api calls @@ -3613,6 +3632,15 @@ int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char * } } + /* Check whether this api call can be done anonymously */ + + if (api_commands[i].auth_user && lp_restrict_anonymous()) { + user_struct *user = get_valid_user_struct(vuid); + + if (!user || user->guest) + return ERROR_NT(NT_STATUS_ACCESS_DENIED); + } + rdata = (char *)malloc(1024); if (rdata) memset(rdata,'\0',1024); diff --git a/source3/smbd/mangle.c b/source3/smbd/mangle.c index 20b2b419cf1..392e48afc19 100644 --- a/source3/smbd/mangle.c +++ b/source3/smbd/mangle.c @@ -29,6 +29,7 @@ static struct { } mangle_backends[] = { { "hash", mangle_hash_init }, { "hash2", mangle_hash2_init }, + /*{ "tdb", mangle_tdb_init }, */ { NULL, NULL } }; @@ -40,11 +41,12 @@ static void mangle_init(void) int i; char *method; - if (mangle_fns) return; + if (mangle_fns) + return; method = lp_mangling_method(); - /* find the first mangling method that manages to initialise and + /* find the first mangling method that manages to initialise and matches the "mangling method" parameter */ for (i=0; mangle_backends[i].name && !mangle_fns; i++) { if (!method || !*method || strcmp(method, mangle_backends[i].name) == 0) { @@ -82,7 +84,12 @@ BOOL mangle_is_mangled(const char *s) */ BOOL mangle_is_8_3(const char *fname, BOOL check_case) { - return mangle_fns->is_8_3(fname, check_case); + return mangle_fns->is_8_3(fname, check_case, False); +} + +BOOL mangle_is_8_3_wildcards(const char *fname, BOOL check_case) +{ + return mangle_fns->is_8_3(fname, check_case, True); } /* @@ -99,7 +106,8 @@ BOOL mangle_check_cache(char *s) /* map a long filename to a 8.3 name. */ -BOOL mangle_map(char *OutName, BOOL need83, BOOL cache83, int snum) + +void mangle_map(char *OutName, BOOL need83, BOOL cache83, int snum) { /* name mangling can be disabled for speed, in which case we just truncate the string */ @@ -107,11 +115,10 @@ BOOL mangle_map(char *OutName, BOOL need83, BOOL cache83, int snum) if (need83) { string_truncate(OutName, 12); } - return True; + return; } /* invoke the inane "mangled map" code */ mangle_map_filename(OutName, snum); - - return mangle_fns->name_map(OutName, need83, cache83); + mangle_fns->name_map(OutName, need83, cache83); } diff --git a/source3/smbd/mangle_hash.c b/source3/smbd/mangle_hash.c index f38c2ae2c45..1d4697474ce 100644 --- a/source3/smbd/mangle_hash.c +++ b/source3/smbd/mangle_hash.c @@ -127,9 +127,8 @@ static BOOL ct_initialized = False; static ubi_cacheRoot mangled_cache[1] = { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } }; static BOOL mc_initialized = False; -#define MANGLED_CACHE_MAX_ENTRIES 0 -#define MANGLED_CACHE_MAX_MEMORY 16384 - +#define MANGLED_CACHE_MAX_ENTRIES 1024 +#define MANGLED_CACHE_MAX_MEMORY 0 /* -------------------------------------------------------------------------- ** * External Variables... @@ -140,16 +139,19 @@ extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */ /* -------------------------------------------------------------------- */ -static NTSTATUS has_valid_chars(const smb_ucs2_t *s) +static NTSTATUS has_valid_chars(const smb_ucs2_t *s, BOOL allow_wildcards) { - if (!s || !*s) return NT_STATUS_INVALID_PARAMETER; + if (!s || !*s) + return NT_STATUS_INVALID_PARAMETER; /* CHECK: this should not be necessary if the ms wild chars are not valid in valid.dat --- simo */ - if (ms_has_wild_w(s)) return NT_STATUS_UNSUCCESSFUL; + if (!allow_wildcards && ms_has_wild_w(s)) + return NT_STATUS_UNSUCCESSFUL; while (*s) { - if(!isvalid83_w(*s)) return NT_STATUS_UNSUCCESSFUL; + if(!isvalid83_w(*s)) + return NT_STATUS_UNSUCCESSFUL; s++; } @@ -159,7 +161,9 @@ static NTSTATUS has_valid_chars(const smb_ucs2_t *s) /* return False if something fail and * return 2 alloced unicode strings that contain prefix and extension */ -static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix, smb_ucs2_t **extension) + +static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix, + smb_ucs2_t **extension, BOOL allow_wildcards) { size_t ext_len; smb_ucs2_t *p; @@ -169,12 +173,10 @@ static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **pr if (!*prefix) { return NT_STATUS_NO_MEMORY; } - if ((p = strrchr_w(*prefix, UCS2_CHAR('.')))) - { + if ((p = strrchr_w(*prefix, UCS2_CHAR('.')))) { ext_len = strlen_w(p+1); if ((ext_len > 0) && (ext_len < 4) && (p != *prefix) && - (NT_STATUS_IS_OK(has_valid_chars(p+1)))) /* check extension */ - { + (NT_STATUS_IS_OK(has_valid_chars(p+1,allow_wildcards)))) /* check extension */ { *p = 0; *extension = strdup_w(p+1); if (!*extension) { @@ -197,20 +199,34 @@ static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **pr * * ************************************************************************** ** */ -static NTSTATUS is_valid_name(const smb_ucs2_t *fname) + +static NTSTATUS is_valid_name(const smb_ucs2_t *fname, BOOL allow_wildcards) { smb_ucs2_t *str, *p; NTSTATUS ret = NT_STATUS_OK; - if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER; + if (!fname || !*fname) + return NT_STATUS_INVALID_PARAMETER; - if (*fname == UCS2_CHAR('.')) return NT_STATUS_UNSUCCESSFUL; + /* . and .. are valid names. */ + if (strcmp_wa(fname, ".")==0 || strcmp_wa(fname, "..")==0) + return NT_STATUS_OK; + + /* Name cannot start with '.' */ + if (*fname == UCS2_CHAR('.')) + return NT_STATUS_UNSUCCESSFUL; - ret = has_valid_chars(fname); - if (NT_STATUS_IS_ERR(ret)) return ret; + ret = has_valid_chars(fname, allow_wildcards); + if (NT_STATUS_IS_ERR(ret)) + return ret; str = strdup_w(fname); p = strchr_w(str, UCS2_CHAR('.')); + if (p && p[1] == UCS2_CHAR(0)) { + /* Name cannot end in '.' */ + SAFE_FREE(str); + return NT_STATUS_UNSUCCESSFUL; + } if (p) *p = 0; strupper_w(str); p = &(str[1]); @@ -254,27 +270,34 @@ static NTSTATUS is_valid_name(const smb_ucs2_t *fname) return ret; } -static NTSTATUS is_8_3_w(const smb_ucs2_t *fname) +static NTSTATUS is_8_3_w(const smb_ucs2_t *fname, BOOL allow_wildcards) { smb_ucs2_t *pref = 0, *ext = 0; size_t plen; NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER; + if (!fname || !*fname) + return NT_STATUS_INVALID_PARAMETER; - if (strlen_w(fname) > 12) return NT_STATUS_UNSUCCESSFUL; + if (strlen_w(fname) > 12) + return NT_STATUS_UNSUCCESSFUL; if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0) return NT_STATUS_OK; - if (NT_STATUS_IS_ERR(is_valid_name(fname))) goto done; + if (NT_STATUS_IS_ERR(is_valid_name(fname, allow_wildcards))) + goto done; - if (NT_STATUS_IS_ERR(mangle_get_prefix(fname, &pref, &ext))) goto done; + if (NT_STATUS_IS_ERR(mangle_get_prefix(fname, &pref, &ext, allow_wildcards))) + goto done; plen = strlen_w(pref); - if (strchr_wa(pref, '.')) goto done; - if (plen < 1 || plen > 8) goto done; - if (ext) if (strlen_w(ext) > 3) goto done; + if (strchr_wa(pref, '.')) + goto done; + if (plen < 1 || plen > 8) + goto done; + if (ext && (strlen_w(ext) > 3)) + goto done; ret = NT_STATUS_OK; @@ -284,26 +307,29 @@ done: return ret; } -static BOOL is_8_3(const char *fname, BOOL check_case) +static BOOL is_8_3(const char *fname, BOOL check_case, BOOL allow_wildcards) { const char *f; smb_ucs2_t *ucs2name; NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - if (!fname || !*fname) return False; - if ((f = strrchr(fname, '/')) == NULL) f = fname; - else f++; + if (!fname || !*fname) + return False; + if ((f = strrchr(fname, '/')) == NULL) + f = fname; + else + f++; - if (strlen(f) > 12) return False; + if (strlen(f) > 12) + return False; ucs2name = acnv_uxu2(f); - if (!ucs2name) - { + if (!ucs2name) { DEBUG(0,("is_8_3: internal error acnv_uxu2() failed!\n")); goto done; } - ret = is_8_3_w(ucs2name); + ret = is_8_3_w(ucs2name, allow_wildcards); done: SAFE_FREE(ucs2name); @@ -334,21 +360,20 @@ done: * ************************************************************************** ** */ static void init_chartest( void ) - { - char *illegalchars = "*\\/?<>|\":"; - unsigned char *s; +{ + char *illegalchars = "*\\/?<>|\":"; + unsigned char *s; - memset( (char *)chartest, '\0', 256 ); - - for( s = (unsigned char *)illegalchars; *s; s++ ) - chartest[*s] = ILLEGAL_MASK; + memset( (char *)chartest, '\0', 256 ); - for( s = (unsigned char *)basechars; *s; s++ ) - chartest[*s] |= BASECHAR_MASK; + for( s = (unsigned char *)illegalchars; *s; s++ ) + chartest[*s] = ILLEGAL_MASK; - ct_initialized = True; - } /* init_chartest */ + for( s = (unsigned char *)basechars; *s; s++ ) + chartest[*s] |= BASECHAR_MASK; + ct_initialized = True; +} /* ************************************************************************** ** * Return True if the name *could be* a mangled name. @@ -368,24 +393,22 @@ static void init_chartest( void ) * ************************************************************************** ** */ static BOOL is_mangled(const char *s) - { - char *magic; - - if( !ct_initialized ) - init_chartest(); - - magic = strchr_m( s, magic_char ); - while( magic && magic[1] && magic[2] ) /* 3 chars, 1st is magic. */ - { - if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */ - && isbasechar( toupper(magic[1]) ) /* is 2nd char basechar? */ - && isbasechar( toupper(magic[2]) ) ) /* is 3rd char basechar? */ - return( True ); /* If all above, then true, */ - magic = strchr_m( magic+1, magic_char ); /* else seek next magic. */ - } - return( False ); - } /* is_mangled */ - +{ + char *magic; + + if( !ct_initialized ) + init_chartest(); + + magic = strchr_m( s, magic_char ); + while( magic && magic[1] && magic[2] ) { /* 3 chars, 1st is magic. */ + if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */ + && isbasechar( toupper(magic[1]) ) /* is 2nd char basechar? */ + && isbasechar( toupper(magic[2]) ) ) /* is 3rd char basechar? */ + return( True ); /* If all above, then true, */ + magic = strchr_m( magic+1, magic_char ); /* else seek next magic. */ + } + return( False ); +} /* ************************************************************************** ** * Compare two cache keys and return a value indicating their ordinal @@ -407,12 +430,12 @@ static BOOL is_mangled(const char *s) * ************************************************************************** ** */ static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr ) - { - char *Key1 = (char *)ItemPtr; - char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1); +{ + char *Key1 = (char *)ItemPtr; + char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1); - return( StrCaseCmp( Key1, Key2 ) ); - } /* cache_compare */ + return( StrCaseCmp( Key1, Key2 ) ); +} /* ************************************************************************** ** * Free a cache entry. @@ -428,10 +451,10 @@ static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr ) * ************************************************************************** ** */ static void cache_free_entry( ubi_trNodePtr WarrenZevon ) - { - ZERO_STRUCTP(WarrenZevon); - SAFE_FREE( WarrenZevon ); - } /* cache_free_entry */ +{ + ZERO_STRUCTP(WarrenZevon); + SAFE_FREE( WarrenZevon ); +} /* ************************************************************************** ** * Initializes or clears the mangled cache. @@ -449,28 +472,25 @@ static void cache_free_entry( ubi_trNodePtr WarrenZevon ) * * ************************************************************************** ** */ + static void mangle_reset( void ) - { - if( !mc_initialized ) - { - (void)ubi_cacheInit( mangled_cache, - cache_compare, - cache_free_entry, - MANGLED_CACHE_MAX_ENTRIES, - MANGLED_CACHE_MAX_MEMORY ); - mc_initialized = True; - } - else - { - (void)ubi_cacheClear( mangled_cache ); - } - - /* - (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() ); - (void)ubi_cacheSetMaxMemory( mangled_cache, lp_mangled_cache_memory() ); - */ - } /* reset_mangled_cache */ +{ + if( !mc_initialized ) { + (void)ubi_cacheInit( mangled_cache, + cache_compare, + cache_free_entry, + MANGLED_CACHE_MAX_ENTRIES, + MANGLED_CACHE_MAX_MEMORY ); + mc_initialized = True; + } else { + (void)ubi_cacheClear( mangled_cache ); + } + /* + (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() ); + (void)ubi_cacheSetMaxMemory( mangled_cache, lp_mangled_cache_memory() ); + */ +} /* ************************************************************************** ** * Add a mangled name into the cache. @@ -497,51 +517,49 @@ static void mangle_reset( void ) * ************************************************************************** ** */ static void cache_mangled_name( char *mangled_name, char *raw_name ) - { - ubi_cacheEntryPtr new_entry; - char *s1; - char *s2; - size_t mangled_len; - size_t raw_len; - size_t i; - - /* If the cache isn't initialized, give up. */ - if( !mc_initialized ) - return; - - /* Init the string lengths. */ - mangled_len = strlen( mangled_name ); - raw_len = strlen( raw_name ); - - /* See if the extensions are unmangled. If so, store the entry - * without the extension, thus creating a "group" reverse map. - */ - s1 = strrchr( mangled_name, '.' ); - if( s1 && (s2 = strrchr( raw_name, '.' )) ) - { - i = 1; - while( s1[i] && (tolower( s1[i] ) == s2[i]) ) - i++; - if( !s1[i] && !s2[i] ) - { - mangled_len -= i; - raw_len -= i; - } - } - - /* Allocate a new cache entry. If the allocation fails, just return. */ - i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2; - new_entry = malloc( i ); - if( !new_entry ) - return; - - /* Fill the new cache entry, and add it to the cache. */ - s1 = (char *)(new_entry + 1); - s2 = (char *)&(s1[mangled_len + 1]); - (void)StrnCpy( s1, mangled_name, mangled_len ); - (void)StrnCpy( s2, raw_name, raw_len ); - ubi_cachePut( mangled_cache, i, new_entry, s1 ); - } /* cache_mangled_name */ +{ + ubi_cacheEntryPtr new_entry; + char *s1; + char *s2; + size_t mangled_len; + size_t raw_len; + size_t i; + + /* If the cache isn't initialized, give up. */ + if( !mc_initialized ) + return; + + /* Init the string lengths. */ + mangled_len = strlen( mangled_name ); + raw_len = strlen( raw_name ); + + /* See if the extensions are unmangled. If so, store the entry + * without the extension, thus creating a "group" reverse map. + */ + s1 = strrchr( mangled_name, '.' ); + if( s1 && (s2 = strrchr( raw_name, '.' )) ) { + i = 1; + while( s1[i] && (tolower( s1[i] ) == s2[i]) ) + i++; + if( !s1[i] && !s2[i] ) { + mangled_len -= i; + raw_len -= i; + } + } + + /* Allocate a new cache entry. If the allocation fails, just return. */ + i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2; + new_entry = malloc( i ); + if( !new_entry ) + return; + + /* Fill the new cache entry, and add it to the cache. */ + s1 = (char *)(new_entry + 1); + s2 = (char *)&(s1[mangled_len + 1]); + (void)StrnCpy( s1, mangled_name, mangled_len ); + (void)StrnCpy( s2, raw_name, raw_len ); + ubi_cachePut( mangled_cache, i, new_entry, s1 ); +} /* ************************************************************************** ** * Check for a name on the mangled name stack @@ -560,63 +578,57 @@ static void cache_mangled_name( char *mangled_name, char *raw_name ) static BOOL check_cache( char *s ) { - ubi_cacheEntryPtr FoundPtr; - char *ext_start = NULL; - char *found_name; - char *saved_ext = NULL; - - /* If the cache isn't initialized, give up. */ - if( !mc_initialized ) - return( False ); - - FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s ); - - /* If we didn't find the name *with* the extension, try without. */ - if( !FoundPtr ) - { - ext_start = strrchr( s, '.' ); - if( ext_start ) - { - if((saved_ext = strdup(ext_start)) == NULL) - return False; - - *ext_start = '\0'; - FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s ); - /* - * At this point s is the name without the - * extension. We re-add the extension if saved_ext - * is not null, before freeing saved_ext. - */ - } - } - - /* Okay, if we haven't found it we're done. */ - if( !FoundPtr ) - { - if(saved_ext) - { - /* Replace the saved_ext as it was truncated. */ - (void)pstrcat( s, saved_ext ); - SAFE_FREE(saved_ext); - } - return( False ); - } - - /* If we *did* find it, we need to copy it into the string buffer. */ - found_name = (char *)(FoundPtr + 1); - found_name += (strlen( found_name ) + 1); - - (void)pstrcpy( s, found_name ); - if( saved_ext ) - { - /* Replace the saved_ext as it was truncated. */ - (void)pstrcat( s, saved_ext ); - SAFE_FREE(saved_ext); - } - - return( True ); -} /* check_mangled_cache */ + ubi_cacheEntryPtr FoundPtr; + char *ext_start = NULL; + char *found_name; + char *saved_ext = NULL; + + /* If the cache isn't initialized, give up. */ + if( !mc_initialized ) + return( False ); + + FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s ); + + /* If we didn't find the name *with* the extension, try without. */ + if( !FoundPtr ) { + ext_start = strrchr( s, '.' ); + if( ext_start ) { + if((saved_ext = strdup(ext_start)) == NULL) + return False; + + *ext_start = '\0'; + FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s ); + /* + * At this point s is the name without the + * extension. We re-add the extension if saved_ext + * is not null, before freeing saved_ext. + */ + } + } + + /* Okay, if we haven't found it we're done. */ + if( !FoundPtr ) { + if(saved_ext) { + /* Replace the saved_ext as it was truncated. */ + (void)pstrcat( s, saved_ext ); + SAFE_FREE(saved_ext); + } + return( False ); + } + + /* If we *did* find it, we need to copy it into the string buffer. */ + found_name = (char *)(FoundPtr + 1); + found_name += (strlen( found_name ) + 1); + + (void)pstrcpy( s, found_name ); + if( saved_ext ) { + /* Replace the saved_ext as it was truncated. */ + (void)pstrcat( s, saved_ext ); + SAFE_FREE(saved_ext); + } + return( True ); +} /***************************************************************************** * do the actual mangling to 8.3 format @@ -624,77 +636,67 @@ static BOOL check_cache( char *s ) ***************************************************************************** */ static void to_8_3(char *s) - { - int csum; - char *p; - char extension[4]; - char base[9]; - int baselen = 0; - int extlen = 0; - - extension[0] = 0; - base[0] = 0; - - p = strrchr(s,'.'); - if( p && (strlen(p+1) < (size_t)4) ) - { - BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */ - - if( all_normal && p[1] != 0 ) - { - *p = 0; - csum = str_checksum( s ); - *p = '.'; - } - else - csum = str_checksum(s); - } - else - csum = str_checksum(s); - - strupper( s ); - - if( p ) - { - if( p == s ) - safe_strcpy( extension, "___", 3 ); - else - { - *p++ = 0; - while( *p && extlen < 3 ) - { - if ( *p != '.') { - extension[extlen++] = p[0]; - } - p++; - } - extension[extlen] = 0; - } - } - - p = s; - - while( *p && baselen < 5 ) - { - if (*p != '.') { - base[baselen++] = p[0]; - } - p++; - } - base[baselen] = 0; +{ + int csum; + char *p; + char extension[4]; + char base[9]; + int baselen = 0; + int extlen = 0; + + extension[0] = 0; + base[0] = 0; + + p = strrchr(s,'.'); + if( p && (strlen(p+1) < (size_t)4) ) { + BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */ + + if( all_normal && p[1] != 0 ) { + *p = 0; + csum = str_checksum( s ); + *p = '.'; + } else + csum = str_checksum(s); + } else + csum = str_checksum(s); + + strupper( s ); + + if( p ) { + if( p == s ) + safe_strcpy( extension, "___", 3 ); + else { + *p++ = 0; + while( *p && extlen < 3 ) { + if ( *p != '.') { + extension[extlen++] = p[0]; + } + p++; + } + extension[extlen] = 0; + } + } - csum = csum % (MANGLE_BASE*MANGLE_BASE); + p = s; + + while( *p && baselen < 5 ) { + if (*p != '.') { + base[baselen++] = p[0]; + } + p++; + } + base[baselen] = 0; - (void)slprintf(s, 12, "%s%c%c%c", - base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) ); + csum = csum % (MANGLE_BASE*MANGLE_BASE); - if( *extension ) - { - (void)pstrcat( s, "." ); - (void)pstrcat( s, extension ); - } + (void)slprintf(s, 12, "%s%c%c%c", + base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) ); - } /* mangle_name_83 */ + if( *extension ) { + (void)pstrcat( s, "." ); + (void)pstrcat( s, extension ); + } +} /***************************************************************************** * Convert a filename to DOS format. Return True if successful. @@ -721,7 +723,8 @@ static void to_8_3(char *s) * * **************************************************************************** */ -static BOOL name_map(char *OutName, BOOL need83, BOOL cache83) + +static void name_map(char *OutName, BOOL need83, BOOL cache83) { smb_ucs2_t *OutName_ucs2; DEBUG(5,("name_map( %s, need83 = %s, cache83 = %s)\n", OutName, @@ -729,11 +732,14 @@ static BOOL name_map(char *OutName, BOOL need83, BOOL cache83) if (push_ucs2_allocate((void **)&OutName_ucs2, OutName) < 0) { DEBUG(0, ("push_ucs2_allocate failed!\n")); - return False; + return; } + if( !need83 && NT_STATUS_IS_ERR(is_valid_name(OutName_ucs2, False))) + need83 = True; + /* check if it's already in 8.3 format */ - if (need83 && !NT_STATUS_IS_OK(is_8_3_w(OutName_ucs2))) { + if (need83 && !NT_STATUS_IS_OK(is_8_3_w(OutName_ucs2, False))) { char *tmp = NULL; /* mangle it into 8.3 */ @@ -750,9 +756,7 @@ static BOOL name_map(char *OutName, BOOL need83, BOOL cache83) DEBUG(5,("name_map() ==> [%s]\n", OutName)); SAFE_FREE(OutName_ucs2); - return(True); -} /* name_map */ - +} /* the following provides the abstraction layer to make it easier diff --git a/source3/smbd/mangle_hash2.c b/source3/smbd/mangle_hash2.c index 959a93e07b1..e2c4b43bc37 100644 --- a/source3/smbd/mangle_hash2.c +++ b/source3/smbd/mangle_hash2.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. new hash based name mangling implementation Copyright (C) Andrew Tridgell 2002 + Copyright (C) Simo Sorce 2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,6 +31,10 @@ for simplicity, we only allow ascii characters in 8.3 names */ + /* hash alghorithm changed to FNV1 by idra@samba.org (Simo Sorce). + * see http://www.isthe.com/chongo/tech/comp/fnv/index.html for a + * discussion on Fowler / Noll / Vo (FNV) Hash by one of it's authors + */ /* =============================================================================== @@ -73,6 +78,10 @@ #define MANGLE_CACHE_SIZE 4096 #endif +#define FNV1_PRIME 0x01000193 +/*the following number is a fnv1 of the string: idra@samba.org 2002 */ +#define FNV1_INIT 0xa6b93095 + /* these tables are used to provide fast tests for characters */ static unsigned char char_flags[256]; @@ -88,13 +97,14 @@ static char **prefix_cache; static u32 *prefix_cache_hashes; /* these are the characters we use in the 8.3 hash. Must be 36 chars long */ -const char *basechars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static const char *basechars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static unsigned char base_reverse[256]; #define base_forward(v) basechars[v] /* the list of reserved dos names - all of these are illegal */ -const char *reserved_names[] = { "AUX", "LOCK$", "CON", "COM1", "COM2", "COM3", "COM4", - "LPT1", "LPT2", "LPT3", "NUL", "PRN", NULL }; +static const char *reserved_names[] = +{ "AUX", "LOCK$", "CON", "COM1", "COM2", "COM3", "COM4", + "LPT1", "LPT2", "LPT3", "NUL", "PRN", NULL }; /* hash a string of the specified length. The string does not need to be @@ -120,13 +130,14 @@ static u32 mangle_hash(const char *key, unsigned length) length = strlen(str); /* Set the initial value from the key size. */ - for (value = 0x238F13AF * length, i=0; i < length; i++) { - value = (value + (((unsigned char)str[i]) << (i*5 % 24))); - } + for (value = FNV1_INIT, i=0; i < length; i++) { + value *= (u32)FNV1_PRIME; + value ^= (u32)(str[i]); + } /* note that we force it to a 31 bit hash, to keep within the limits of the 36^6 mangle space */ - return (1103515243 * value + 12345) & ~0x80000000; + return value & ~0x80000000; } /* @@ -184,12 +195,12 @@ 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(const char *name) + */ +static BOOL is_mangled_component(const char *name) { int len, i; - M_DEBUG(0,("is_mangled %s ?\n", name)); + M_DEBUG(0,("is_mangled_component %s ?\n", name)); /* the best distinguishing characteristic is the ~ */ if (name[6] != '~') return False; @@ -229,6 +240,39 @@ static BOOL is_mangled(const char *name) } + +/* + determine if a string is possibly in a mangled format, ignoring + case + + In this algorithm, mangled names use only pure ascii characters (no + multi-byte) so we can avoid doing a UCS2 conversion + + NOTE! This interface must be able to handle a path with unix + directory separators. It should return true if any component is + mangled + */ +static BOOL is_mangled(const char *name) +{ + const char *p; + const char *s; + + M_DEBUG(0,("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); + return True; + } + free(component); + } + + /* and the last part ... */ + return is_mangled_component(s); +} + + /* see if a filename is an allowable 8.3 name. @@ -236,7 +280,7 @@ static BOOL is_mangled(const char *name) simplifies things greatly (it means that we know the string won't get larger when converted from UNIX to DOS formats) */ -static BOOL is_8_3(const char *name, BOOL check_case) +static BOOL is_8_3(const char *name, BOOL check_case, BOOL allow_wildcards) { int len, i; char *dot_p; @@ -286,8 +330,8 @@ static BOOL is_8_3(const char *name, BOOL check_case) /* the length are all OK. Now check to see if the characters themselves are OK */ for (i=0; name[i]; i++) { - /* note that we allow wildcard petterns! */ - if (!FLAG_CHECK(name[i], FLAG_ASCII|FLAG_WILDCARD) && name[i] != '.') { + /* note that we may allow wildcard petterns! */ + if (!FLAG_CHECK(name[i], FLAG_ASCII|(allow_wildcards ? FLAG_WILDCARD : 0)) && name[i] != '.') { return False; } } @@ -343,8 +387,12 @@ static BOOL check_cache(char *name) } /* we found it - construct the full name */ - strncpy(extension, name+9, 3); - extension[3] = 0; + if (name[8] == '.') { + strncpy(extension, name+9, 3); + extension[3] = 0; + } else { + extension[0] = 0; + } if (extension[0]) { M_DEBUG(0,("check_cache: %s -> %s.%s\n", name, prefix, extension)); @@ -383,17 +431,38 @@ static BOOL is_reserved_name(const char *name) } /* - see if a filename is a legal long filename + See if a filename is a legal long filename. + A filename ending in a '.' is not legal unless it's "." or "..". JRA. */ + static BOOL is_legal_name(const char *name) { + const char *dot_pos = NULL; + BOOL alldots = True; + size_t numdots = 0; + while (*name) { if (FLAG_CHECK(name[0], FLAG_ILLEGAL)) { return False; } + if (name[0] == '.') { + dot_pos = name; + numdots++; + } else { + alldots = False; + } name++; } + if (dot_pos) { + if (alldots && (numdots == 1 || numdots == 2)) + return True; /* . or .. is a valid name */ + + /* A valid long name cannot end in '.' */ + if (dot_pos[1] == '\0') + return False; + } + return True; } @@ -408,7 +477,7 @@ static BOOL is_legal_name(const char *name) the name parameter must be able to hold 13 bytes */ -static BOOL name_map(char *name, BOOL need83, BOOL cache83) +static void name_map(char *name, BOOL need83, BOOL cache83) { char *dot_p; char lead_char; @@ -422,14 +491,14 @@ static BOOL name_map(char *name, BOOL need83, BOOL cache83) if (!is_reserved_name(name)) { /* if the name is already a valid 8.3 name then we don't need to do anything */ - if (is_8_3(name, False)) { - return True; + if (is_8_3(name, False, False)) { + return; } /* if the caller doesn't strictly need 8.3 then just check for illegal filenames */ if (!need83 && is_legal_name(name)) { - return True; + return; } } @@ -511,7 +580,6 @@ static BOOL name_map(char *name, BOOL need83, BOOL cache83) fstrcpy(name, new_name); /* all done, we've managed to mangle it */ - return True; } diff --git a/source3/smbd/mangle_map.c b/source3/smbd/mangle_map.c index 71d93407181..553e3d949de 100644 --- a/source3/smbd/mangle_map.c +++ b/source3/smbd/mangle_map.c @@ -127,8 +127,8 @@ static char *map_filename( char *s, /* This is null terminated */ */ static void mangled_map(char *s, const char *MangledMap) { - char *start=MangledMap; /* Use this to search for mappings. */ - char *end; /* Used to find the end of strings. */ + const char *start=MangledMap; /* Use this to search for mappings. */ + const char *end; /* Used to find the end of strings. */ char *match_string; pstring new_string; /* Make up the result here. */ char *np; /* Points into new_string. */ diff --git a/source3/smbd/message.c b/source3/smbd/message.c index 971834c012c..ba646f12aa0 100644 --- a/source3/smbd/message.c +++ b/source3/smbd/message.c @@ -85,7 +85,7 @@ static void msg_deliver(void) pstrcpy(s,lp_msg_command()); pstring_sub(s,"%f",alpha_strcpy(alpha_msgfrom,msgfrom,NULL,sizeof(alpha_msgfrom))); pstring_sub(s,"%t",alpha_strcpy(alpha_msgto,msgto,NULL,sizeof(alpha_msgto))); - standard_sub_basic(current_user_info.smb_name, s); + standard_sub_basic(current_user_info.smb_name, s, sizeof(s)); pstring_sub(s,"%s",name); smbrun(s,NULL); } @@ -118,8 +118,8 @@ int reply_sends(connection_struct *conn, outsize = set_message(outbuf,0,0,True); p = smb_buf(inbuf)+1; - p += srvstr_pull(inbuf, msgfrom, p, sizeof(msgfrom), -1, STR_TERMINATE) + 1; - p += srvstr_pull(inbuf, msgto, p, sizeof(msgto), -1, STR_TERMINATE) + 1; + p += srvstr_pull_buf(inbuf, msgfrom, p, sizeof(msgfrom), STR_TERMINATE) + 1; + p += srvstr_pull_buf(inbuf, msgto, p, sizeof(msgto), STR_TERMINATE) + 1; msg = p; @@ -160,8 +160,8 @@ int reply_sendstrt(connection_struct *conn, msgpos = 0; p = smb_buf(inbuf)+1; - p += srvstr_pull(inbuf, msgfrom, p, sizeof(msgfrom), -1, STR_TERMINATE) + 1; - p += srvstr_pull(inbuf, msgto, p, sizeof(msgto), -1, STR_TERMINATE) + 1; + p += srvstr_pull_buf(inbuf, msgfrom, p, sizeof(msgfrom), STR_TERMINATE) + 1; + p += srvstr_pull_buf(inbuf, msgto, p, sizeof(msgto), STR_TERMINATE) + 1; DEBUG( 3, ( "SMBsendstrt (from %s to %s)\n", msgfrom, msgto ) ); diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index 18682e6c9ff..81c2427a003 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -50,8 +50,9 @@ static void get_challenge(char buff[8]) } /**************************************************************************** -reply for the core protocol + Reply for the core protocol. ****************************************************************************/ + static int reply_corep(char *inbuf, char *outbuf) { int outsize = set_message(outbuf,1,0,True); @@ -61,107 +62,110 @@ static int reply_corep(char *inbuf, char *outbuf) return outsize; } - /**************************************************************************** -reply for the coreplus protocol + Reply for the coreplus protocol. ****************************************************************************/ + static int reply_coreplus(char *inbuf, char *outbuf) { - int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); - int outsize = set_message(outbuf,13,0,True); - SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support - readbraw and writebraw (possibly) */ - /* Reply, SMBlockread, SMBwritelock supported. */ - SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); - SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */ + int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); + int outsize = set_message(outbuf,13,0,True); + SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support + readbraw and writebraw (possibly) */ + /* Reply, SMBlockread, SMBwritelock supported. */ + SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); + SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */ - Protocol = PROTOCOL_COREPLUS; + Protocol = PROTOCOL_COREPLUS; - return outsize; + return outsize; } - /**************************************************************************** -reply for the lanman 1.0 protocol + Reply for the lanman 1.0 protocol. ****************************************************************************/ + static int reply_lanman1(char *inbuf, char *outbuf) { - int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); - int secword=0; - time_t t = time(NULL); + int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); + int secword=0; + time_t t = time(NULL); - global_encrypted_passwords_negotiated = lp_encrypted_passwords(); + global_encrypted_passwords_negotiated = lp_encrypted_passwords(); - if (lp_security()>=SEC_USER) secword |= 1; - if (global_encrypted_passwords_negotiated) secword |= 2; + if (lp_security()>=SEC_USER) + secword |= NEGOTIATE_SECURITY_USER_LEVEL; + if (global_encrypted_passwords_negotiated) + secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; - set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True); - SSVAL(outbuf,smb_vwv1,secword); - /* Create a token value and add it to the outgoing packet. */ - if (global_encrypted_passwords_negotiated) { - get_challenge(smb_buf(outbuf)); - } + set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True); + SSVAL(outbuf,smb_vwv1,secword); + /* Create a token value and add it to the outgoing packet. */ + if (global_encrypted_passwords_negotiated) { + get_challenge(smb_buf(outbuf)); + } - Protocol = PROTOCOL_LANMAN1; + Protocol = PROTOCOL_LANMAN1; - /* Reply, SMBlockread, SMBwritelock supported. */ - SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); - SSVAL(outbuf,smb_vwv2,max_recv); - SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */ - SSVAL(outbuf,smb_vwv4,1); - SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support - readbraw writebraw (possibly) */ - SIVAL(outbuf,smb_vwv6,sys_getpid()); - SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60); + /* Reply, SMBlockread, SMBwritelock supported. */ + SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); + SSVAL(outbuf,smb_vwv2,max_recv); + SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */ + SSVAL(outbuf,smb_vwv4,1); + SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support + readbraw writebraw (possibly) */ + SIVAL(outbuf,smb_vwv6,sys_getpid()); + SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60); - put_dos_date(outbuf,smb_vwv8,t); + put_dos_date(outbuf,smb_vwv8,t); - return (smb_len(outbuf)+4); + return (smb_len(outbuf)+4); } - /**************************************************************************** -reply for the lanman 2.0 protocol + Reply for the lanman 2.0 protocol. ****************************************************************************/ + static int reply_lanman2(char *inbuf, char *outbuf) { - int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); - int secword=0; - time_t t = time(NULL); + int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); + int secword=0; + time_t t = time(NULL); - global_encrypted_passwords_negotiated = lp_encrypted_passwords(); + global_encrypted_passwords_negotiated = lp_encrypted_passwords(); - if (lp_security()>=SEC_USER) secword |= 1; - if (global_encrypted_passwords_negotiated) secword |= 2; - - set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True); - SSVAL(outbuf,smb_vwv1,secword); - SIVAL(outbuf,smb_vwv6,sys_getpid()); - - /* Create a token value and add it to the outgoing packet. */ - if (global_encrypted_passwords_negotiated) { - get_challenge(smb_buf(outbuf)); - } - - Protocol = PROTOCOL_LANMAN2; - - /* Reply, SMBlockread, SMBwritelock supported. */ - SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); - SSVAL(outbuf,smb_vwv2,max_recv); - SSVAL(outbuf,smb_vwv3,lp_maxmux()); - SSVAL(outbuf,smb_vwv4,1); - SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */ - SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60); - put_dos_date(outbuf,smb_vwv8,t); - - return (smb_len(outbuf)+4); -} + if (lp_security()>=SEC_USER) + secword |= NEGOTIATE_SECURITY_USER_LEVEL; + if (global_encrypted_passwords_negotiated) + secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; + set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True); + SSVAL(outbuf,smb_vwv1,secword); + SIVAL(outbuf,smb_vwv6,sys_getpid()); + /* Create a token value and add it to the outgoing packet. */ + if (global_encrypted_passwords_negotiated) { + get_challenge(smb_buf(outbuf)); + } + + Protocol = PROTOCOL_LANMAN2; + + /* Reply, SMBlockread, SMBwritelock supported. */ + SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); + SSVAL(outbuf,smb_vwv2,max_recv); + SSVAL(outbuf,smb_vwv3,lp_maxmux()); + SSVAL(outbuf,smb_vwv4,1); + SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */ + SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60); + put_dos_date(outbuf,smb_vwv8,t); + + return (smb_len(outbuf)+4); +} + +/**************************************************************************** + Generate the spnego negprot reply blob. Return the number of bytes used. +****************************************************************************/ -/* - generate the spnego negprot reply blob. Return the number of bytes used -*/ static int negprot_spnego(char *p) { DATA_BLOB blob; @@ -197,7 +201,7 @@ static int negprot_spnego(char *p) blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE"); } else { ADS_STRUCT *ads; - ads = ads_init(NULL, NULL, NULL, NULL); + ads = ads_init_simple(); /* win2000 uses host$@REALM, which we will probably use eventually, but for now this works */ asprintf(&principal, "HOST/%s@%s", guid, ads->realm); @@ -211,11 +215,10 @@ static int negprot_spnego(char *p) return len; } - - /**************************************************************************** -reply for the nt protocol + Reply for the nt protocol. ****************************************************************************/ + static int reply_nt1(char *inbuf, char *outbuf) { /* dual names + lock_and_read + nt SMBs + remote API calls */ @@ -262,9 +265,9 @@ static int reply_nt1(char *inbuf, char *outbuf) capabilities |= CAP_DFS; if (lp_security() >= SEC_USER) - secword |= 1; + secword |= NEGOTIATE_SECURITY_USER_LEVEL; if (global_encrypted_passwords_negotiated) - secword |= 2; + secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; set_message(outbuf,17,0,True); @@ -377,133 +380,128 @@ protocol [LANMAN2.1] /* List of supported protocols, most desired first */ static struct { - char *proto_name; - char *short_name; - int (*proto_reply_fn)(char *, char *); - int protocol_level; + char *proto_name; + char *short_name; + int (*proto_reply_fn)(char *, char *); + int protocol_level; } supported_protocols[] = { - {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1}, - {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1}, - {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, - {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, - {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, - {"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1}, - {"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1}, - {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS}, - {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE}, - {NULL,NULL,NULL,0}, + {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1}, + {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1}, + {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, + {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, + {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, + {"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1}, + {"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1}, + {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS}, + {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE}, + {NULL,NULL,NULL,0}, }; - /**************************************************************************** - reply to a negprot + Reply to a negprot. ****************************************************************************/ + int reply_negprot(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - int outsize = set_message(outbuf,1,0,True); - int Index=0; - int choice= -1; - int protocol; - char *p; - int bcc = SVAL(smb_buf(inbuf),-2); - int arch = ARCH_ALL; - START_PROFILE(SMBnegprot); - - p = smb_buf(inbuf)+1; - while (p < (smb_buf(inbuf) + bcc)) - { - Index++; - DEBUG(3,("Requested protocol [%s]\n",p)); - if (strcsequal(p,"Windows for Workgroups 3.1a")) - arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K ); - else if (strcsequal(p,"DOS LM1.2X002")) - arch &= ( ARCH_WFWG | ARCH_WIN95 ); - else if (strcsequal(p,"DOS LANMAN2.1")) - arch &= ( ARCH_WFWG | ARCH_WIN95 ); - else if (strcsequal(p,"NT LM 0.12")) - arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K ); - else if (strcsequal(p,"LANMAN2.1")) - arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); - else if (strcsequal(p,"LM1.2X002")) - arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); - else if (strcsequal(p,"MICROSOFT NETWORKS 1.03")) - arch &= ARCH_WINNT; - else if (strcsequal(p,"XENIX CORE")) - arch &= ( ARCH_WINNT | ARCH_OS2 ); - else if (strcsequal(p,"Samba")) { - arch = ARCH_SAMBA; - break; - } + int outsize = set_message(outbuf,1,0,True); + int Index=0; + int choice= -1; + int protocol; + char *p; + int bcc = SVAL(smb_buf(inbuf),-2); + int arch = ARCH_ALL; + START_PROFILE(SMBnegprot); + + p = smb_buf(inbuf)+1; + while (p < (smb_buf(inbuf) + bcc)) { + Index++; + DEBUG(3,("Requested protocol [%s]\n",p)); + if (strcsequal(p,"Windows for Workgroups 3.1a")) + arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K ); + else if (strcsequal(p,"DOS LM1.2X002")) + arch &= ( ARCH_WFWG | ARCH_WIN95 ); + else if (strcsequal(p,"DOS LANMAN2.1")) + arch &= ( ARCH_WFWG | ARCH_WIN95 ); + else if (strcsequal(p,"NT LM 0.12")) + arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K ); + else if (strcsequal(p,"LANMAN2.1")) + arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); + else if (strcsequal(p,"LM1.2X002")) + arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); + else if (strcsequal(p,"MICROSOFT NETWORKS 1.03")) + arch &= ARCH_WINNT; + else if (strcsequal(p,"XENIX CORE")) + arch &= ( ARCH_WINNT | ARCH_OS2 ); + else if (strcsequal(p,"Samba")) { + arch = ARCH_SAMBA; + break; + } - p += strlen(p) + 2; - } + p += strlen(p) + 2; + } - switch ( arch ) { - case ARCH_SAMBA: - set_remote_arch(RA_SAMBA); - break; - case ARCH_WFWG: - set_remote_arch(RA_WFWG); - break; - case ARCH_WIN95: - set_remote_arch(RA_WIN95); - break; - case ARCH_WINNT: - if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE) - set_remote_arch(RA_WIN2K); - else - set_remote_arch(RA_WINNT); - break; - case ARCH_WIN2K: - set_remote_arch(RA_WIN2K); - break; - case ARCH_OS2: - set_remote_arch(RA_OS2); - break; - default: - set_remote_arch(RA_UNKNOWN); - break; - } + switch ( arch ) { + case ARCH_SAMBA: + set_remote_arch(RA_SAMBA); + break; + case ARCH_WFWG: + set_remote_arch(RA_WFWG); + break; + case ARCH_WIN95: + set_remote_arch(RA_WIN95); + break; + case ARCH_WINNT: + if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE) + set_remote_arch(RA_WIN2K); + else + set_remote_arch(RA_WINNT); + break; + case ARCH_WIN2K: + set_remote_arch(RA_WIN2K); + break; + case ARCH_OS2: + set_remote_arch(RA_OS2); + break; + default: + set_remote_arch(RA_UNKNOWN); + break; + } - /* possibly reload - change of architecture */ - reload_services(True); + /* possibly reload - change of architecture */ + reload_services(True); - /* Check for protocols, most desirable first */ - for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) - { - p = smb_buf(inbuf)+1; - Index = 0; - if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) && - (supported_protocols[protocol].protocol_level >= lp_minprotocol())) - while (p < (smb_buf(inbuf) + bcc)) - { - if (strequal(p,supported_protocols[protocol].proto_name)) - choice = Index; - Index++; - p += strlen(p) + 2; - } - if(choice != -1) - break; - } + /* Check for protocols, most desirable first */ + for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) { + p = smb_buf(inbuf)+1; + Index = 0; + if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) && + (supported_protocols[protocol].protocol_level >= lp_minprotocol())) + while (p < (smb_buf(inbuf) + bcc)) { + if (strequal(p,supported_protocols[protocol].proto_name)) + choice = Index; + Index++; + p += strlen(p) + 2; + } + if(choice != -1) + break; + } - SSVAL(outbuf,smb_vwv0,choice); - if(choice != -1) { - extern fstring remote_proto; - fstrcpy(remote_proto,supported_protocols[protocol].short_name); - reload_services(True); - outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf); - DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name)); - } - else { - DEBUG(0,("No protocol supported !\n")); - } - SSVAL(outbuf,smb_vwv0,choice); + SSVAL(outbuf,smb_vwv0,choice); + if(choice != -1) { + extern fstring remote_proto; + fstrcpy(remote_proto,supported_protocols[protocol].short_name); + reload_services(True); + outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf); + DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name)); + } else { + DEBUG(0,("No protocol supported !\n")); + } + SSVAL(outbuf,smb_vwv0,choice); - DEBUG( 5, ( "negprot index=%d\n", choice ) ); + DEBUG( 5, ( "negprot index=%d\n", choice ) ); - END_PROFILE(SMBnegprot); - return(outsize); + END_PROFILE(SMBnegprot); + return(outsize); } - diff --git a/source3/smbd/notify_kernel.c b/source3/smbd/notify_kernel.c index 19ea41e1956..8454917163a 100644 --- a/source3/smbd/notify_kernel.c +++ b/source3/smbd/notify_kernel.c @@ -1,5 +1,6 @@ /* - Unix SMB/CIFS implementation. + Unix SMB/Netbios implementation. + Version 3.0 change notify handling - linux kernel based implementation Copyright (C) Andrew Tridgell 2000 @@ -22,9 +23,9 @@ #if HAVE_KERNEL_CHANGE_NOTIFY -static VOLATILE sig_atomic_t fd_pending; -static VOLATILE sig_atomic_t signals_received; -static VOLATILE sig_atomic_t signals_processed; +#define FD_PENDING_SIZE 20 +static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE]; +static SIG_ATOMIC_T signals_received; #ifndef DN_ACCESS #define DN_ACCESS 0x00000001 /* File accessed in directory */ @@ -53,84 +54,114 @@ static VOLATILE sig_atomic_t signals_processed; This is the structure to keep the information needed to determine if a directory has changed. *****************************************************************************/ + struct change_data { int directory_handle; }; /**************************************************************************** -the signal handler for change notify + The signal handler for change notify. + The Linux kernel has a bug in that we should be able to block any + further delivery of RT signals until the kernel_check_notify() function + unblocks them, but it seems that any signal mask we're setting here is + being overwritten on exit from this handler. I should create a standalone + test case for the kernel hackers. JRA. *****************************************************************************/ + static void signal_handler(int sig, siginfo_t *info, void *unused) { - BlockSignals(True, sig); - fd_pending = (sig_atomic_t)info->si_fd; - signals_received++; + if (signals_received < FD_PENDING_SIZE - 1) { + fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd; + signals_received++; + } /* Else signal is lost. */ sys_select_signal(); } - - /**************************************************************************** Check if a change notify should be issued. time non-zero means timeout check (used for hash). Ignore this (async method where time is zero will be used instead). *****************************************************************************/ + static BOOL kernel_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t) { struct change_data *data = (struct change_data *)datap; + int i; + BOOL ret = False; if (t) return False; - if (data->directory_handle != (int)fd_pending) return False; - - DEBUG(3,("kernel change notify on %s fd=%d\n", path, (int)fd_pending)); - - close((int)fd_pending); - fd_pending = (sig_atomic_t)-1; - data->directory_handle = -1; - signals_processed++; + BlockSignals(True, RT_SIGNAL_NOTIFY); + for (i = 0; i < signals_received; i++) { + if (data->directory_handle == (int)fd_pending_array[i]) { + DEBUG(3,("kernel_check_notify: kernel change notify on %s fd[%d]=%d (signals_received=%d)\n", + path, i, (int)fd_pending_array[i], (int)signals_received )); + + close((int)fd_pending_array[i]); + fd_pending_array[i] = (SIG_ATOMIC_T)-1; + if (signals_received - i - 1) { + memmove((void *)&fd_pending_array[i], (void *)&fd_pending_array[i+1], + sizeof(SIG_ATOMIC_T)*(signals_received-i-1)); + } + data->directory_handle = -1; + signals_received--; + ret = True; + break; + } + } BlockSignals(False, RT_SIGNAL_NOTIFY); - return True; + return ret; } /**************************************************************************** -remove a change notify data structure + Remove a change notify data structure. *****************************************************************************/ + static void kernel_remove_notify(void *datap) { struct change_data *data = (struct change_data *)datap; int fd = data->directory_handle; if (fd != -1) { - if (fd == (int)fd_pending) { - fd_pending = (sig_atomic_t)-1; - signals_processed++; - BlockSignals(False, RT_SIGNAL_NOTIFY); + int i; + BlockSignals(True, RT_SIGNAL_NOTIFY); + for (i = 0; i < signals_received; i++) { + if (fd == (int)fd_pending_array[i]) { + close(fd); + fd_pending_array[i] = (SIG_ATOMIC_T)-1; + if (signals_received - i - 1) { + memmove((void *)&fd_pending_array[i], (void *)&fd_pending_array[i+1], + sizeof(SIG_ATOMIC_T)*(signals_received-i-1)); + } + data->directory_handle = -1; + signals_received--; + break; + } } - close(fd); + BlockSignals(False, RT_SIGNAL_NOTIFY); } SAFE_FREE(data); - DEBUG(3,("removed kernel change notify fd=%d\n", fd)); + DEBUG(3,("kernel_remove_notify: fd=%d\n", fd)); } - /**************************************************************************** -register a change notify request + Register a change notify request. *****************************************************************************/ + static void *kernel_register_notify(connection_struct *conn, char *path, uint32 flags) { struct change_data data; int fd; unsigned long kernel_flags; - fd = conn->vfs_ops.open(conn, path, O_RDONLY, 0); + fd = sys_open(path,O_RDONLY, 0); if (fd == -1) { DEBUG(3,("Failed to open directory %s for change notify\n", path)); return NULL; } - if (fcntl(fd, F_SETSIG, RT_SIGNAL_NOTIFY) == -1) { + if (sys_fcntl_long(fd, F_SETSIG, RT_SIGNAL_NOTIFY) == -1) { DEBUG(3,("Failed to set signal handler for change notify\n")); return NULL; } @@ -147,7 +178,7 @@ static void *kernel_register_notify(connection_struct *conn, char *path, uint32 if (flags & FILE_NOTIFY_CHANGE_EA) kernel_flags |= DN_ATTRIB; if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_RENAME|DN_DELETE; - if (fcntl(fd, F_NOTIFY, kernel_flags) == -1) { + if (sys_fcntl_long(fd, F_NOTIFY, kernel_flags) == -1) { DEBUG(3,("Failed to set async flag for change notify\n")); return NULL; } @@ -161,22 +192,24 @@ static void *kernel_register_notify(connection_struct *conn, char *path, uint32 } /**************************************************************************** -see if the kernel supports change notify + See if the kernel supports change notify. ****************************************************************************/ + static BOOL kernel_notify_available(void) { int fd, ret; fd = open("/tmp", O_RDONLY); - if (fd == -1) return False; /* uggh! */ - ret = fcntl(fd, F_NOTIFY, 0); + if (fd == -1) + return False; /* uggh! */ + ret = sys_fcntl_long(fd, F_NOTIFY, 0); close(fd); return ret == 0; } - /**************************************************************************** -setup kernel based change notify + Setup kernel based change notify. ****************************************************************************/ + struct cnotify_fns *kernel_notify_init(void) { static struct cnotify_fns cnotify; @@ -190,7 +223,8 @@ struct cnotify_fns *kernel_notify_init(void) return NULL; } - if (!kernel_notify_available()) return NULL; + if (!kernel_notify_available()) + return NULL; cnotify.register_notify = kernel_register_notify; cnotify.check_notify = kernel_check_notify; @@ -200,7 +234,6 @@ struct cnotify_fns *kernel_notify_init(void) return &cnotify; } - #else void notify_kernel_dummy(void) {} #endif /* HAVE_KERNEL_CHANGE_NOTIFY */ diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index edee14513c8..e0a0da7a75b 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -454,6 +454,7 @@ to open_mode 0x%x\n", (unsigned long)*desired_access, (unsigned long)share_acces /**************************************************************************** Reply to an NT create and X call on a pipe. ****************************************************************************/ + static int nt_open_pipe(char *fname, connection_struct *conn, char *inbuf, char *outbuf, int *ppnum) { @@ -502,7 +503,7 @@ static int do_ntcreate_pipe_open(connection_struct *conn, int pnum = -1; char *p = NULL; - srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE); if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) return ret; @@ -605,12 +606,13 @@ int reply_ntcreate_and_X(connection_struct *conn, } if(!dir_fsp->is_directory) { + + srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE); + /* * Check to see if this is a mac fork of some kind. */ - srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE); - if( strchr_m(fname, ':')) { END_PROFILE(SMBntcreateX); return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); @@ -635,10 +637,18 @@ int reply_ntcreate_and_X(connection_struct *conn, dir_name_len++; } - srvstr_pull(inbuf, &fname[dir_name_len], smb_buf(inbuf), sizeof(fname)-dir_name_len, - -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, &fname[dir_name_len], smb_buf(inbuf), sizeof(fname)-dir_name_len, STR_TERMINATE); } else { - srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE); + + /* + * Check to see if this is a mac fork of some kind. + */ + + if( strchr_m(fname, ':')) { + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } } /* @@ -880,29 +890,29 @@ static int do_nt_transact_create_pipe( connection_struct *conn, return ERROR_DOS(ERRDOS,ERRbadaccess); } - srvstr_pull(inbuf, fname, params+53, sizeof(fname), -1, STR_TERMINATE); - - if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) - return ret; + srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE); + if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) + return ret; + /* Realloc the size of parameters and data we will return */ params = Realloc(*ppparams, 69); if(params == NULL) return ERROR_DOS(ERRDOS,ERRnomem); - + *ppparams = params; - + memset((char *)params,'\0',69); - + p = params; SCVAL(p,0,NO_OPLOCK_RETURN); - + p += 2; SSVAL(p,0,pnum); p += 2; SIVAL(p,0,FILE_WAS_OPENED); p += 8; - + p += 32; SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */ p += 20; @@ -910,12 +920,12 @@ static int do_nt_transact_create_pipe( connection_struct *conn, SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE); /* Device state. */ SSVAL(p,2, 0x5FF); /* ? */ - + DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname)); - + /* Send the required number of replies */ send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0); - + return -1; } @@ -923,17 +933,15 @@ static int do_nt_transact_create_pipe( connection_struct *conn, Internal fn to set security descriptors. ****************************************************************************/ -static BOOL set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security_info_sent, int *pdef_class,uint32 *pdef_code) +static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security_info_sent) { prs_struct pd; SEC_DESC *psd = NULL; TALLOC_CTX *mem_ctx; BOOL ret; - + if (sd_len == 0) { - *pdef_class = ERRDOS; - *pdef_code = ERRbadaccess; - return False; + return NT_STATUS_OK; } /* @@ -942,9 +950,7 @@ static BOOL set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security if ((mem_ctx = talloc_init()) == NULL) { DEBUG(0,("set_sd: talloc_init failed.\n")); - *pdef_class = ERRDOS; - *pdef_code = ERRnomem; - return False; + return NT_STATUS_NO_MEMORY; } prs_init(&pd, 0, mem_ctx, UNMARSHALL); @@ -966,11 +972,9 @@ static BOOL set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security * Return access denied for want of a better error message.. */ talloc_destroy(mem_ctx); - *pdef_class = ERRDOS; - *pdef_code = ERRnomem; - return False; + return NT_STATUS_NO_MEMORY; } - + if (psd->off_owner_sid==0) security_info_sent &= ~OWNER_SECURITY_INFORMATION; if (psd->off_grp_sid==0) @@ -981,19 +985,15 @@ static BOOL set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security security_info_sent &= ~DACL_SECURITY_INFORMATION; ret = fsp->conn->vfs_ops.fset_nt_acl( fsp, fsp->fd, security_info_sent, psd); - + if (!ret) { talloc_destroy(mem_ctx); - *pdef_class = ERRDOS; - *pdef_code = ERRnoaccess; - return False; + return NT_STATUS_ACCESS_DENIED; } - + talloc_destroy(mem_ctx); - - *pdef_class = 0; - *pdef_code = 0; - return True; + + return NT_STATUS_OK; } /**************************************************************************** @@ -1005,304 +1005,307 @@ static int call_nt_transact_create(connection_struct *conn, int bufsize, char **ppsetup, char **ppparams, char **ppdata) { - pstring fname; - char *params = *ppparams; - char *data = *ppdata; - int total_parameter_count = (int)IVAL(inbuf, smb_nt_TotalParameterCount); - /* Breakout the oplock request bits so we can set the - reply bits separately. */ - int oplock_request = 0; - mode_t unixmode; - int fmode=0,rmode=0; - SMB_OFF_T file_len = 0; - SMB_STRUCT_STAT sbuf; - int smb_action = 0; - BOOL bad_path = False; - files_struct *fsp = NULL; - char *p = NULL; - uint32 flags; - uint32 desired_access; - uint32 file_attributes; - uint32 share_access; - uint32 create_disposition; - uint32 create_options; - uint32 sd_len; - uint16 root_dir_fid; - int smb_ofun; - int smb_open_mode; - int smb_attr; - int error_class; - uint32 error_code; - time_t c_time; - - DEBUG(5,("call_nt_transact_create\n")); + pstring fname; + char *params = *ppparams; + char *data = *ppdata; + int total_parameter_count = (int)IVAL(inbuf, smb_nt_TotalParameterCount); + /* Breakout the oplock request bits so we can set the reply bits separately. */ + int oplock_request = 0; + mode_t unixmode; + int fmode=0,rmode=0; + SMB_OFF_T file_len = 0; + SMB_STRUCT_STAT sbuf; + int smb_action = 0; + BOOL bad_path = False; + files_struct *fsp = NULL; + char *p = NULL; + uint32 flags; + uint32 desired_access; + uint32 file_attributes; + uint32 share_access; + uint32 create_disposition; + uint32 create_options; + uint32 sd_len; + uint16 root_dir_fid; + int smb_ofun; + int smb_open_mode; + int smb_attr; + time_t c_time; + NTSTATUS nt_status; - /* - * If it's an IPC, use the pipe handler. - */ + DEBUG(5,("call_nt_transact_create\n")); + + /* + * If it's an IPC, use the pipe handler. + */ - if (IS_IPC(conn)) { + if (IS_IPC(conn)) { if (lp_nt_pipe_support()) return do_nt_transact_create_pipe(conn, inbuf, outbuf, length, bufsize, ppsetup, ppparams, ppdata); else return ERROR_DOS(ERRDOS,ERRbadaccess); - } + } - /* - * Ensure minimum number of parameters sent. - */ + /* + * Ensure minimum number of parameters sent. + */ - if(total_parameter_count < 54) { - DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)total_parameter_count)); - return ERROR_DOS(ERRDOS,ERRbadaccess); - } + if(total_parameter_count < 54) { + DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)total_parameter_count)); + return ERROR_DOS(ERRDOS,ERRbadaccess); + } - flags = IVAL(params,0); - desired_access = IVAL(params,8); - file_attributes = IVAL(params,20); - share_access = IVAL(params,24); - create_disposition = IVAL(params,28); - create_options = IVAL(params,32); - sd_len = IVAL(params,36); - root_dir_fid = (uint16)IVAL(params,4); - smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK); + flags = IVAL(params,0); + desired_access = IVAL(params,8); + file_attributes = IVAL(params,20); + share_access = IVAL(params,24); + create_disposition = IVAL(params,28); + create_options = IVAL(params,32); + sd_len = IVAL(params,36); + root_dir_fid = (uint16)IVAL(params,4); + smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK); - /* - * We need to construct the open_and_X ofun value from the - * NT values, as that's what our code is structured to accept. - */ + /* + * We need to construct the open_and_X ofun value from the + * NT values, as that's what our code is structured to accept. + */ - if((smb_ofun = map_create_disposition( create_disposition )) == -1) - return ERROR_DOS(ERRDOS,ERRbadmem); + if((smb_ofun = map_create_disposition( create_disposition )) == -1) + return ERROR_DOS(ERRDOS,ERRbadmem); - /* - * Get the file name. - */ + /* + * Get the file name. + */ - if(root_dir_fid != 0) { - /* - * This filename is relative to a directory fid. - */ + if(root_dir_fid != 0) { + /* + * This filename is relative to a directory fid. + */ - files_struct *dir_fsp = file_fsp(params,4); - size_t dir_name_len; + files_struct *dir_fsp = file_fsp(params,4); + size_t dir_name_len; - if(!dir_fsp) - return ERROR_DOS(ERRDOS,ERRbadfid); + if(!dir_fsp) + return ERROR_DOS(ERRDOS,ERRbadfid); - if(!dir_fsp->is_directory) { - /* - * Check to see if this is a mac fork of some kind. - */ + if(!dir_fsp->is_directory) { - srvstr_pull(inbuf, fname, params+53, sizeof(fname), -1, STR_TERMINATE); + srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE); - if( strchr_m(fname, ':')) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - } + /* + * Check to see if this is a mac fork of some kind. + */ - return ERROR_DOS(ERRDOS,ERRbadfid); - } + if( strchr_m(fname, ':')) + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - /* - * Copy in the base directory name. - */ + return ERROR_DOS(ERRDOS,ERRbadfid); + } - pstrcpy( fname, dir_fsp->fsp_name ); - dir_name_len = strlen(fname); + /* + * Copy in the base directory name. + */ - /* - * Ensure it ends in a '\'. - */ + pstrcpy( fname, dir_fsp->fsp_name ); + dir_name_len = strlen(fname); - if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) { - pstrcat(fname, "\\"); - dir_name_len++; - } + /* + * Ensure it ends in a '\'. + */ - srvstr_pull(inbuf, &fname[dir_name_len], params+53, sizeof(fname)-dir_name_len, - -1, STR_TERMINATE); - } else { - srvstr_pull(inbuf, fname, params+53, sizeof(fname), -1, STR_TERMINATE); - } + if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) { + pstrcat(fname, "\\"); + dir_name_len++; + } - /* - * Now contruct the smb_open_mode value from the desired access - * and the share access. - */ + srvstr_pull(inbuf, &fname[dir_name_len], params+53, sizeof(fname)-dir_name_len, + total_parameter_count-53, STR_TERMINATE); + } else { + srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE); + + /* + * Check to see if this is a mac fork of some kind. + */ - if((smb_open_mode = map_share_mode( fname, create_options, &desired_access, - share_access, file_attributes)) == -1) - return ERROR_DOS(ERRDOS,ERRbadaccess); + if( strchr_m(fname, ':')) + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } - oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; - oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; + /* + * Now contruct the smb_open_mode value from the desired access + * and the share access. + */ - /* - * Check if POSIX semantics are wanted. - */ + if((smb_open_mode = map_share_mode( fname, create_options, &desired_access, + share_access, file_attributes)) == -1) + return ERROR_DOS(ERRDOS,ERRbadaccess); - set_posix_case_semantics(file_attributes); + oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; + oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; + + /* + * Check if POSIX semantics are wanted. + */ + + set_posix_case_semantics(file_attributes); - RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); + RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); + unix_convert(fname,conn,0,&bad_path,&sbuf); - unixmode = unix_mode(conn,smb_attr | aARCH, fname); + unixmode = unix_mode(conn,smb_attr | aARCH, fname); - /* - * If it's a request for a directory open, deal with it separately. - */ + /* + * If it's a request for a directory open, deal with it separately. + */ - if(create_options & FILE_DIRECTORY_FILE) { + if(create_options & FILE_DIRECTORY_FILE) { - oplock_request = 0; + oplock_request = 0; - /* - * We will get a create directory here if the Win32 - * app specified a security descriptor in the - * CreateDirectory() call. - */ + /* + * We will get a create directory here if the Win32 + * app specified a security descriptor in the + * CreateDirectory() call. + */ - fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action); + fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action); - if(!fsp) { - restore_case_semantics(file_attributes); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + if(!fsp) { + restore_case_semantics(file_attributes); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - } else { + } else { - /* - * Ordinary file case. - */ + /* + * Ordinary file case. + */ - fsp = open_file_shared1(conn,fname,&sbuf,desired_access, - smb_open_mode,smb_ofun,unixmode, - oplock_request,&rmode,&smb_action); + fsp = open_file_shared1(conn,fname,&sbuf,desired_access, + smb_open_mode,smb_ofun,unixmode, + oplock_request,&rmode,&smb_action); - if (!fsp) { + if (!fsp) { - if(errno == EISDIR) { + if(errno == EISDIR) { - /* - * Fail the open if it was explicitly a non-directory file. - */ + /* + * Fail the open if it was explicitly a non-directory file. + */ - if (create_options & FILE_NON_DIRECTORY_FILE) { - restore_case_semantics(file_attributes); - SSVAL(outbuf, smb_flg2, - SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES); - return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY); - } + if (create_options & FILE_NON_DIRECTORY_FILE) { + restore_case_semantics(file_attributes); + SSVAL(outbuf, smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES); + return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY); + } - oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action); + oplock_request = 0; + fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action); - if(!fsp) { + if(!fsp) { + restore_case_semantics(file_attributes); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + } else { restore_case_semantics(file_attributes); set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRnoaccess)); } - } else { - - restore_case_semantics(file_attributes); - set_bad_path_error(errno, bad_path); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - } + } - file_len = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - if(fmode == 0) - fmode = FILE_ATTRIBUTE_NORMAL; + file_len = sbuf.st_size; + fmode = dos_mode(conn,fname,&sbuf); + if(fmode == 0) + fmode = FILE_ATTRIBUTE_NORMAL; - if (fmode & aDIR) { - close_file(fsp,False); - restore_case_semantics(file_attributes); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } + if (fmode & aDIR) { + close_file(fsp,False); + restore_case_semantics(file_attributes); + return ERROR_DOS(ERRDOS,ERRnoaccess); + } - /* - * If the caller set the extended oplock request bit - * and we granted one (by whatever means) - set the - * correct bit for extended oplock reply. - */ + /* + * If the caller set the extended oplock request bit + * and we granted one (by whatever means) - set the + * correct bit for extended oplock reply. + */ - if (oplock_request && lp_fake_oplocks(SNUM(conn))) - smb_action |= EXTENDED_OPLOCK_GRANTED; + if (oplock_request && lp_fake_oplocks(SNUM(conn))) + smb_action |= EXTENDED_OPLOCK_GRANTED; - if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) - smb_action |= EXTENDED_OPLOCK_GRANTED; - } - - /* - * Now try and apply the desired SD. - */ + if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) + smb_action |= EXTENDED_OPLOCK_GRANTED; + } - if (!set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION, &error_class, &error_code)) { - close_file(fsp,False); - restore_case_semantics(file_attributes); - return ERROR_DOS(error_class, error_code); - } + /* + * Now try and apply the desired SD. + */ - restore_case_semantics(file_attributes); + if (sd_len && !NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION))) { + close_file(fsp,False); + restore_case_semantics(file_attributes); + return ERROR_NT(nt_status); + } + + restore_case_semantics(file_attributes); - /* Realloc the size of parameters and data we will return */ - params = Realloc(*ppparams, 69); - if(params == NULL) - return ERROR_DOS(ERRDOS,ERRnomem); + /* Realloc the size of parameters and data we will return */ + params = Realloc(*ppparams, 69); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); - *ppparams = params; + *ppparams = params; - memset((char *)params,'\0',69); + memset((char *)params,'\0',69); - p = params; - if (smb_action & EXTENDED_OPLOCK_GRANTED) - SCVAL(p,0, BATCH_OPLOCK_RETURN); - else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) - SCVAL(p,0, LEVEL_II_OPLOCK_RETURN); - else - SCVAL(p,0,NO_OPLOCK_RETURN); + p = params; + if (smb_action & EXTENDED_OPLOCK_GRANTED) + SCVAL(p,0, BATCH_OPLOCK_RETURN); + else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) + SCVAL(p,0, LEVEL_II_OPLOCK_RETURN); + else + SCVAL(p,0,NO_OPLOCK_RETURN); - p += 2; - SSVAL(p,0,fsp->fnum); - p += 2; - SIVAL(p,0,smb_action); - p += 8; - - /* Create time. */ - c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); - - if (lp_dos_filetime_resolution(SNUM(conn))) { - c_time &= ~1; - sbuf.st_atime &= ~1; - sbuf.st_mtime &= ~1; - sbuf.st_mtime &= ~1; - } + p += 2; + SSVAL(p,0,fsp->fnum); + p += 2; + SIVAL(p,0,smb_action); + p += 8; - put_long_date(p,c_time); - p += 8; - put_long_date(p,sbuf.st_atime); /* access time */ - p += 8; - put_long_date(p,sbuf.st_mtime); /* write time */ - p += 8; - put_long_date(p,sbuf.st_mtime); /* change time */ - p += 8; - SIVAL(p,0,fmode); /* File Attributes. */ - p += 4; - SOFF_T(p, 0, SMB_ROUNDUP_ALLOCATION(file_len)); - p += 8; - SOFF_T(p,0,file_len); - - DEBUG(5,("call_nt_transact_create: open name = %s\n", fname)); - - /* Send the required number of replies */ - send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0); + /* Create time. */ + c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); - return -1; + if (lp_dos_filetime_resolution(SNUM(conn))) { + c_time &= ~1; + sbuf.st_atime &= ~1; + sbuf.st_mtime &= ~1; + sbuf.st_mtime &= ~1; + } + + put_long_date(p,c_time); + p += 8; + put_long_date(p,sbuf.st_atime); /* access time */ + p += 8; + put_long_date(p,sbuf.st_mtime); /* write time */ + p += 8; + put_long_date(p,sbuf.st_mtime); /* change time */ + p += 8; + SIVAL(p,0,fmode); /* File Attributes. */ + p += 4; + SOFF_T(p, 0, SMB_ROUNDUP_ALLOCATION(file_len)); + p += 8; + SOFF_T(p,0,file_len); + + DEBUG(5,("call_nt_transact_create: open name = %s\n", fname)); + + /* Send the required number of replies */ + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0); + + return -1; } /**************************************************************************** @@ -1560,8 +1563,7 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, uint32 total_data_count = (uint32)IVAL(inbuf, smb_nts_TotalDataCount); files_struct *fsp = NULL; uint32 security_info_sent = 0; - int error_class; - uint32 error_code; + NTSTATUS nt_status; if(total_parameter_count < 8) return ERROR_DOS(ERRDOS,ERRbadfunc); @@ -1577,8 +1579,11 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name, (unsigned int)security_info_sent )); - if (!set_sd( fsp, data, total_data_count, security_info_sent, &error_class, &error_code)) - return ERROR_DOS(error_class, error_code); + if (total_data_count == 0) + return ERROR_DOS(ERRDOS, ERRbadaccess); + + if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, total_data_count, security_info_sent))) + return ERROR_NT(nt_status); done: @@ -1589,18 +1594,19 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, /**************************************************************************** Reply to IOCTL - not implemented - no plans. ****************************************************************************/ + static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, char **ppsetup, char **ppparams, char **ppdata) { - static BOOL logged_message = False; + static BOOL logged_message = False; - if(!logged_message) { - DEBUG(0,("call_nt_transact_ioctl: Currently not implemented.\n")); - logged_message = True; /* Only print this once... */ - } - return ERROR_DOS(ERRSRV,ERRnosupport); + if(!logged_message) { + DEBUG(3,("call_nt_transact_ioctl: Currently not implemented.\n")); + logged_message = True; /* Only print this once... */ + } + return ERROR_DOS(ERRSRV,ERRnosupport); } /**************************************************************************** diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 29a854a3974..8c6e8ed805c 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -87,7 +87,7 @@ static void check_for_pipe(char *fname) ****************************************************************************/ static BOOL open_file(files_struct *fsp,connection_struct *conn, - char *fname1,SMB_STRUCT_STAT *psbuf,int flags,mode_t mode, uint32 desired_access) + const char *fname1,SMB_STRUCT_STAT *psbuf,int flags,mode_t mode, uint32 desired_access) { extern struct current_user current_user; pstring fname; @@ -169,11 +169,15 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, if (fsp->fd == -1) ret = vfs_stat(conn, fname, psbuf); - else + else { ret = vfs_fstat(fsp,fsp->fd,psbuf); + /* If we have an fd, this stat should succeed. */ + if (ret == -1) + DEBUG(0,("Error doing fstat on open file %s (%s)\n", fname,strerror(errno) )); + } + /* For a non-io open, this stat failing means file not found. JRA */ if (ret == -1) { - DEBUG(0,("Error doing fstat on open file %s (%s)\n", fname,strerror(errno) )); fd_close(conn, fsp); return False; } @@ -1046,7 +1050,7 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", Open a file for for write to ensure that we can fchmod it. ****************************************************************************/ -files_struct *open_file_fchmod(connection_struct *conn, char *fname, SMB_STRUCT_STAT *psbuf) +files_struct *open_file_fchmod(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) { files_struct *fsp = NULL; BOOL fsp_open; @@ -1058,7 +1062,9 @@ files_struct *open_file_fchmod(connection_struct *conn, char *fname, SMB_STRUCT_ if(!fsp) return NULL; - fsp_open = open_file(fsp,conn,fname,psbuf,O_WRONLY,0,0); + /* note! we must use a non-zero desired access or we don't get + a real file descriptor. Oh what a twisted web we weave. */ + fsp_open = open_file(fsp,conn,fname,psbuf,O_WRONLY,0,FILE_WRITE_DATA); /* * This is not a user visible file open. @@ -1158,7 +1164,7 @@ files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_ST */ if(!got_stat) { - DEBUG(0,("open_directory: unable to stat name = %s. Error was %s\n", + DEBUG(3,("open_directory: unable to stat name = %s. Error was %s\n", fname, strerror(errno) )); file_free(fsp); return NULL; diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index 23606f1d147..14b243b36ed 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -72,34 +72,69 @@ BOOL oplock_message_waiting(fd_set *fds) ****************************************************************************/ -BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeout) +BOOL receive_local_message( char *buffer, int buffer_len, int timeout) { struct sockaddr_in from; - int fromlen = sizeof(from); + socklen_t fromlen = sizeof(from); int32 msg_len = 0; + fd_set fds; + int selrtn = -1; + FD_ZERO(&fds); smb_read_error = 0; - if(timeout != 0) { + /* + * We need to check for kernel oplocks before going into the select + * here, as the EINTR generated by the linux kernel oplock may have + * already been eaten. JRA. + */ + + if (koplocks && koplocks->msg_waiting(&fds)) { + return koplocks->receive_message(&fds, buffer, buffer_len); + } + + while (timeout > 0 && selrtn == -1) { struct timeval to; - int selrtn; int maxfd = oplock_sock; + time_t starttime = time(NULL); - if (koplocks && koplocks->notification_fd != -1) { - FD_SET(koplocks->notification_fd, fds); - maxfd = MAX(maxfd, koplocks->notification_fd); - } + FD_ZERO(&fds); + maxfd = setup_oplock_select_set(&fds); to.tv_sec = timeout / 1000; to.tv_usec = (timeout % 1000) * 1000; - selrtn = sys_select(maxfd+1,fds,NULL,NULL,&to); + DEBUG(5,("receive_local_message: doing select with timeout of %d ms\n", timeout)); + + selrtn = sys_select(maxfd+1,&fds,NULL,NULL,&to); if (selrtn == -1 && errno == EINTR) { + /* could be a kernel oplock interrupt */ - if (koplocks && koplocks->msg_waiting(fds)) { - return koplocks->receive_message(fds, buffer, buffer_len); + if (koplocks && koplocks->msg_waiting(&fds)) { + return koplocks->receive_message(&fds, buffer, buffer_len); + } + + /* + * Linux 2.0.x seems to have a bug in that + * it can return -1, EINTR with a timeout of zero. + * Make sure we bail out here with a read timeout + * if we got EINTR on a timeout of 1 or less. + */ + + if (timeout <= 1) { + smb_read_error = READ_TIMEOUT; + return False; } + + /* Not a kernel interrupt - could be a SIGUSR1 message. We must restart. */ + /* We need to decrement the timeout here. */ + timeout -= ((time(NULL) - starttime)*1000); + if (timeout < 0) + timeout = 1; + + DEBUG(5,("receive_local_message: EINTR : new timeout %d ms\n", timeout)); + continue; } /* Check if error */ @@ -116,11 +151,11 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou } } - if (koplocks && koplocks->msg_waiting(fds)) { - return koplocks->receive_message(fds, buffer, buffer_len); + if (koplocks && koplocks->msg_waiting(&fds)) { + return koplocks->receive_message(&fds, buffer, buffer_len); } - if (!FD_ISSET(oplock_sock, fds)) + if (!FD_ISSET(oplock_sock, &fds)) return False; /* @@ -131,7 +166,7 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou /* * Read a loopback udp message. */ - msg_len = recvfrom(oplock_sock, &buffer[OPBRK_CMD_HEADER_LEN], + msg_len = sys_recvfrom(oplock_sock, &buffer[OPBRK_CMD_HEADER_LEN], buffer_len - OPBRK_CMD_HEADER_LEN, 0, (struct sockaddr *)&from, &fromlen); if(msg_len < 0) { @@ -417,7 +452,7 @@ oplocks. Returning success.\n")); toaddr.sin_port = htons(from_port); toaddr.sin_family = AF_INET; - if(sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0, + if(sys_sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0, (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) { DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n", (int)remotepid, strerror(errno))); @@ -930,7 +965,7 @@ dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n", (unsigned int)dev, (double)inode, file_id ); } - if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0, + if(sys_sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0, (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) { if( DEBUGLVL( 0 ) ) { dbgtext( "request_oplock_break: failed when sending a oplock " ); @@ -967,16 +1002,8 @@ dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n", char op_break_reply[OPBRK_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN]; uint16 reply_from_port; char *reply_msg_start; - fd_set fds; - - FD_ZERO(&fds); - FD_SET(oplock_sock,&fds); - - if (koplocks && koplocks->notification_fd != -1) { - FD_SET(koplocks->notification_fd, &fds); - } - if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply), + if(receive_local_message(op_break_reply, sizeof(op_break_reply), time_left ? time_left * 1000 : 1) == False) { if(smb_read_error == READ_TIMEOUT) { if( DEBUGLVL( 0 ) ) { diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c index 14f6de27c44..ffcf3d0af4d 100644 --- a/source3/smbd/oplock_irix.c +++ b/source3/smbd/oplock_irix.c @@ -56,7 +56,7 @@ static BOOL irix_oplocks_available(void) unlink(tmpname); - if(fcntl(fd, F_OPLKREG, pfd[1]) == -1) { + if(sys_fcntl_long(fd, F_OPLKREG, pfd[1]) == -1) { DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not available on this machine. \ Disabling kernel oplock support.\n" )); close(pfd[0]); @@ -65,7 +65,7 @@ Disabling kernel oplock support.\n" )); return False; } - if(fcntl(fd, F_OPLKACK, OP_REVOKE) < 0 ) { + if(sys_fcntl_long(fd, F_OPLKACK, OP_REVOKE) < 0 ) { DEBUG(0,("check_kernel_oplocks: Error when removing kernel oplock. Error was %s. \ Disabling kernel oplock support.\n", strerror(errno) )); close(pfd[0]); @@ -99,7 +99,7 @@ static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_le */ if(read(oplock_pipe_read, &dummy, 1) != 1) { - DEBUG(0,("receive_local_message: read of kernel notification failed. \ + DEBUG(0,("irix_oplock_receive_message: read of kernel notification failed. \ Error was %s.\n", strerror(errno) )); smb_read_error = READ_ERROR; return False; @@ -111,8 +111,8 @@ Error was %s.\n", strerror(errno) )); * request outstanding. */ - if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) { - DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \ + if(sys_fcntl_ptr(oplock_pipe_read, F_OPLKSTAT, &os) < 0) { + DEBUG(0,("irix_oplock_receive_message: fcntl of kernel notification failed. \ Error was %s.\n", strerror(errno) )); if(errno == EAGAIN) { /* @@ -131,12 +131,12 @@ Error was %s.\n", strerror(errno) )); */ if ((fsp = file_find_di_first((SMB_DEV_T)os.os_dev, (SMB_INO_T)os.os_ino)) == NULL) { - DEBUG(0,("receive_local_message: unable to find open file with dev = %x, inode = %.0f\n", + DEBUG(0,("irix_oplock_receive_message: unable to find open file with dev = %x, inode = %.0f\n", (unsigned int)os.os_dev, (double)os.os_ino )); return False; } - DEBUG(5,("receive_local_message: kernel oplock break request received for \ + DEBUG(5,("irix_oplock_receive_message: kernel oplock break request received for \ dev = %x, inode = %.0f\n, file_id = %ul", (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id )); /* @@ -164,21 +164,21 @@ dev = %x, inode = %.0f\n, file_id = %ul", (unsigned int)fsp->dev, (double)fsp->i static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type) { - if (fcntl(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) { + if (sys_fcntl_long(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) { if(errno != EAGAIN) { - DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \ + DEBUG(0,("irix_set_kernel_oplock: Unable to get kernel oplock on file %s, dev = %x, \ inode = %.0f, file_id = %ul. Error was %s\n", fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id, strerror(errno) )); } else { - DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ + DEBUG(5,("irix_set_kernel_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ inode = %.0f, file_id = %ul. Another process had the file open.\n", fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id )); } return False; } - DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %ul\n", + DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %ul\n", fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id)); return True; @@ -195,8 +195,8 @@ static void irix_release_kernel_oplock(files_struct *fsp) * Check and print out the current kernel * oplock state of this file. */ - int state = fcntl(fsp->fd, F_OPLKACK, -1); - dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %ul, has kernel \ + int state = sys_fcntl_long(fsp->fd, F_OPLKACK, -1); + dbgtext("irix_release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %ul, has kernel \ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id, state ); } @@ -204,9 +204,9 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, /* * Remove the kernel oplock on this file. */ - if(fcntl(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) { + if(sys_fcntl_long(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) { if( DEBUGLVL( 0 )) { - dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " ); + dbgtext("irix_release_kernel_oplock: Error when removing kernel oplock on file " ); dbgtext("%s, dev = %x, inode = %.0f, file_id = %ul. Error was %s\n", fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id, strerror(errno) ); diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c index d9465783807..85f89c12a06 100644 --- a/source3/smbd/oplock_linux.c +++ b/source3/smbd/oplock_linux.c @@ -22,9 +22,9 @@ #if HAVE_KERNEL_OPLOCKS_LINUX -static VOLATILE sig_atomic_t signals_received; -static VOLATILE sig_atomic_t signals_processed; -static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal */ +static SIG_ATOMIC_T signals_received; +#define FD_PENDING_SIZE 100 +static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE]; #ifndef F_SETLEASE #define F_SETLEASE 1024 @@ -52,9 +52,10 @@ static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal static void signal_handler(int sig, siginfo_t *info, void *unused) { - BlockSignals(True, sig); - fd_pending = (sig_atomic_t)info->si_fd; - signals_received++; + if (signals_received < FD_PENDING_SIZE - 1) { + fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd; + signals_received++; + } /* Else signal is lost. */ sys_select_signal(); } @@ -124,20 +125,28 @@ static int linux_setlease(int fd, int leasetype) static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len) { - BOOL ret = True; + int fd; struct files_struct *fsp; - if (signals_received == signals_processed) - return False; + BlockSignals(True, RT_SIGNAL_LEASE); + fd = fd_pending_array[0]; + fsp = file_find_fd(fd); + fd_pending_array[0] = (SIG_ATOMIC_T)-1; + if (signals_received > 1) + memmove((void *)&fd_pending_array[0], (void *)&fd_pending_array[1], + sizeof(SIG_ATOMIC_T)*(signals_received-1)); + signals_received--; + /* now we can receive more signals */ + BlockSignals(False, RT_SIGNAL_LEASE); - if ((fsp = file_find_fd(fd_pending)) == NULL) { - DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd_pending)); - ret = False; - goto out; + if (fsp == NULL) { + DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd)); + return False; } - DEBUG(3,("receive_local_message: kernel oplock break request received for \ -dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode )); + DEBUG(3,("linux_oplock_receive_message: kernel oplock break request received for \ +dev = %x, inode = %.0f fd = %d, fileid = %lu \n", (unsigned int)fsp->dev, (double)fsp->inode, + fd, fsp->file_id)); /* * Create a kernel oplock break message. @@ -155,13 +164,7 @@ dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode )); memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode)); memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id)); - out: - /* now we can receive more signals */ - fd_pending = (sig_atomic_t)-1; - signals_processed++; - BlockSignals(False, RT_SIGNAL_LEASE); - - return ret; + return True; } /**************************************************************************** @@ -171,14 +174,14 @@ dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode )); static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type) { if (linux_setlease(fsp->fd, F_WRLCK) == -1) { - DEBUG(3,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ + DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ inode = %.0f. (%s)\n", fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode, strerror(errno))); return False; } - DEBUG(3,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %lu\n", + DEBUG(3,("linux_set_kernel_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %lu\n", fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id)); return True; @@ -196,7 +199,7 @@ static void linux_release_kernel_oplock(files_struct *fsp) * oplock state of this file. */ int state = fcntl(fsp->fd, F_GETLEASE, 0); - dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %lu has kernel \ + dbgtext("linux_release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %lu has kernel \ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id, state ); } @@ -206,7 +209,7 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, */ if (linux_setlease(fsp->fd, F_UNLCK) == -1) { if (DEBUGLVL(0)) { - dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " ); + dbgtext("linux_release_kernel_oplock: Error when removing kernel oplock on file " ); dbgtext("%s, dev = %x, inode = %.0f, file_id = %lu. Error was %s\n", fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id, strerror(errno) ); @@ -244,7 +247,7 @@ static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *i static BOOL linux_oplock_msg_waiting(fd_set *fds) { - return signals_processed != signals_received; + return signals_received != 0; } /**************************************************************************** diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 629157f22d8..82c0cef77d7 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -259,9 +259,19 @@ int register_vuid(auth_serversupplied_info *server_info, char *smb_name) { /* Keep the homedir handy */ const char *homedir = pdb_get_homedir(server_info->sam_account); + const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); + const char *logon_script = pdb_get_logon_script(server_info->sam_account); if (homedir) { vuser->homedir = smb_xstrdup(homedir); } + + if (unix_homedir) { + vuser->unix_homedir = smb_xstrdup(unix_homedir); + } + + if (logon_script) { + vuser->logon_script = smb_xstrdup(logon_script); + } } memcpy(vuser->session_key, server_info->session_key, sizeof(vuser->session_key)); @@ -279,7 +289,7 @@ int register_vuid(auth_serversupplied_info *server_info, char *smb_name) /* Find all the groups this uid is in and store them. Used by change_to_user() */ initialise_groups(vuser->user.unix_name, vuser->uid, vuser->gid); - get_current_groups( &vuser->n_groups, &vuser->groups); + get_current_groups(vuser->gid, &vuser->n_groups, &vuser->groups); if (server_info->ptok) add_supplementary_nt_login_groups(&vuser->n_groups, &vuser->groups, &server_info->ptok); @@ -301,9 +311,11 @@ int register_vuid(auth_serversupplied_info *server_info, char *smb_name) } /* Register a home dir service for this user */ - if ((!vuser->guest) && vuser->homedir && *(vuser->homedir) + if ((!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir) && (lp_servicenumber(vuser->user.unix_name) < 0)) { - add_home_service(vuser->user.unix_name, vuser->homedir); + vuser->homes_snum = add_home_service(vuser->user.unix_name, vuser->user.unix_name, vuser->unix_homedir); + } else { + vuser->homes_snum = -1; } return vuser->vuid; @@ -336,7 +348,7 @@ void add_session_user(char *user) /**************************************************************************** check if a username is valid ****************************************************************************/ -BOOL user_ok(char *user,int snum) +BOOL user_ok(const char *user,int snum) { char **valid, **invalid; BOOL ret; @@ -345,27 +357,27 @@ BOOL user_ok(char *user,int snum) ret = True; if (lp_invalid_users(snum)) { - lp_list_copy(&invalid, lp_invalid_users(snum)); - if (invalid && lp_list_substitute(invalid, "%S", lp_servicename(snum))) { + str_list_copy(&invalid, lp_invalid_users(snum)); + if (invalid && str_list_substitute(invalid, "%S", lp_servicename(snum))) { ret = !user_in_list(user, invalid); } } - if (invalid) lp_list_free (&invalid); + if (invalid) str_list_free (&invalid); if (ret && lp_valid_users(snum)) { - lp_list_copy(&valid, lp_valid_users(snum)); - if (valid && lp_list_substitute(valid, "%S", lp_servicename(snum))) { + str_list_copy(&valid, lp_valid_users(snum)); + if (valid && str_list_substitute(valid, "%S", lp_servicename(snum))) { ret = user_in_list(user,valid); } } - if (valid) lp_list_free (&valid); + if (valid) str_list_free (&valid); if (ret && lp_onlyuser(snum)) { - char **user_list = lp_list_make (lp_username(snum)); - if (user_list && lp_list_substitute(user_list, "%S", lp_servicename(snum))) { + char **user_list = str_list_make (lp_username(snum)); + if (user_list && str_list_substitute(user_list, "%S", lp_servicename(snum))) { ret = user_in_list(user, user_list); } - if (user_list) lp_list_free (&user_list); + if (user_list) str_list_free (&user_list); } return(ret); @@ -462,42 +474,17 @@ static char *validate_group(char *group, DATA_BLOB password,int snum) ****************************************************************************/ BOOL authorise_login(int snum,char *user, DATA_BLOB password, - BOOL *guest,BOOL *force,uint16 vuid) + BOOL *guest) { BOOL ok = False; - user_struct *vuser = get_valid_user_struct(vuid); - + #if DEBUG_PASSWORD - DEBUG(100,("authorise_login: checking authorisation on user=%s pass=%s vuid=%d\n", - user,password.data, vuid)); + DEBUG(100,("authorise_login: checking authorisation on user=%s pass=%s\n", + user,password.data)); #endif *guest = False; - if (GUEST_ONLY(snum)) - *force = True; - - if (!GUEST_ONLY(snum) && (lp_security() > SEC_SHARE)) { - - /* - * We should just use the given vuid from a sessionsetup_and_X. - */ - - if (!vuser) { - DEBUG(1,("authorise_login: refusing user '%s' with no session setup\n", user)); - return False; - } - - if ((!vuser->guest && user_ok(vuser->user.unix_name,snum)) || - (vuser->guest && GUEST_OK(snum))) { - fstrcpy(user,vuser->user.unix_name); - *guest = vuser->guest; - DEBUG(3,("authorise_login: ACCEPTED: validated based on vuid as %sguest \ -(user=%s)\n", vuser->guest ? "" : "non-", user)); - return True; - } - } - /* there are several possibilities: 1) login as the given user with given password 2) login as a previously registered username with the given password @@ -510,84 +497,61 @@ BOOL authorise_login(int snum,char *user, DATA_BLOB password, if the service is guest_only then steps 1 to 5 are skipped */ - if (!(GUEST_ONLY(snum) && GUEST_OK(snum))) { - /* check for a previously registered guest username */ - if (!ok && (vuser != 0) && vuser->guest) { - if (user_ok(vuser->user.unix_name,snum) && - password_ok(vuser->user.unix_name, password)) { - fstrcpy(user, vuser->user.unix_name); - *guest = False; - DEBUG(3,("authorise_login: ACCEPTED: given password with registered user %s\n", user)); + /* now check the list of session users */ + if (!ok) { + char *auser; + char *user_list = strdup(session_users); + if (!user_list) + return(False); + + for (auser=strtok(user_list,LIST_SEP); !ok && auser; + auser = strtok(NULL,LIST_SEP)) { + fstring user2; + fstrcpy(user2,auser); + if (!user_ok(user2,snum)) + continue; + + if (password_ok(user2,password)) { ok = True; + fstrcpy(user,user2); + DEBUG(3,("authorise_login: ACCEPTED: session list username (%s) \ +and given password ok\n", user)); } } - - /* now check the list of session users */ - if (!ok) { - char *auser; - char *user_list = strdup(session_users); - if (!user_list) - return(False); - - for (auser=strtok(user_list,LIST_SEP); !ok && auser; - auser = strtok(NULL,LIST_SEP)) { + + SAFE_FREE(user_list); + } + + /* check the user= fields and the given password */ + if (!ok && lp_username(snum)) { + char *auser; + pstring user_list; + StrnCpy(user_list,lp_username(snum),sizeof(pstring)); + + pstring_sub(user_list,"%S",lp_servicename(snum)); + + for (auser=strtok(user_list,LIST_SEP); auser && !ok; + auser = strtok(NULL,LIST_SEP)) { + if (*auser == '@') { + auser = validate_group(auser+1,password,snum); + if (auser) { + ok = True; + fstrcpy(user,auser); + DEBUG(3,("authorise_login: ACCEPTED: group username \ +and given password ok (%s)\n", user)); + } + } else { fstring user2; fstrcpy(user2,auser); - if (!user_ok(user2,snum)) - continue; - - if (password_ok(user2,password)) { + if (user_ok(user2,snum) && password_ok(user2,password)) { ok = True; fstrcpy(user,user2); - DEBUG(3,("authorise_login: ACCEPTED: session list username (%s) \ -and given password ok\n", user)); - } - } - - SAFE_FREE(user_list); - } - - /* check for a previously validated username/password pair */ - if (!ok && (lp_security() > SEC_SHARE) && (vuser != 0) && !vuser->guest && - user_ok(vuser->user.unix_name,snum)) { - fstrcpy(user,vuser->user.unix_name); - *guest = False; - DEBUG(3,("authorise_login: ACCEPTED: validated uid (%s) as non-guest\n", - user)); - ok = True; - } - - /* check the user= fields and the given password */ - if (!ok && lp_username(snum)) { - char *auser; - pstring user_list; - StrnCpy(user_list,lp_username(snum),sizeof(pstring)); - - pstring_sub(user_list,"%S",lp_servicename(snum)); - - for (auser=strtok(user_list,LIST_SEP); auser && !ok; - auser = strtok(NULL,LIST_SEP)) { - if (*auser == '@') { - auser = validate_group(auser+1,password,snum); - if (auser) { - ok = True; - fstrcpy(user,auser); - DEBUG(3,("authorise_login: ACCEPTED: group username \ + DEBUG(3,("authorise_login: ACCEPTED: user list username \ and given password ok (%s)\n", user)); - } - } else { - fstring user2; - fstrcpy(user2,auser); - if (user_ok(user2,snum) && password_ok(user2,password)) { - ok = True; - fstrcpy(user,user2); - DEBUG(3,("authorise_login: ACCEPTED: user list username \ -and given password ok (%s)\n", user)); - } } } } - } /* not guest only */ + } /* check for a normal guest connection */ if (!ok && GUEST_OK(snum)) { diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c index 6c1e6efa735..f7e9c595c13 100644 --- a/source3/smbd/pipes.c +++ b/source3/smbd/pipes.c @@ -50,7 +50,7 @@ int reply_open_pipe_and_X(connection_struct *conn, int i; /* XXXX we need to handle passed times, sattr and flags */ - srvstr_pull(inbuf, pipe_name, smb_buf(inbuf), sizeof(pipe_name), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, pipe_name, smb_buf(inbuf), sizeof(pipe_name), STR_TERMINATE); /* If the name doesn't start \PIPE\ then this is directed */ /* at a mailslot or something we really, really don't understand, */ diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 9c8835214fb..85818d524a3 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -104,7 +104,7 @@ static void print_canon_ace(canon_ace *pace, int num) dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" ); dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee)); if (pace->owner_type == UID_ACE) { - char *u_name = uidtoname(pace->unix_ug.uid); + const char *u_name = uidtoname(pace->unix_ug.uid); dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name); } else if (pace->owner_type == GID_ACE) { char *g_name = gidtoname(pace->unix_ug.gid); @@ -439,9 +439,15 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, if (security_info_sent & OWNER_SECURITY_INFORMATION) { sid_copy(&owner_sid, psd->owner_sid); if (!sid_to_uid( &owner_sid, puser, &sid_type)) { +#if ACL_FORCE_UNMAPPABLE + /* this allows take ownership to work reasonably */ + extern struct current_user current_user; + *puser = current_user.uid; +#else DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n", sid_string_static(&owner_sid))); return False; +#endif } } @@ -453,8 +459,14 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, if (security_info_sent & GROUP_SECURITY_INFORMATION) { sid_copy(&grp_sid, psd->grp_sid); if (!sid_to_gid( &grp_sid, pgrp, &sid_type)) { +#if ACL_FORCE_UNMAPPABLE + /* this allows take group ownership to work reasonably */ + extern struct current_user current_user; + *pgrp = current_user.gid; +#else DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n")); return False; +#endif } } @@ -467,7 +479,7 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, Ensure the enforced permissions for this share apply. ****************************************************************************/ -static mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type) +static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) { int snum = SNUM(fsp->conn); mode_t and_bits = (mode_t)0; @@ -486,6 +498,10 @@ static mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type) /* Now bounce them into the S_USR space. */ switch(type) { case S_IRUSR: + /* Ensure owner has read access. */ + pace->perms |= S_IRUSR; + if (fsp->is_directory) + pace->perms |= (S_IWUSR|S_IXUSR); and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR); or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR); break; @@ -499,7 +515,34 @@ static mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type) break; } - return ((perms & and_bits)|or_bits); + pace->perms = ((pace->perms & and_bits)|or_bits); +} + +/**************************************************************************** + Check if a given uid/SID is in a group gid/SID. This is probably very + expensive and will need optimisation. A *lot* of optimisation :-). JRA. +****************************************************************************/ + +static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) +{ + extern DOM_SID global_sid_World; + fstring u_name; + fstring g_name; + + /* "Everyone" always matches every uid. */ + + if (sid_equal(&group_ace->trustee, &global_sid_World)) + return True; + + fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid)); + fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid)); + + /* + * Due to the winbind interfaces we need to do this via names, + * not uids/gids. + */ + + return user_in_group_list(u_name, g_name ); } /**************************************************************************** @@ -524,24 +567,16 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, BOOL got_user = False; BOOL got_grp = False; BOOL got_other = False; + canon_ace *pace_other = NULL; + canon_ace *pace_group = NULL; for (pace = *pp_ace; pace; pace = pace->next) { if (pace->type == SMB_ACL_USER_OBJ) { - if (setting_acl) { - /* Ensure owner has read access. */ - pace->perms |= S_IRUSR; - if (fsp->is_directory) - pace->perms |= (S_IWUSR|S_IXUSR); - - /* - * Ensure create mask/force create mode is respected on set. - */ - - pace->perms = apply_default_perms(fsp, pace->perms, S_IRUSR); - } - + if (setting_acl) + apply_default_perms(fsp, pace, S_IRUSR); got_user = True; + } else if (pace->type == SMB_ACL_GROUP_OBJ) { /* @@ -549,8 +584,10 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, */ if (setting_acl) - pace->perms = apply_default_perms(fsp, pace->perms, S_IRGRP); + apply_default_perms(fsp, pace, S_IRGRP); got_grp = True; + pace_group = pace; + } else if (pace->type == SMB_ACL_OTHER) { /* @@ -558,8 +595,9 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, */ if (setting_acl) - pace->perms = apply_default_perms(fsp, pace->perms, S_IROTH); + apply_default_perms(fsp, pace, S_IROTH); got_other = True; + pace_other = pace; } } @@ -574,9 +612,21 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, pace->owner_type = UID_ACE; pace->unix_ug.uid = pst->st_uid; pace->trustee = *pfile_owner_sid; - pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); pace->attr = ALLOW_ACE; + if (setting_acl) { + /* If we only got an "everyone" perm, just use that. */ + if (!got_grp && got_other) + pace->perms = pace_other->perms; + else if (got_grp && uid_entry_in_group(pace, pace_group)) + pace->perms = pace_group->perms; + else + pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); + apply_default_perms(fsp, pace, S_IRUSR); + } else { + pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); + } + DLIST_ADD(*pp_ace, pace); } @@ -591,8 +641,17 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, pace->owner_type = GID_ACE; pace->unix_ug.uid = pst->st_gid; pace->trustee = *pfile_grp_sid; - pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); pace->attr = ALLOW_ACE; + if (setting_acl) { + /* If we only got an "everyone" perm, just use that. */ + if (got_other) + pace->perms = pace_other->perms; + else + pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); + apply_default_perms(fsp, pace, S_IRGRP); + } else { + pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); + } DLIST_ADD(*pp_ace, pace); } @@ -608,8 +667,9 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, pace->owner_type = WORLD_ACE; pace->unix_ug.world = -1; pace->trustee = global_sid_World; - pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH); pace->attr = ALLOW_ACE; + pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH); + apply_default_perms(fsp, pace, S_IROTH); DLIST_ADD(*pp_ace, pace); } @@ -919,33 +979,6 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); } /**************************************************************************** - Check if a given uid/SID is in a group gid/SID. This is probably very - expensive and will need optimisation. A *lot* of optimisation :-). JRA. -****************************************************************************/ - -static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) -{ - extern DOM_SID global_sid_World; - fstring u_name; - fstring g_name; - - /* "Everyone" always matches every uid. */ - - if (sid_equal(&group_ace->trustee, &global_sid_World)) - return True; - - fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid)); - fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid)); - - /* - * Due to the winbind interfaces we need to do this via names, - * not uids/gids. - */ - - return user_in_group_list(u_name, g_name ); -} - -/**************************************************************************** ASCII art time again... JRA :-). We have 3 cases to process when moving from an NT ACL to a POSIX ACL. Firstly, @@ -1996,6 +2029,52 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) return sd_size; } +/* + try to chown a file. We will be able to chown it under the following conditions + + 1) if we have root privileges, then it will just work + 2) if we have write permission to the file and dos_filemodes is set + then allow chown to the currently authenticated user. + + */ +static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) +{ + int ret; + extern struct current_user current_user; + files_struct *fsp; + SMB_STRUCT_STAT st; + + /* try the direct way first */ + ret = vfs_chown(conn, fname, uid, gid); + if (ret == 0) + return 0; + + if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn))) + return -1; + + if (vfs_stat(conn,fname,&st)) + return -1; + + fsp = open_file_fchmod(conn,fname,&st); + if (!fsp) + return -1; + + /* only allow chown to the current user. This is more secure, + and also copes with the case where the SID in a take ownership ACL is + a local SID on the users workstation + */ + uid = current_user.uid; + + become_root(); + /* Keep the current file gid the same. */ + ret = vfswrap_fchown(fsp, fsp->fd, uid, (gid_t)-1); + unbecome_root(); + + close_file_fchmod(fsp); + + return ret; +} + /**************************************************************************** Reply to set a security descriptor on an fsp. security_info_sent is the description of the following NT ACL. @@ -2052,7 +2131,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); - if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { + if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n", fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) )); return False; @@ -2308,6 +2387,7 @@ BOOL directory_has_default_acl(connection_struct *conn, const char *fname) if (dir_acl != NULL && (conn->vfs_ops.sys_acl_get_entry(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) has_acl = True; - conn->vfs_ops.sys_acl_free_acl(conn, dir_acl); + if (dir_acl) + conn->vfs_ops.sys_acl_free_acl(conn, dir_acl); return has_acl; } diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 007621f6bb2..43d3c6c5314 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -42,8 +42,8 @@ extern int last_message; extern int global_oplock_break; extern userdom_struct current_user_info; extern int smb_read_error; -extern VOLATILE sig_atomic_t reload_after_sighup; -extern VOLATILE sig_atomic_t got_sig_term; +SIG_ATOMIC_T reload_after_sighup; +SIG_ATOMIC_T got_sig_term; extern BOOL global_machine_password_needs_changing; extern fstring global_myworkgroup; extern pstring global_myname; @@ -109,10 +109,12 @@ BOOL push_oplock_pending_smb_message(char *buf, int msg_len) oplock messages, change notify events etc. ****************************************************************************/ -static void async_processing(fd_set *fds, char *buffer, int buffer_len) +static void async_processing(char *buffer, int buffer_len) { + DEBUG(10,("async_processing: Doing async processing.\n")); + /* check for oplock messages (both UDP and kernel) */ - if (receive_local_message(fds, buffer, buffer_len, 0)) { + if (receive_local_message(buffer, buffer_len, 1)) { process_local_message(buffer, buffer_len); } @@ -193,6 +195,27 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) */ FD_ZERO(&fds); + + /* + * Ensure we process oplock break messages by preference. + * We have to do this before the select, after the select + * and if the select returns EINTR. This is due to the fact + * that the selects called from async_processing can eat an EINTR + * caused by a signal (we can't take the break message there). + * This is hideously complex - *MUST* be simplified for 3.0 ! JRA. + */ + + if (oplock_message_waiting(&fds)) { + DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n")); + async_processing(buffer, buffer_len); + /* + * After async processing we must go and do the select again, as + * the state of the flag in fds for the server file descriptor is + * indeterminate - we may have done I/O on it in the oplock processing. JRA. + */ + goto again; + } + FD_SET(smbd_server_fd(),&fds); maxfd = setup_oplock_select_set(&fds); @@ -206,7 +229,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) is the best we can do until the oplock code knows more about signals */ if (selrtn == -1 && errno == EINTR) { - async_processing(&fds, buffer, buffer_len); + async_processing(buffer, buffer_len); /* * After async processing we must go and do the select again, as * the state of the flag in fds for the server file descriptor is @@ -235,7 +258,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) */ if (oplock_message_waiting(&fds)) { - async_processing(&fds, buffer, buffer_len); + async_processing(buffer, buffer_len); /* * After async processing we must go and do the select again, as * the state of the flag in fds for the server file descriptor is @@ -275,7 +298,6 @@ BOOL receive_next_smb(char *inbuf, int bufsize, int timeout) void respond_to_all_remaining_local_messages(void) { char buffer[1024]; - fd_set fds; /* * Assert we have no exclusive open oplocks. @@ -288,23 +310,12 @@ void respond_to_all_remaining_local_messages(void) } /* - * Setup the select read fd set. - */ - - FD_ZERO(&fds); - if(!setup_oplock_select_set(&fds)) - return; - - /* * Keep doing receive_local_message with a 1 ms timeout until * we have no more messages. */ - while(receive_local_message(&fds, buffer, sizeof(buffer), 1)) { + while(receive_local_message(buffer, sizeof(buffer), 1)) { /* Deal with oplock break requests from other smbd's. */ process_local_message(buffer, sizeof(buffer)); - - FD_ZERO(&fds); - (void)setup_oplock_select_set(&fds); } return; @@ -829,10 +840,6 @@ set. Ignoring max smbd restriction.\n")); ****************************************************************************/ void process_smb(char *inbuf, char *outbuf) { -#ifdef WITH_SSL - extern BOOL sslEnabled; /* don't use function for performance reasons */ - static int sslConnected = 0; -#endif /* WITH_SSL */ static int trans_num; int msg_type = CVAL(inbuf,0); int32 len = smb_len(inbuf); @@ -860,18 +867,6 @@ void process_smb(char *inbuf, char *outbuf) DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type, len ) ); DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) ); -#ifdef WITH_SSL - if(sslEnabled && !sslConnected){ - sslConnected = sslutil_negotiate_ssl(smbd_server_fd(), msg_type); - if(sslConnected < 0){ /* an error occured */ - exit_server("SSL negotiation failed"); - }else if(sslConnected){ - trans_num++; - return; - } - } -#endif /* WITH_SSL */ - if (msg_type == 0) show_msg(inbuf); else if(msg_type == SMBkeepalive) diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index fbb981781fd..0ccdf7c241b 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -163,10 +163,10 @@ int reply_tcon(connection_struct *conn, *service = *password = *dev = 0; p = smb_buf(inbuf)+1; - p += srvstr_pull(inbuf, service, p, sizeof(service), -1, STR_TERMINATE) + 1; - pwlen = srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1; + p += srvstr_pull_buf(inbuf, service, p, sizeof(service), STR_TERMINATE) + 1; + pwlen = srvstr_pull_buf(inbuf, password, p, sizeof(password), STR_TERMINATE) + 1; p += pwlen; - p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1; + p += srvstr_pull_buf(inbuf, dev, p, sizeof(dev), STR_TERMINATE) + 1; p = strrchr_m(service,'\\'); if (p) { @@ -233,7 +233,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt } p = smb_buf(inbuf) + passlen; - p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE); + p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE); /* * the service name can be either: \\server\share @@ -377,7 +377,7 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size SMB_STRUCT_STAT sbuf; START_PROFILE(SMBchkpth); - srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE); RESOLVE_DFSPATH(name, conn, inbuf, outbuf); @@ -429,7 +429,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size START_PROFILE(SMBgetatr); p = smb_buf(inbuf) + 1; - p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE); + p += srvstr_pull_buf(inbuf, fname, p, sizeof(fname), STR_TERMINATE); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -505,7 +505,7 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size START_PROFILE(SMBsetatr); p = smb_buf(inbuf) + 1; - p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE); + p += srvstr_pull_buf(inbuf, fname, p, sizeof(fname), STR_TERMINATE); unix_convert(fname,conn,0,&bad_path,&sbuf); mode = SVAL(inbuf,smb_vwv0); @@ -542,23 +542,46 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size ****************************************************************************/ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - int outsize = 0; - SMB_BIG_UINT dfree,dsize,bsize; - START_PROFILE(SMBdskattr); - - conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize); - - outsize = set_message(outbuf,5,0,True); + int outsize = 0; + SMB_BIG_UINT dfree,dsize,bsize; + START_PROFILE(SMBdskattr); + + conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize); - SSVAL(outbuf,smb_vwv0,dsize); - SSVAL(outbuf,smb_vwv1,bsize/512); - SSVAL(outbuf,smb_vwv2,512); - SSVAL(outbuf,smb_vwv3,dfree); + outsize = set_message(outbuf,5,0,True); + + if (Protocol <= PROTOCOL_LANMAN2) { + double total_space, free_space; + /* we need to scale this to a number that DOS6 can handle. We + use floating point so we can handle large drives on systems + that don't have 64 bit integers - DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree)); + we end up displaying a maximum of 2G to DOS systems + */ + total_space = dsize * (double)bsize; + free_space = dfree * (double)bsize; - END_PROFILE(SMBdskattr); - return(outsize); + dsize = (total_space+63*512) / (64*512); + dfree = (free_space+63*512) / (64*512); + + if (dsize > 0xFFFF) dsize = 0xFFFF; + if (dfree > 0xFFFF) dfree = 0xFFFF; + + SSVAL(outbuf,smb_vwv0,dsize); + SSVAL(outbuf,smb_vwv1,64); /* this must be 64 for dos systems */ + SSVAL(outbuf,smb_vwv2,512); /* and this must be 512 */ + SSVAL(outbuf,smb_vwv3,dfree); + } else { + SSVAL(outbuf,smb_vwv0,dsize); + SSVAL(outbuf,smb_vwv1,bsize/512); + SSVAL(outbuf,smb_vwv2,512); + SSVAL(outbuf,smb_vwv3,dfree); + } + + DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree)); + + END_PROFILE(SMBdskattr); + return(outsize); } @@ -602,7 +625,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size maxentries = SVAL(inbuf,smb_vwv0); dirtype = SVAL(inbuf,smb_vwv1); p = smb_buf(inbuf) + 1; - p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE); + p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE); p++; status_len = SVAL(p, 0); p += 2; @@ -783,7 +806,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size outsize = set_message(outbuf,1,0,True); p = smb_buf(inbuf) + 1; - p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE); + p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE); p++; status_len = SVAL(p,0); p += 2; @@ -831,7 +854,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, share_mode = SVAL(inbuf,smb_vwv0); - srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), STR_TERMINATE); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -921,7 +944,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt } /* XXXX we need to handle passed times, sattr and flags */ - srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -1040,7 +1063,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, com = SVAL(inbuf,smb_com); createmode = SVAL(inbuf,smb_vwv0); - srvstr_pull(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), STR_TERMINATE); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -1112,7 +1135,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, START_PROFILE(SMBctemp); createmode = SVAL(inbuf,smb_vwv0); - srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), STR_TERMINATE); pstrcat(fname,"\\TMXXXXXX"); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -1370,7 +1393,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size dirtype = SVAL(inbuf,smb_vwv0); - srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE); RESOLVE_DFSPATH(name, conn, inbuf, outbuf); @@ -2719,7 +2742,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, NTSTATUS status; START_PROFILE(SMBmkdir); - srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), STR_TERMINATE); status = mkdir_internal(conn, directory); if (!NT_STATUS_IS_OK(status)) @@ -2880,7 +2903,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, SMB_STRUCT_STAT sbuf; START_PROFILE(SMBrmdir); - srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), STR_TERMINATE); RESOLVE_DFSPATH(directory, conn, inbuf, outbuf) @@ -3241,9 +3264,9 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, START_PROFILE(SMBmv); p = smb_buf(inbuf) + 1; - p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE); + p += srvstr_pull_buf(inbuf, name, p, sizeof(name), STR_TERMINATE); p++; - p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE); + p += srvstr_pull_buf(inbuf, newname, p, sizeof(newname), STR_TERMINATE); RESOLVE_DFSPATH(name, conn, inbuf, outbuf); RESOLVE_DFSPATH(newname, conn, inbuf, outbuf); @@ -3373,8 +3396,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, *directory = *mask = 0; p = smb_buf(inbuf); - p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE); - p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE); + p += srvstr_pull_buf(inbuf, name, p, sizeof(name), STR_TERMINATE); + p += srvstr_pull_buf(inbuf, newname, p, sizeof(newname), STR_TERMINATE); DEBUG(3,("reply_copy : %s -> %s\n",name,newname)); @@ -3526,7 +3549,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_DOS(ERRDOS,ERRnoaccess); } - srvstr_pull(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), STR_TERMINATE); if (strlen(newdir) == 0) { ok = True; diff --git a/source3/smbd/sec_ctx.c b/source3/smbd/sec_ctx.c index 87bf8b17443..bdcdce6e145 100644 --- a/source3/smbd/sec_ctx.c +++ b/source3/smbd/sec_ctx.c @@ -132,29 +132,39 @@ static void gain_root(void) Get the list of current groups. ****************************************************************************/ -int get_current_groups(int *p_ngroups, gid_t **p_groups) +int get_current_groups(gid_t gid, int *p_ngroups, gid_t **p_groups) { int i; gid_t grp; - int ngroups = sys_getgroups(0,&grp); - gid_t *groups; + int ngroups; + gid_t *groups = NULL; (*p_ngroups) = 0; (*p_groups) = NULL; - if (ngroups <= 0) - return -1; + /* this looks a little strange, but is needed to cope with + systems that put the current egid in the group list + returned from getgroups() (tridge) */ + save_re_gid(); + set_effective_gid(gid); + setgid(gid); - if((groups = (gid_t *)malloc(sizeof(gid_t)*ngroups)) == NULL) { + ngroups = sys_getgroups(0,&grp); + if (ngroups <= 0) { + goto fail; + } + + if((groups = (gid_t *)malloc(sizeof(gid_t)*(ngroups+1))) == NULL) { DEBUG(0,("setup_groups malloc fail !\n")); - return -1; + goto fail; } if ((ngroups = sys_getgroups(ngroups,groups)) == -1) { - SAFE_FREE(groups); - return -1; + goto fail; } + restore_re_gid(); + (*p_ngroups) = ngroups; (*p_groups) = groups; @@ -164,7 +174,12 @@ int get_current_groups(int *p_ngroups, gid_t **p_groups) } DEBUG( 3, ( "\n" ) ); - return ngroups; + return ngroups; + +fail: + SAFE_FREE(groups); + restore_re_gid(); + return -1; } /**************************************************************************** @@ -204,7 +219,7 @@ BOOL initialise_groups(char *user, uid_t uid, gid_t gid) SAFE_FREE(prev_ctx_p->groups); prev_ctx_p->ngroups = 0; - get_current_groups(&prev_ctx_p->ngroups, &prev_ctx_p->groups); + get_current_groups(gid, &prev_ctx_p->ngroups, &prev_ctx_p->groups); done: unbecome_root(); @@ -404,7 +419,7 @@ void init_sec_ctx(void) ctx_p->uid = geteuid(); ctx_p->gid = getegid(); - get_current_groups(&ctx_p->ngroups, &ctx_p->groups); + get_current_groups(ctx_p->gid, &ctx_p->ngroups, &ctx_p->groups); ctx_p->token = NULL; /* Maps to guest user. */ diff --git a/source3/smbd/server.c b/source3/smbd/server.c index c759f56e0cb..6f0d0238b0d 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -53,7 +53,7 @@ int smbd_server_fd(void) return server_fd; } -void smbd_set_server_fd(int fd) +static void smbd_set_server_fd(int fd) { server_fd = fd; client_setfd(fd); @@ -63,7 +63,7 @@ void smbd_set_server_fd(int fd) Terminate signal. ****************************************************************************/ -VOLATILE sig_atomic_t got_sig_term = 0; +SIG_ATOMIC_T got_sig_term = 0; static void sig_term(void) { @@ -75,7 +75,7 @@ static void sig_term(void) Catch a sighup. ****************************************************************************/ -VOLATILE sig_atomic_t reload_after_sighup = 0; +SIG_ATOMIC_T reload_after_sighup = 0; static void sig_hup(int sig) { @@ -382,6 +382,8 @@ BOOL reload_services(BOOL test) { BOOL ret; + set_register_printer_fn(); + if (lp_loaded()) { pstring fname; pstrcpy(fname,lp_configfile()); @@ -531,6 +533,7 @@ void exit_server(char *reason) } locking_end(); + printing_end(); DEBUG(3,("Server exit (%s)\n", (reason ? reason : ""))); exit(0); @@ -782,15 +785,6 @@ static void usage(char *pname) } #endif -#ifdef WITH_SSL - { - extern BOOL sslEnabled; - sslEnabled = lp_ssl_enabled(); - if(sslEnabled) - sslutil_init(True); - } -#endif /* WITH_SSL */ - fstrcpy(global_myworkgroup, lp_workgroup()); DEBUG(3,( "loaded services\n")); @@ -861,6 +855,9 @@ static void usage(char *pname) if (!share_info_db_init()) exit(1); + if (!init_registry()) + exit(1); + if(!initialize_password_db(False)) exit(1); @@ -869,7 +866,7 @@ static void usage(char *pname) /* possibly reload the services file. */ reload_services(True); - if(!pdb_generate_sam_sid()) { + if(!get_global_sam_sid()) { DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n")); exit(1); } diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 0ae49b7adfa..9ac610ab5a9 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -78,12 +78,9 @@ BOOL set_current_service(connection_struct *conn,BOOL do_chdir) Add a home service. Returns the new service number or -1 if fail. ****************************************************************************/ -int add_home_service(const char *service, const char *homedir) +int add_home_service(const char *service, const char *username, const char *homedir) { int iHomeService; - int iService; - fstring new_service; - fstring domain; if (!service || !homedir) return -1; @@ -98,11 +95,19 @@ int add_home_service(const char *service, const char *homedir) * include any macros. */ - split_domain_and_name(service, domain, new_service); - lp_add_home(new_service, iHomeService, homedir); - iService = lp_servicenumber(new_service); + { + const char *p = strchr(service,*lp_winbind_separator()); + + /* We only want the 'user' part of the string */ + if (p) { + service = p + 1; + } + } + + lp_add_home(service, iHomeService, username, homedir); + + return lp_servicenumber(service); - return iService; } @@ -122,7 +127,7 @@ int find_service(fstring service) /* now handle the special case of a home directory */ if (iService < 0) { - char *phome_dir = get_user_service_home_dir(service); + char *phome_dir = get_user_home_dir(service); if(!phome_dir) { @@ -131,13 +136,13 @@ int find_service(fstring service) * be a Windows to unix mapped user name. */ if(map_username(service)) - phome_dir = get_user_service_home_dir(service); + phome_dir = get_user_home_dir(service); } DEBUG(3,("checking for home directory %s gave %s\n",service, phome_dir?phome_dir:"(NULL)")); - iService = add_home_service(service,phome_dir); + iService = add_home_service(service,service /* 'username' */, phome_dir); } /* If we still don't have a service, attempt to add it as a printer. */ @@ -213,7 +218,7 @@ int find_service(fstring service) do some basic sainity checks on the share. This function modifies dev, ecode. ****************************************************************************/ -static NTSTATUS share_sanity_checks(int snum, const char* service, pstring dev) +static NTSTATUS share_sanity_checks(int snum, pstring dev) { if (!lp_snum_ok(snum) || @@ -223,7 +228,7 @@ static NTSTATUS share_sanity_checks(int snum, const char* service, pstring dev) } /* you can only connect to the IPC$ service as an ipc device */ - if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) + if (strequal(lp_fstype(snum), "IPC")) pstrcpy(dev,"IPC"); if (dev[0] == '?' || !dev[0]) { @@ -261,24 +266,24 @@ static void set_read_only(connection_struct *conn) if (!service) return; - lp_list_copy(&list, lp_readlist(conn->service)); + str_list_copy(&list, lp_readlist(conn->service)); if (list) { - if (!lp_list_substitute(list, "%S", service)) { + if (!str_list_substitute(list, "%S", service)) { DEBUG(0, ("ERROR: read list substitution failed\n")); } if (user_in_list(conn->user, list)) conn->read_only = True; - lp_list_free(&list); + str_list_free(&list); } - lp_list_copy(&list, lp_writelist(conn->service)); + str_list_copy(&list, lp_writelist(conn->service)); if (list) { - if (!lp_list_substitute(list, "%S", service)) { + if (!str_list_substitute(list, "%S", service)) { DEBUG(0, ("ERROR: write list substitution failed\n")); } if (user_in_list(conn->user, list)) conn->read_only = False; - lp_list_free(&list); + str_list_free(&list); } } @@ -314,89 +319,26 @@ static void set_admin_user(connection_struct *conn) } /**************************************************************************** - Make a connection to a service. - * - * @param service (May be modified to canonical form???) + Make a connection, given the snum to connect to, and the vuser of the + connecting user if appropriate. ****************************************************************************/ -connection_struct *make_connection(char *service, DATA_BLOB password, - char *dev, uint16 vuid, NTSTATUS *status) +static connection_struct *make_connection_snum(int snum, user_struct *vuser, + DATA_BLOB password, + char *dev, NTSTATUS *status) { - int snum; struct passwd *pass = NULL; BOOL guest = False; BOOL force = False; connection_struct *conn; - uid_t euid; - + struct stat st; fstring user; - ZERO_STRUCT(user); - - /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */ - if (!non_root_mode() && (euid = geteuid()) != 0) { - DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid )); - smb_panic("make_connection: PANIC ERROR. Called as nonroot\n"); - } - - strlower(service); - - snum = find_service(service); - - if (snum < 0) { - if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) { - DEBUG(3,("refusing IPC connection\n")); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - - DEBUG(0,("%s (%s) couldn't find service %s\n", - remote_machine, client_addr(), service)); - *status = NT_STATUS_BAD_NETWORK_NAME; - return NULL; - } - - if (strequal(service,HOMES_NAME)) { - if(lp_security() != SEC_SHARE) { - if (validated_username(vuid)) { - fstring unix_username; - fstrcpy(unix_username,validated_username(vuid)); - return make_connection(unix_username, - password,dev,vuid,status); - } - } else { - /* Security = share. Try with current_user_info.smb_name - * as the username. */ - if (* current_user_info.smb_name) { - fstring unix_username; - fstrcpy(unix_username, - current_user_info.smb_name); - map_username(unix_username); - return make_connection(unix_username, - password,dev,vuid,status); - } - } - } + *user = 0; - if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, service, dev))) { + if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) { return NULL; } - /* add it as a possible user name if we - are in share mode security */ - if (lp_security() == SEC_SHARE) { - add_session_user(service); - } - - - /* shall we let them in? */ - if (!authorise_login(snum,user,password,&guest,&force,vuid)) { - DEBUG( 2, ( "Invalid username/password for %s [%s]\n", service, user ) ); - *status = NT_STATUS_WRONG_PASSWORD; - return NULL; - } - - add_session_user(user); - conn = conn_new(); if (!conn) { DEBUG(0,("Couldn't find free connection.\n")); @@ -404,20 +346,72 @@ connection_struct *make_connection(char *service, DATA_BLOB password, return NULL; } - /* find out some info about the user */ - pass = smb_getpwnam(user,True); + if (lp_guest_only(snum)) { + char *guestname = lp_guestaccount(); + guest = True; + force = True; + pass = getpwnam_alloc(guestname); + if (!pass) { + DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname)); + conn_free(conn); + *status = NT_STATUS_NO_SUCH_USER; + return NULL; + } + fstrcpy(user,pass->pw_name); + conn->force_user = True; + string_set(&conn->user,pass->pw_name); + passwd_free(&pass); + DEBUG(3,("Guest only user %s\n",user)); + } else if (vuser) { + if (vuser->guest) { + if (!lp_guest_ok(snum)) { + DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)", lp_servicename(snum))); + conn_free(conn); + *status = NT_STATUS_ACCESS_DENIED; + return NULL; + } + } else { + if (!user_ok(vuser->user.unix_name, snum)) { + DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)", vuser->user.unix_name, lp_servicename(snum))); + conn_free(conn); + *status = NT_STATUS_ACCESS_DENIED; + return NULL; + } + } + conn->vuid = vuser->vuid; + conn->uid = vuser->uid; + conn->gid = vuser->gid; + string_set(&conn->user,vuser->user.unix_name); + fstrcpy(user,vuser->user.unix_name); + guest = vuser->guest; + } else if (lp_security() == SEC_SHARE) { + /* add it as a possible user name if we + are in share mode security */ + add_session_user(lp_servicename(snum)); + /* shall we let them in? */ + if (!authorise_login(snum,user,password,&guest)) { + DEBUG( 2, ( "Invalid username/password for [%s]\n", + lp_servicename(snum)) ); + conn_free(conn); + *status = NT_STATUS_WRONG_PASSWORD; + return NULL; + } + pass = Get_Pwnam(user); + conn->force_user = force; + conn->uid = pass->pw_uid; + conn->gid = pass->pw_gid; + string_set(&conn->user, pass->pw_name); + fstrcpy(user, pass->pw_name); - if (pass == NULL) { - DEBUG(0,( "Couldn't find account %s\n",user)); - *status = NT_STATUS_NO_SUCH_USER; + } else { + DEBUG(0, ("invalid VUID (vuser) but not in security=share\n")); conn_free(conn); + *status = NT_STATUS_ACCESS_DENIED; return NULL; } - conn->force_user = force; - conn->vuid = vuid; - conn->uid = pass->pw_uid; - conn->gid = pass->pw_gid; + add_session_user(user); + safe_strcpy(conn->client_address, client_addr(), sizeof(conn->client_address)-1); conn->num_files_open = 0; @@ -450,18 +444,21 @@ connection_struct *make_connection(char *service, DATA_BLOB password, pstrcpy(fuser,lp_force_user(snum)); /* Allow %S to be used by force user. */ - pstring_sub(fuser,"%S",service); + pstring_sub(fuser,"%S",lp_servicename(snum)); - pass2 = (struct passwd *)Get_Pwnam_Modify(fuser); + pass2 = (struct passwd *)Get_Pwnam(fuser); if (pass2) { conn->uid = pass2->pw_uid; conn->gid = pass2->pw_gid; - string_set(&conn->user,fuser); - fstrcpy(user,fuser); + string_set(&conn->user,pass2->pw_name); + fstrcpy(user,pass2->pw_name); conn->force_user = True; - DEBUG(3,("Forced user %s\n",fuser)); + DEBUG(3,("Forced user %s\n",user)); } else { DEBUG(1,("Couldn't find user %s\n",fuser)); + conn_free(conn); + *status = NT_STATUS_NO_SUCH_USER; + return NULL; } } @@ -483,7 +480,7 @@ connection_struct *make_connection(char *service, DATA_BLOB password, BOOL user_must_be_member = False; StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1); - + if (tmp_gname[0] == '+') { user_must_be_member = True; StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2); @@ -491,7 +488,7 @@ connection_struct *make_connection(char *service, DATA_BLOB password, StrnCpy(gname,tmp_gname,sizeof(pstring)-1); } /* default service may be a group name */ - pstring_sub(gname,"%S",service); + pstring_sub(gname,"%S",lp_servicename(snum)); gid = nametogid(gname); if (gid != (gid_t)-1) { @@ -512,6 +509,9 @@ connection_struct *make_connection(char *service, DATA_BLOB password, } } else { DEBUG(1,("Couldn't find group %s\n",gname)); + conn_free(conn); + *status = NT_STATUS_NO_SUCH_GROUP; + return NULL; } } #endif /* HAVE_GETGRNAM */ @@ -519,7 +519,7 @@ connection_struct *make_connection(char *service, DATA_BLOB password, { pstring s; pstrcpy(s,lp_pathname(snum)); - standard_sub_conn(conn,s); + standard_sub_conn(conn,s,sizeof(s)); string_set(&conn->connectpath,s); DEBUG(3,("Connect path is %s\n",s)); } @@ -531,7 +531,7 @@ connection_struct *make_connection(char *service, DATA_BLOB password, /* Find all the groups this uid is in and store them. Used by change_to_user() */ initialise_groups(conn->user, conn->uid, conn->gid); - get_current_groups(&conn->ngroups,&conn->groups); + get_current_groups(conn->gid, &conn->ngroups,&conn->groups); conn->nt_user_token = create_nt_token(conn->uid, conn->gid, conn->ngroups, conn->groups, @@ -544,15 +544,15 @@ connection_struct *make_connection(char *service, DATA_BLOB password, */ { - BOOL can_write = share_access_check(conn, snum, vuid, FILE_WRITE_DATA); + BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA); if (!can_write) { - if (!share_access_check(conn, snum, vuid, FILE_READ_DATA)) { + if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) { /* No access, read or write. */ - *status = NT_STATUS_ACCESS_DENIED; DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n", - service )); + lp_servicename(snum))); conn_free(conn); + *status = NT_STATUS_ACCESS_DENIED; return NULL; } else { conn->read_only = True; @@ -564,6 +564,7 @@ connection_struct *make_connection(char *service, DATA_BLOB password, if (!smbd_vfs_init(conn)) { DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn)))); conn_free(conn); + *status = NT_STATUS_UNSUCCESSFUL; return NULL; } @@ -574,8 +575,8 @@ connection_struct *make_connection(char *service, DATA_BLOB password, lp_max_connections(SNUM(conn)), False)) { DEBUG(1,("too many connections - rejected\n")); - *status = NT_STATUS_INSUFFICIENT_RESOURCES; conn_free(conn); + *status = NT_STATUS_INSUFFICIENT_RESOURCES; return NULL; } @@ -585,7 +586,7 @@ connection_struct *make_connection(char *service, DATA_BLOB password, int ret; pstring cmd; pstrcpy(cmd,lp_rootpreexec(SNUM(conn))); - standard_sub_conn(conn,cmd); + standard_sub_conn(conn,cmd,sizeof(cmd)); DEBUG(5,("cmd=%s\n",cmd)); ret = smbrun(cmd,NULL); if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) { @@ -605,16 +606,16 @@ connection_struct *make_connection(char *service, DATA_BLOB password, *status = NT_STATUS_LOGON_FAILURE; return NULL; } - + /* Remember that a different vuid can connect later without these checks... */ - + /* Preexecs are done here as they might make the dir we are to ChDir to below */ /* execute any "preexec = " line */ if (*lp_preexec(SNUM(conn))) { int ret; pstring cmd; pstrcpy(cmd,lp_preexec(SNUM(conn))); - standard_sub_conn(conn,cmd); + standard_sub_conn(conn,cmd,sizeof(cmd)); ret = smbrun(cmd,NULL); if (ret != 0 && lp_preexec_close(SNUM(conn))) { DEBUG(1,("preexec gave %d - failing connection\n", ret)); @@ -625,7 +626,12 @@ connection_struct *make_connection(char *service, DATA_BLOB password, return NULL; } } - + +#if CHECK_PATH_ON_TCONX + /* win2000 does not check the permissions on the directory + during the tree connect, instead relying on permission + check during individual operations. To match this behaviour + I have disabled this chdir check (tridge) */ if (vfs_ChDir(conn,conn->connectpath) != 0) { DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n", remote_machine, conn->client_address, @@ -636,12 +642,23 @@ connection_struct *make_connection(char *service, DATA_BLOB password, *status = NT_STATUS_BAD_NETWORK_NAME; return NULL; } +#else + /* the alternative is just to check the directory exists */ + if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) { + DEBUG(0,("%s is not a directory\n", conn->connectpath)); + change_to_root_user(); + yield_connection(conn, lp_servicename(SNUM(conn))); + conn_free(conn); + *status = NT_STATUS_BAD_NETWORK_NAME; + return NULL; + } +#endif string_set(&conn->origpath,conn->connectpath); #if SOFTLINK_OPTIMISATION - /* resolve any soft links early */ - { + /* resolve any soft links early if possible */ + if (vfs_ChDir(conn,conn->connectpath) == 0) { pstring s; pstrcpy(s,conn->connectpath); vfs_GetWd(conn,s); @@ -674,11 +691,11 @@ connection_struct *make_connection(char *service, DATA_BLOB password, /* Invoke VFS make connection hook */ if (conn->vfs_ops.connect) { - if (conn->vfs_ops.connect(conn, service, user) < 0) { + if (conn->vfs_ops.connect(conn, lp_servicename(snum), user) < 0) { DEBUG(0,("make_connection: VFS make connection failed!\n")); - *status = NT_STATUS_UNSUCCESSFUL; change_to_root_user(); conn_free(conn); + *status = NT_STATUS_UNSUCCESSFUL; return NULL; } } @@ -689,6 +706,130 @@ connection_struct *make_connection(char *service, DATA_BLOB password, return(conn); } +/*************************************************************************************** + Simple wrapper function for make_connection() to include a call to + vfs_chdir() + **************************************************************************************/ + +connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, + char *dev, uint16 vuid, NTSTATUS *status) +{ + connection_struct *conn = NULL; + + conn = make_connection(service_in, password, dev, vuid, status); + + /* + * make_connection() does not change the directory for us any more + * so we have to do it as a separate step --jerry + */ + + if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) { + DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n", + conn->connectpath,strerror(errno))); + yield_connection(conn, lp_servicename(SNUM(conn))); + conn_free(conn); + *status = NT_STATUS_UNSUCCESSFUL; + return NULL; + } + + return conn; +} + +/**************************************************************************** + Make a connection to a service. + * + * @param service +****************************************************************************/ + +connection_struct *make_connection(const char *service_in, DATA_BLOB password, + char *dev, uint16 vuid, NTSTATUS *status) +{ + uid_t euid; + user_struct *vuser = NULL; + pstring service; + int snum = -1; + + /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */ + if (!non_root_mode() && (euid = geteuid()) != 0) { + DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid )); + smb_panic("make_connection: PANIC ERROR. Called as nonroot\n"); + } + + if(lp_security() != SEC_SHARE) { + vuser = get_valid_user_struct(vuid); + if (!vuser) { + DEBUG(1,("make_connection: refusing to connect with no session setup\n")); + return NULL; + } + } + + /* Logic to try and connect to the correct [homes] share, preferably without too many + getpwnam() lookups. This is particulary nasty for winbind usernames, where the + share name isn't the same as unix username. + + The snum of the homes share is stored on the vuser at session setup time. + */ + + if (strequal(service_in,HOMES_NAME)) { + if(lp_security() != SEC_SHARE) { + DATA_BLOB no_pw = data_blob(NULL, 0); + if (vuser->homes_snum != -1) { + DEBUG(5, ("making a connection to [homes] service created at session setup time\n")); + return make_connection_snum(vuser->homes_snum, + vuser, no_pw, + dev, status); + } + } else { + /* Security = share. Try with current_user_info.smb_name + * as the username. */ + if (*current_user_info.smb_name) { + fstring unix_username; + fstrcpy(unix_username, + current_user_info.smb_name); + map_username(unix_username); + snum = find_service(unix_username); + } + if (snum != -1) { + DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in)); + return make_connection_snum(snum, NULL, + password, + dev, status); + } + } + } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1) + && strequal(service, lp_servicename(vuser->homes_snum))) { + DATA_BLOB no_pw = data_blob(NULL, 0); + DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service)); + return make_connection_snum(vuser->homes_snum, + vuser, no_pw, + dev, status); + } + + pstrcpy(service, service_in); + + strlower(service); + + snum = find_service(service); + + if (snum < 0) { + if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) { + DEBUG(3,("refusing IPC connection to %s\n", service)); + *status = NT_STATUS_ACCESS_DENIED; + return NULL; + } + + DEBUG(0,("%s (%s) couldn't find service %s\n", + remote_machine, client_addr(), service)); + *status = NT_STATUS_BAD_NETWORK_NAME; + return NULL; + } + + DEBUG(5, ("making a connection to 'normal' service %s\n", service)); + + return make_connection_snum(snum, vuser, + password, + dev, status); +} /**************************************************************************** close a cnum @@ -721,7 +862,7 @@ void close_cnum(connection_struct *conn, uint16 vuid) change_to_user(conn, vuid)) { pstring cmd; pstrcpy(cmd,lp_postexec(SNUM(conn))); - standard_sub_conn(conn,cmd); + standard_sub_conn(conn,cmd,sizeof(cmd)); smbrun(cmd,NULL); change_to_root_user(); } @@ -731,8 +872,12 @@ void close_cnum(connection_struct *conn, uint16 vuid) if (*lp_rootpostexec(SNUM(conn))) { pstring cmd; pstrcpy(cmd,lp_rootpostexec(SNUM(conn))); - standard_sub_conn(conn,cmd); + standard_sub_conn(conn,cmd,sizeof(cmd)); smbrun(cmd,NULL); } + + /* make sure we leave the directory available for unmount */ + vfs_ChDir(conn, "/"); + conn_free(conn); } diff --git a/source3/smbd/session.c b/source3/smbd/session.c index 05a7b24da28..dade953ec1a 100644 --- a/source3/smbd/session.c +++ b/source3/smbd/session.c @@ -163,16 +163,54 @@ void session_yield(user_struct *vuser) tdb_delete(tdb, key); } -BOOL session_traverse(int (*fn)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *), void *state) +static BOOL session_traverse(int (*fn)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *), void *state) { - if (!tdb) { - DEBUG(3, ("No tdb opened\n")); - return False; - } + if (!tdb) { + DEBUG(3, ("No tdb opened\n")); + return False; + } - tdb_traverse(tdb, fn, state); - return True; + tdb_traverse(tdb, fn, state); + return True; } +struct session_list { + int count; + struct sessionid *sessions; +}; + +static int gather_sessioninfo(TDB_CONTEXT *stdb, TDB_DATA kbuf, TDB_DATA dbuf, + void *state) +{ + struct session_list *sesslist = (struct session_list *) state; + const struct sessionid *current = (const struct sessionid *) dbuf.dptr; + + sesslist->count += 1; + sesslist->sessions = REALLOC(sesslist->sessions, sesslist->count * + sizeof(struct sessionid)); + + memcpy(&sesslist->sessions[sesslist->count - 1], current, + sizeof(struct sessionid)); + DEBUG(7,("gather_sessioninfo session from %s@%s\n", + current->username, current->remote_machine)); + return 0; +} +int list_sessions(struct sessionid **session_list) +{ + struct session_list sesslist; + + sesslist.count = 0; + sesslist.sessions = NULL; + + if (!session_traverse(gather_sessioninfo, (void *) &sesslist)) { + DEBUG(3, ("Session traverse failed\n")); + SAFE_FREE(sesslist.sessions); + *session_list = NULL; + return 0; + } + *session_list = sesslist.sessions; + return sesslist.count; +} + diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 899c9174b22..867b00ff5cc 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -120,7 +120,7 @@ static int reply_spnego_kerberos(connection_struct *conn, return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - ads = ads_init(NULL, NULL, NULL, NULL); + ads = ads_init_simple(); ret = ads_verify_ticket(ads, &ticket, &client, &auth_data); if (!NT_STATUS_IS_OK(ret)) { @@ -235,11 +235,12 @@ static int reply_spnego_negotiate(connection_struct *conn, char *OIDs[ASN1_MAX_OIDS]; DATA_BLOB secblob; int i; - uint32 ntlmssp_command, neg_flags; - DATA_BLOB sess_key, chal, spnego_chal; + uint32 ntlmssp_command, neg_flags, chal_flags; + DATA_BLOB chal, spnego_chal, extra_data; const uint8 *cryptkey; BOOL got_kerberos = False; NTSTATUS nt_status; + extern pstring global_myname; /* parse out the OIDs and the first sec blob */ if (!parse_negTokenTarg(blob1, OIDs, &secblob)) { @@ -274,18 +275,23 @@ static int reply_spnego_negotiate(connection_struct *conn, "NTLMSSP", &ntlmssp_command, &neg_flags, - &sess_key)) { + &extra_data)) { return ERROR_NT(NT_STATUS_LOGON_FAILURE); } + + DEBUG(5, ("Extra data: \n")); + dump_data(5, extra_data.data, extra_data.length); data_blob_free(&secblob); - data_blob_free(&sess_key); + data_blob_free(&extra_data); if (ntlmssp_command != NTLMSSP_NEGOTIATE) { return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - DEBUG(3,("Got neg_flags=%08x\n", neg_flags)); + DEBUG(3,("Got neg_flags=0x%08x\n", neg_flags)); + + debug_ntlmssp_flags(neg_flags); if (ntlmssp_auth_context) { (ntlmssp_auth_context->free)(&ntlmssp_auth_context); @@ -300,22 +306,47 @@ static int reply_spnego_negotiate(connection_struct *conn, /* Give them the challenge. For now, ignore neg_flags and just return the flags we want. Obviously this is not correct */ - neg_flags = NTLMSSP_NEGOTIATE_UNICODE | + chal_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_LM_KEY | - NTLMSSP_NEGOTIATE_NTLM; - - msrpc_gen(&chal, "Cddddbdddd", - "NTLMSSP", - NTLMSSP_CHALLENGE, - 0, - 0x30, /* ?? */ - neg_flags, - cryptkey, 8, - 0, 0, 0, - 0x3000); /* ?? */ + NTLMSSP_NEGOTIATE_NTLM | + NTLMSSP_CHAL_TARGET_INFO; + + { + DATA_BLOB domain_blob, netbios_blob, realm_blob; + + msrpc_gen(&domain_blob, + "U", + lp_workgroup()); + + msrpc_gen(&netbios_blob, + "U", + global_myname); + + msrpc_gen(&realm_blob, + "U", + lp_realm()); + + + msrpc_gen(&chal, "CddddbBBBB", + "NTLMSSP", + NTLMSSP_CHALLENGE, + 0, + 0x30, /* ?? */ + chal_flags, + cryptkey, 8, + domain_blob.data, domain_blob.length, + domain_blob.data, domain_blob.length, + netbios_blob.data, netbios_blob.length, + realm_blob.data, realm_blob.length); + + data_blob_free(&domain_blob); + data_blob_free(&netbios_blob); + data_blob_free(&realm_blob); + } if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) { DEBUG(3,("Failed to generate challenge\n")); + data_blob_free(&chal); return ERROR_NT(NT_STATUS_LOGON_FAILURE); } @@ -346,10 +377,15 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, int sess_vuid; BOOL as_guest; uint32 auth_flags = AUTH_FLAG_NONE; - auth_usersupplied_info *user_info = NULL; auth_serversupplied_info *server_info = NULL; + /* we must have setup the auth context by now */ + if (!ntlmssp_auth_context) { + DEBUG(2,("ntlmssp_auth_context is NULL in reply_spnego_auth\n")); + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } + if (!spnego_parse_auth(blob1, &auth)) { #if 0 file_save("auth.dat", blob1.data, blob1.length); @@ -606,7 +642,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, plaintext_password.data[passlen1] = 0; } - srvstr_pull(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), -1, STR_TERMINATE); + srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE); *domain = 0; } else { @@ -669,14 +705,10 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, } p += passlen1 + passlen2; - p += srvstr_pull(inbuf, user, p, sizeof(user), -1, - STR_TERMINATE); - p += srvstr_pull(inbuf, domain, p, sizeof(domain), - -1, STR_TERMINATE); - p += srvstr_pull(inbuf, native_os, p, sizeof(native_os), - -1, STR_TERMINATE); - p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman), - -1, STR_TERMINATE); + p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE); + p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE); + p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE); + p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE); DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n", domain,native_os,native_lanman)); } diff --git a/source3/smbd/srvstr.c b/source3/smbd/srvstr.c index 90da422f133..36fecf5bd2e 100644 --- a/source3/smbd/srvstr.c +++ b/source3/smbd/srvstr.c @@ -30,3 +30,12 @@ int srvstr_pull(void *base_ptr, char *dest, const void *src, int dest_len, int s { return pull_string(base_ptr, dest, src, dest_len, src_len, flags); } + +/* pull a string from the smb_buf part of a packet. In this case the + string can either be null terminated or it can be terminated by the + end of the smbbuf area +*/ +int srvstr_pull_buf(void *inbuf, char *dest, const void *src, int dest_len, int flags) +{ + return pull_string(inbuf, dest, src, dest_len, smb_bufrem(inbuf, src), flags); +} diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 1972e9c8c8e..f1dfb39aacf 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -37,255 +37,261 @@ extern pstring global_myname; HACK ! Always assumes smb_setup field is zero. ****************************************************************************/ -static int send_trans2_replies(char *outbuf, int bufsize, char *params, - int paramsize, char *pdata, int datasize) +static int send_trans2_replies(char *outbuf, + int bufsize, + char *params, + int paramsize, + char *pdata, + int datasize) { - /* As we are using a protocol > LANMAN1 then the max_send - variable must have been set in the sessetupX call. - This takes precedence over the max_xmit field in the - global struct. These different max_xmit variables should - be merged as this is now too confusing */ - - extern int max_send; - int data_to_send = datasize; - int params_to_send = paramsize; - int useable_space; - char *pp = params; - char *pd = pdata; - int params_sent_thistime, data_sent_thistime, total_sent_thistime; - int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */ - int data_alignment_offset = 0; - - /* Initially set the wcnt area to be 10 - this is true for all - trans2 replies */ - set_message(outbuf,10,0,True); - - /* If there genuinely are no parameters or data to send just send - the empty packet */ - if(params_to_send == 0 && data_to_send == 0) - { - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_trans2_replies: send_smb failed."); - return 0; - } - - /* When sending params and data ensure that both are nicely aligned */ - /* Only do this alignment when there is also data to send - else - can cause NT redirector problems. */ - if (((params_to_send % 4) != 0) && (data_to_send != 0)) - data_alignment_offset = 4 - (params_to_send % 4); - - /* Space is bufsize minus Netbios over TCP header minus SMB header */ - /* The alignment_offset is to align the param bytes on an even byte - boundary. NT 4.0 Beta needs this to work correctly. */ - useable_space = bufsize - ((smb_buf(outbuf)+ - alignment_offset+data_alignment_offset) - - outbuf); - - /* useable_space can never be more than max_send minus the - alignment offset. */ - useable_space = MIN(useable_space, - max_send - (alignment_offset+data_alignment_offset)); - - - while (params_to_send || data_to_send) - { - /* Calculate whether we will totally or partially fill this packet */ - total_sent_thistime = params_to_send + data_to_send + - alignment_offset + data_alignment_offset; - /* We can never send more than useable_space */ - /* - * Note that 'useable_space' does not include the alignment offsets, - * but we must include the alignment offsets in the calculation of - * the length of the data we send over the wire, as the alignment offsets - * are sent here. Fix from Marc_Jacobsen@hp.com. - */ - total_sent_thistime = MIN(total_sent_thistime, useable_space+ - alignment_offset + data_alignment_offset); - - set_message(outbuf, 10, total_sent_thistime, True); - - /* Set total params and data to be sent */ - SSVAL(outbuf,smb_tprcnt,paramsize); - SSVAL(outbuf,smb_tdrcnt,datasize); - - /* Calculate how many parameters and data we can fit into - this packet. Parameters get precedence */ - - params_sent_thistime = MIN(params_to_send,useable_space); - data_sent_thistime = useable_space - params_sent_thistime; - data_sent_thistime = MIN(data_sent_thistime,data_to_send); - - SSVAL(outbuf,smb_prcnt, params_sent_thistime); - - /* smb_proff is the offset from the start of the SMB header to the - parameter bytes, however the first 4 bytes of outbuf are - the Netbios over TCP header. Thus use smb_base() to subtract - them from the calculation */ - - SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); - - if(params_sent_thistime == 0) - SSVAL(outbuf,smb_prdisp,0); - else - /* Absolute displacement of param bytes sent in this packet */ - SSVAL(outbuf,smb_prdisp,pp - params); - - SSVAL(outbuf,smb_drcnt, data_sent_thistime); - if(data_sent_thistime == 0) - { - SSVAL(outbuf,smb_droff,0); - SSVAL(outbuf,smb_drdisp, 0); - } - else - { - /* The offset of the data bytes is the offset of the - parameter bytes plus the number of parameters being sent this time */ - SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) - - smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); - SSVAL(outbuf,smb_drdisp, pd - pdata); - } - - /* Copy the param bytes into the packet */ - if(params_sent_thistime) - memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); - /* Copy in the data bytes */ - if(data_sent_thistime) - memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ - data_alignment_offset,pd,data_sent_thistime); - - DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", - params_sent_thistime, data_sent_thistime, useable_space)); - DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", - params_to_send, data_to_send, paramsize, datasize)); - - /* Send the packet */ - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_trans2_replies: send_smb failed."); - - pp += params_sent_thistime; - pd += data_sent_thistime; - - params_to_send -= params_sent_thistime; - data_to_send -= data_sent_thistime; - - /* Sanity check */ - if(params_to_send < 0 || data_to_send < 0) - { - DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!", - params_to_send, data_to_send)); - return -1; - } - } - - return 0; + /* As we are using a protocol > LANMAN1 then the max_send + variable must have been set in the sessetupX call. + This takes precedence over the max_xmit field in the + global struct. These different max_xmit variables should + be merged as this is now too confusing */ + + extern int max_send; + int data_to_send = datasize; + int params_to_send = paramsize; + int useable_space; + char *pp = params; + char *pd = pdata; + int params_sent_thistime, data_sent_thistime, total_sent_thistime; + int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */ + int data_alignment_offset = 0; + + /* Initially set the wcnt area to be 10 - this is true for all trans2 replies */ + + set_message(outbuf,10,0,True); + + /* If there genuinely are no parameters or data to send just send the empty packet */ + + if(params_to_send == 0 && data_to_send == 0) { + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("send_trans2_replies: send_smb failed."); + return 0; + } + + /* When sending params and data ensure that both are nicely aligned */ + /* Only do this alignment when there is also data to send - else + can cause NT redirector problems. */ + + if (((params_to_send % 4) != 0) && (data_to_send != 0)) + data_alignment_offset = 4 - (params_to_send % 4); + + /* Space is bufsize minus Netbios over TCP header minus SMB header */ + /* The alignment_offset is to align the param bytes on an even byte + boundary. NT 4.0 Beta needs this to work correctly. */ + + useable_space = bufsize - ((smb_buf(outbuf)+ alignment_offset+data_alignment_offset) - outbuf); + + /* useable_space can never be more than max_send minus the alignment offset. */ + + useable_space = MIN(useable_space, max_send - (alignment_offset+data_alignment_offset)); + + while (params_to_send || data_to_send) { + /* Calculate whether we will totally or partially fill this packet */ + + total_sent_thistime = params_to_send + data_to_send + alignment_offset + data_alignment_offset; + + /* We can never send more than useable_space */ + /* + * Note that 'useable_space' does not include the alignment offsets, + * but we must include the alignment offsets in the calculation of + * the length of the data we send over the wire, as the alignment offsets + * are sent here. Fix from Marc_Jacobsen@hp.com. + */ + + total_sent_thistime = MIN(total_sent_thistime, useable_space+ alignment_offset + data_alignment_offset); + + set_message(outbuf, 10, total_sent_thistime, True); + + /* Set total params and data to be sent */ + SSVAL(outbuf,smb_tprcnt,paramsize); + SSVAL(outbuf,smb_tdrcnt,datasize); + + /* Calculate how many parameters and data we can fit into + * this packet. Parameters get precedence + */ + + params_sent_thistime = MIN(params_to_send,useable_space); + data_sent_thistime = useable_space - params_sent_thistime; + data_sent_thistime = MIN(data_sent_thistime,data_to_send); + + SSVAL(outbuf,smb_prcnt, params_sent_thistime); + + /* smb_proff is the offset from the start of the SMB header to the + parameter bytes, however the first 4 bytes of outbuf are + the Netbios over TCP header. Thus use smb_base() to subtract + them from the calculation */ + + SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); + + if(params_sent_thistime == 0) + SSVAL(outbuf,smb_prdisp,0); + else + /* Absolute displacement of param bytes sent in this packet */ + SSVAL(outbuf,smb_prdisp,pp - params); + + SSVAL(outbuf,smb_drcnt, data_sent_thistime); + if(data_sent_thistime == 0) { + SSVAL(outbuf,smb_droff,0); + SSVAL(outbuf,smb_drdisp, 0); + } else { + /* The offset of the data bytes is the offset of the + parameter bytes plus the number of parameters being sent this time */ + SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) - + smb_base(outbuf)) + params_sent_thistime + data_alignment_offset); + SSVAL(outbuf,smb_drdisp, pd - pdata); + } + + /* Copy the param bytes into the packet */ + + if(params_sent_thistime) + memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); + + /* Copy in the data bytes */ + if(data_sent_thistime) + memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ + data_alignment_offset,pd,data_sent_thistime); + + DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", + params_sent_thistime, data_sent_thistime, useable_space)); + DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", + params_to_send, data_to_send, paramsize, datasize)); + + /* Send the packet */ + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("send_trans2_replies: send_smb failed."); + + pp += params_sent_thistime; + pd += data_sent_thistime; + + params_to_send -= params_sent_thistime; + data_to_send -= data_sent_thistime; + + /* Sanity check */ + if(params_to_send < 0 || data_to_send < 0) { + DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!", + params_to_send, data_to_send)); + return -1; + } + } + + return 0; } /**************************************************************************** Reply to a TRANSACT2_OPEN. ****************************************************************************/ -static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, - int bufsize, - char **pparams, char **ppdata) +static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - char *params = *pparams; - int16 open_mode = SVAL(params, 2); - int16 open_attr = SVAL(params,6); - BOOL oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1)); + char *params = *pparams; + int16 open_mode; + int16 open_attr; + BOOL oplock_request; +#if 0 + BOOL return_additional_info; + int16 open_sattr; + time_t open_time; +#endif + int16 open_ofun; + int32 open_size; + char *pname; + pstring fname; + mode_t unixmode; + SMB_OFF_T size=0; + int fmode=0,mtime=0,rmode; + SMB_INO_T inode = 0; + SMB_STRUCT_STAT sbuf; + int smb_action = 0; + BOOL bad_path = False; + files_struct *fsp; + + /* + * Ensure we have enough parameters to perform the operation. + */ + + if (total_params < 29) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + open_mode = SVAL(params, 2); + open_attr = SVAL(params,6); + oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1)); #if 0 - BOOL return_additional_info = BITSETW(params,0); - int16 open_sattr = SVAL(params, 4); - time_t open_time = make_unix_date3(params+8); + return_additional_info = BITSETW(params,0); + open_sattr = SVAL(params, 4); + open_time = make_unix_date3(params+8); #endif - int16 open_ofun = SVAL(params,12); - int32 open_size = IVAL(params,14); - char *pname = ¶ms[28]; - pstring fname; - mode_t unixmode; - SMB_OFF_T size=0; - int fmode=0,mtime=0,rmode; - SMB_INO_T inode = 0; - SMB_STRUCT_STAT sbuf; - int smb_action = 0; - BOOL bad_path = False; - files_struct *fsp; - - srvstr_pull(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE); - - DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n", - fname,open_mode, open_attr, open_ofun, open_size)); - - if (IS_IPC(conn)) { + open_ofun = SVAL(params,12); + open_size = IVAL(params,14); + pname = ¶ms[28]; + + srvstr_pull(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE); + + DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n", + fname,open_mode, open_attr, open_ofun, open_size)); + + if (IS_IPC(conn)) return(ERROR_DOS(ERRSRV,ERRaccess)); - } - /* XXXX we need to handle passed times, sattr and flags */ + /* XXXX we need to handle passed times, sattr and flags */ - unix_convert(fname,conn,0,&bad_path,&sbuf); + unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn)) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - unixmode = unix_mode(conn,open_attr | aARCH, fname); + if (!check_name(fname,conn)) { + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + unixmode = unix_mode(conn,open_attr | aARCH, fname); - fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode, - oplock_request, &rmode,&smb_action); + fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode, + oplock_request, &rmode,&smb_action); - if (!fsp) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - size = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - mtime = sbuf.st_mtime; - inode = sbuf.st_ino; - if (fmode & aDIR) { - close_file(fsp,False); - return(ERROR_DOS(ERRDOS,ERRnoaccess)); - } - - /* Realloc the size of parameters and data we will return */ - params = Realloc(*pparams, 28); - if( params == NULL ) { - return(ERROR_DOS(ERRDOS,ERRnomem)); - } - *pparams = params; - - memset((char *)params,'\0',28); - SSVAL(params,0,fsp->fnum); - SSVAL(params,2,fmode); - put_dos_date2(params,4, mtime); - SIVAL(params,8, (uint32)size); - SSVAL(params,12,rmode); - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) { - smb_action |= EXTENDED_OPLOCK_GRANTED; - } - - SSVAL(params,18,smb_action); - /* - * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes. - */ - SIVAL(params,20,inode); + if (!fsp) { + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + size = sbuf.st_size; + fmode = dos_mode(conn,fname,&sbuf); + mtime = sbuf.st_mtime; + inode = sbuf.st_ino; + if (fmode & aDIR) { + close_file(fsp,False); + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + } + + /* Realloc the size of parameters and data we will return */ + params = Realloc(*pparams, 28); + if( params == NULL ) + return(ERROR_DOS(ERRDOS,ERRnomem)); + *pparams = params; + + memset((char *)params,'\0',28); + SSVAL(params,0,fsp->fnum); + SSVAL(params,2,fmode); + put_dos_date2(params,4, mtime); + SIVAL(params,8, (uint32)size); + SSVAL(params,12,rmode); + + if (oplock_request && lp_fake_oplocks(SNUM(conn))) + smb_action |= EXTENDED_OPLOCK_GRANTED; + + SSVAL(params,18,smb_action); + + /* + * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes. + */ + SIVAL(params,20,inode); - /* Send the required number of replies */ - send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0); + /* Send the required number of replies */ + send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0); - return -1; + return -1; } /********************************************************* @@ -304,10 +310,6 @@ static BOOL exact_match(char *str,char *mask, BOOL case_sig) return strcasecmp(str,mask) == 0; } -#if 0 - -Not finished yet - jra. - /**************************************************************************** Return the filetype for UNIX extensions. ****************************************************************************/ @@ -370,35 +372,63 @@ static uint32 unix_dev_minor(SMB_DEV_T dev) } /**************************************************************************** - Map standard UNIX permissions onto wire representations. + Map wire perms onto standard UNIX permissions. Obey share restrictions. ****************************************************************************/ -static uint32 unix_perms_to_wire(mode_t perms) +static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *pst, uint32 perms) { - uint ret = 0; - - ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0); - ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0); - ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0); - ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0); - ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0); - ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0); - ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0); - ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0); - ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0); + mode_t ret = 0; + + if (perms == SMB_MODE_NO_CHANGE) + return pst->st_mode; + + ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0); + ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0); + ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0); + ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0); + ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0); + ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0); + ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0); + ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0); + ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0); #ifdef S_ISVTX - ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0); + ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0); #endif #ifdef S_ISGID - ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0); + ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0); #endif #ifdef S_ISUID - ret |= ((perms & S_ISVTX) ? UNIX_SET_UID : 0); + ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0); #endif + + if (VALID_STAT(*pst) && S_ISDIR(pst->st_mode)) { + ret &= lp_dir_mask(SNUM(conn)); + /* Add in force bits */ + ret |= lp_force_dir_mode(SNUM(conn)); + } else { + /* Apply mode mask */ + ret &= lp_create_mask(SNUM(conn)); + /* Add in force bits */ + ret |= lp_force_create_mode(SNUM(conn)); + } + return ret; } -#endif +/**************************************************************************** +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")); + if(IVAL(p,0) == SMB_TIME_NO_CHANGE_LO && + IVAL(p,4) == SMB_TIME_NO_CHANGE_HI) { + return -1; + } else { + return interpret_long_date(p); + } +} /**************************************************************************** Get a level dependent lanman2 dir entry. @@ -508,16 +538,23 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, continue; } } else if (vfs_stat(conn,pathreal,&sbuf) != 0) { - /* Needed to show the msdfs symlinks as directories */ - if(!lp_host_msdfs() || !lp_msdfs_root(SNUM(conn)) - || !is_msdfs_link(conn, pathreal)) { + + /* Needed to show the msdfs symlinks as + * directories */ + + if(lp_host_msdfs() && + lp_msdfs_root(SNUM(conn)) && + is_msdfs_link(conn, pathreal, NULL, NULL, + &sbuf)) { + + DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal)); + sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR; + + } else { + DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n", - pathreal,strerror(errno))); + pathreal,strerror(errno))); continue; - } else { - DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", - pathreal)); - sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR; } } @@ -557,7 +594,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL; switch (info_level) { - case 1: + case SMB_INFO_STANDARD: if(requires_resume_key) { SIVAL(p,0,reskey); p += 4; @@ -576,7 +613,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, p += len; break; - case 2: + case SMB_INFO_QUERY_EA_SIZE: if(requires_resume_key) { SIVAL(p,0,reskey); p += 4; @@ -693,14 +730,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, /* CIFS UNIX Extension. */ -#if 0 /* JRA - FIXME - NEEDS UNICODE CONVERSION !!! */ case SMB_FIND_FILE_UNIX: - - len = 108+strlen(fname)+1; /* (length of SMB_QUERY_FILE_UNIX_BASIC = 100)+4+4+strlen(fname)*/ - /* +1 to be sure to transmit the termination of fname */ - len = (len + 3) & ~3; - - SIVAL(p,0,len); p+= 4; /* Offset from this structure to the beginning of the next one */ + p+= 4; SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */ /* Begin of SMB_QUERY_FILE_UNIX_BASIC */ @@ -750,12 +781,16 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, SIVAL(p,4,0); p+= 8; + len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE); + p += len; + + len = PTR_DIFF(p, pdata); + len = (len + 3) & ~3; + SIVAL(pdata,0,len); /* Offset from this structure to the beginning of the next one */ + p = pdata + len; /* End of SMB_QUERY_FILE_UNIX_BASIC */ - pstrcpy(p,fname); - p=pdata+len; break; -#endif default: return(False); @@ -782,612 +817,664 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, Reply to a TRANS2_FINDFIRST. ****************************************************************************/ -static int call_trans2findfirst(connection_struct *conn, - char *inbuf, char *outbuf, int bufsize, - char **pparams, char **ppdata) +static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - /* We must be careful here that we don't return more than the - allowed number of data bytes. If this means returning fewer than - maxentries then so be it. We assume that the redirector has - enough room for the fixed number of parameter bytes it has - requested. */ - uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *params = *pparams; - char *pdata = *ppdata; - int dirtype = SVAL(params,0); - int maxentries = SVAL(params,2); - BOOL close_after_first = BITSETW(params+4,0); - BOOL close_if_end = BITSETW(params+4,1); - BOOL requires_resume_key = BITSETW(params+4,2); - int info_level = SVAL(params,6); - pstring directory; - pstring mask; - char *p, *wcard; - int last_name_off=0; - int dptr_num = -1; - int numentries = 0; - int i; - BOOL finished = False; - BOOL dont_descend = False; - BOOL out_of_space = False; - int space_remaining; - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - - *directory = *mask = 0; - - DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n", - dirtype, maxentries, close_after_first, close_if_end, requires_resume_key, - info_level, max_data_bytes)); + /* We must be careful here that we don't return more than the + allowed number of data bytes. If this means returning fewer than + maxentries then so be it. We assume that the redirector has + enough room for the fixed number of parameter bytes it has + requested. */ + uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt); + char *params = *pparams; + char *pdata = *ppdata; + int dirtype = SVAL(params,0); + int maxentries = SVAL(params,2); + BOOL close_after_first = BITSETW(params+4,0); + BOOL close_if_end = BITSETW(params+4,1); + BOOL requires_resume_key = BITSETW(params+4,2); + int info_level = SVAL(params,6); + pstring directory; + pstring mask; + char *p, *wcard; + int last_name_off=0; + int dptr_num = -1; + int numentries = 0; + int i; + BOOL finished = False; + BOOL dont_descend = False; + BOOL out_of_space = False; + int space_remaining; + BOOL bad_path = False; + SMB_STRUCT_STAT sbuf; + + if (total_params < 12) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + *directory = *mask = 0; + + DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, \ +close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n", + dirtype, maxentries, close_after_first, close_if_end, requires_resume_key, + info_level, max_data_bytes)); - switch (info_level) - { - case 1: - case 2: - case 3: - case 4: - case SMB_FIND_FILE_DIRECTORY_INFO: - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - case SMB_FIND_FILE_NAMES_INFO: - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - break; - default: - return(ERROR_DOS(ERRDOS,ERRunknownlevel)); - } - - srvstr_pull(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE); - - RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf); - - unix_convert(directory,conn,0,&bad_path,&sbuf); - if(!check_name(directory,conn)) { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + switch (info_level) { + case SMB_INFO_STANDARD: + case SMB_INFO_QUERY_EA_SIZE: + case SMB_FIND_FILE_DIRECTORY_INFO: + case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + case SMB_FIND_FILE_NAMES_INFO: + case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + break; + case SMB_FIND_FILE_UNIX: + if (!lp_unix_extensions()) + return(ERROR_DOS(ERRDOS,ERRunknownlevel)); + break; + default: + return(ERROR_DOS(ERRDOS,ERRunknownlevel)); + } -#if 0 - /* Ugly - NT specific hack - maybe not needed ? (JRA) */ - if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && - (get_remote_arch() == RA_WINNT)) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbaddirectory; - } -#endif - - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - - p = strrchr_m(directory,'/'); - if(p == NULL) { - pstrcpy(mask,directory); - pstrcpy(directory,"./"); - } else { - pstrcpy(mask,p+1); - *p = 0; - } - - DEBUG(5,("dir=%s, mask = %s\n",directory, mask)); - - pdata = Realloc(*ppdata, max_data_bytes + 1024); - if( pdata == NULL ) { - return(ERROR_DOS(ERRDOS,ERRnomem)); - } - *ppdata = pdata; - memset((char *)pdata,'\0',max_data_bytes + 1024); - - /* Realloc the params space */ - params = Realloc(*pparams, 10); - if (params == NULL) { - return ERROR_DOS(ERRDOS,ERRnomem); - } - *pparams = params; - - dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid)); - if (dptr_num < 0) - return(UNIXERROR(ERRDOS,ERRbadfile)); - - /* Save the wildcard match and attribs we are using on this directory - - needed as lanman2 assumes these are being saved between calls */ - - if(!(wcard = strdup(mask))) { - dptr_close(&dptr_num); - return ERROR_DOS(ERRDOS,ERRnomem); - } - - dptr_set_wcard(dptr_num, wcard); - dptr_set_attr(dptr_num, dirtype); - - DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype)); - - /* We don't need to check for VOL here as this is returned by - a different TRANS2 call. */ + srvstr_pull(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE); + + RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf); + + unix_convert(directory,conn,0,&bad_path,&sbuf); + if(!check_name(directory,conn)) { + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + + p = strrchr_m(directory,'/'); + if(p == NULL) { + pstrcpy(mask,directory); + pstrcpy(directory,"./"); + } else { + pstrcpy(mask,p+1); + *p = 0; + } + + DEBUG(5,("dir=%s, mask = %s\n",directory, mask)); + + pdata = Realloc(*ppdata, max_data_bytes + 1024); + if( pdata == NULL ) + return(ERROR_DOS(ERRDOS,ERRnomem)); + + *ppdata = pdata; + memset((char *)pdata,'\0',max_data_bytes + 1024); + + /* Realloc the params space */ + params = Realloc(*pparams, 10); + if (params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + *pparams = params; + + dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid)); + if (dptr_num < 0) + return(UNIXERROR(ERRDOS,ERRbadfile)); + + /* Save the wildcard match and attribs we are using on this directory - + needed as lanman2 assumes these are being saved between calls */ + + if(!(wcard = strdup(mask))) { + dptr_close(&dptr_num); + return ERROR_DOS(ERRDOS,ERRnomem); + } + + dptr_set_wcard(dptr_num, wcard); + dptr_set_attr(dptr_num, dirtype); + + DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype)); + + /* We don't need to check for VOL here as this is returned by + a different TRANS2 call. */ - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", - conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) - dont_descend = True; + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn)))); + if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) + dont_descend = True; - p = pdata; - space_remaining = max_data_bytes; - out_of_space = False; - - for (i=0;(i<maxentries) && !finished && !out_of_space;i++) - { - BOOL got_exact_match = False; - - /* this is a heuristic to avoid seeking the dirptr except when - absolutely necessary. It allows for a filename of about 40 chars */ - if (space_remaining < DIRLEN_GUESS && numentries > 0) - { - out_of_space = True; - finished = False; - } - else - { - finished = !get_lanman2_dir_entry(conn, + p = pdata; + space_remaining = max_data_bytes; + out_of_space = False; + + for (i=0;(i<maxentries) && !finished && !out_of_space;i++) { + BOOL got_exact_match = False; + + /* this is a heuristic to avoid seeking the dirptr except when + absolutely necessary. It allows for a filename of about 40 chars */ + if (space_remaining < DIRLEN_GUESS && numentries > 0) { + out_of_space = True; + finished = False; + } else { + finished = !get_lanman2_dir_entry(conn, inbuf, outbuf, mask,dirtype,info_level, requires_resume_key,dont_descend, &p,pdata,space_remaining, &out_of_space, &got_exact_match, &last_name_off); - } + } - if (finished && out_of_space) - finished = False; + if (finished && out_of_space) + finished = False; - if (!finished && !out_of_space) - numentries++; + if (!finished && !out_of_space) + numentries++; - /* - * As an optimisation if we know we aren't looking - * for a wildcard name (ie. the name matches the wildcard exactly) - * then we can finish on any (first) match. - * This speeds up large directory searches. JRA. - */ + /* + * As an optimisation if we know we aren't looking + * for a wildcard name (ie. the name matches the wildcard exactly) + * then we can finish on any (first) match. + * This speeds up large directory searches. JRA. + */ - if(got_exact_match) - finished = True; + if(got_exact_match) + finished = True; - space_remaining = max_data_bytes - PTR_DIFF(p,pdata); - } + space_remaining = max_data_bytes - PTR_DIFF(p,pdata); + } - /* Check if we can close the dirptr */ - if(close_after_first || (finished && close_if_end)) - { - DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num)); - dptr_close(&dptr_num); - } - - /* - * If there are no matching entries we must return ERRDOS/ERRbadfile - - * from observation of NT. - */ - - if(numentries == 0) { - dptr_close(&dptr_num); - return ERROR_DOS(ERRDOS,ERRbadfile); - } - - /* At this point pdata points to numentries directory entries. */ - - /* Set up the return parameter block */ - SSVAL(params,0,dptr_num); - SSVAL(params,2,numentries); - SSVAL(params,4,finished); - SSVAL(params,6,0); /* Never an EA error */ - SSVAL(params,8,last_name_off); - - send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata)); - - if ((! *directory) && dptr_path(dptr_num)) - slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); - - DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", - smb_fn_name(CVAL(inbuf,smb_com)), - mask, directory, dirtype, numentries ) ); - - /* - * Force a name mangle here to ensure that the - * mask as an 8.3 name is top of the mangled cache. - * The reasons for this are subtle. Don't remove - * this code unless you know what you are doing - * (see PR#13758). JRA. - */ - - if(!mangle_is_8_3( mask, False)) - mangle_map(mask, True, True, SNUM(conn)); - - return(-1); + /* Check if we can close the dirptr */ + if(close_after_first || (finished && close_if_end)) { + DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num)); + dptr_close(&dptr_num); + } + + /* + * If there are no matching entries we must return ERRDOS/ERRbadfile - + * from observation of NT. + */ + + if(numentries == 0) { + dptr_close(&dptr_num); + return ERROR_DOS(ERRDOS,ERRbadfile); + } + + /* At this point pdata points to numentries directory entries. */ + + /* Set up the return parameter block */ + SSVAL(params,0,dptr_num); + SSVAL(params,2,numentries); + SSVAL(params,4,finished); + SSVAL(params,6,0); /* Never an EA error */ + SSVAL(params,8,last_name_off); + + send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata)); + + if ((! *directory) && dptr_path(dptr_num)) + slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); + + DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", + smb_fn_name(CVAL(inbuf,smb_com)), + mask, directory, dirtype, numentries ) ); + + /* + * Force a name mangle here to ensure that the + * mask as an 8.3 name is top of the mangled cache. + * The reasons for this are subtle. Don't remove + * this code unless you know what you are doing + * (see PR#13758). JRA. + */ + + if(!mangle_is_8_3_wildcards( mask, False)) + mangle_map(mask, True, True, SNUM(conn)); + + return(-1); } /**************************************************************************** Reply to a TRANS2_FINDNEXT. ****************************************************************************/ -static int call_trans2findnext(connection_struct *conn, - char *inbuf, char *outbuf, - int length, int bufsize, - char **pparams, char **ppdata) +static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - /* We must be careful here that we don't return more than the - allowed number of data bytes. If this means returning fewer than - maxentries then so be it. We assume that the redirector has - enough room for the fixed number of parameter bytes it has - requested. */ - int max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *params = *pparams; - char *pdata = *ppdata; - int dptr_num = SVAL(params,0); - int maxentries = SVAL(params,2); - uint16 info_level = SVAL(params,4); - uint32 resume_key = IVAL(params,6); - BOOL close_after_request = BITSETW(params+10,0); - BOOL close_if_end = BITSETW(params+10,1); - BOOL requires_resume_key = BITSETW(params+10,2); - BOOL continue_bit = BITSETW(params+10,3); - pstring resume_name; - pstring mask; - pstring directory; - char *p; - uint16 dirtype; - int numentries = 0; - int i, last_name_off=0; - BOOL finished = False; - BOOL dont_descend = False; - BOOL out_of_space = False; - int space_remaining; - - *mask = *directory = *resume_name = 0; - - srvstr_pull(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE); - - DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \ + /* We must be careful here that we don't return more than the + allowed number of data bytes. If this means returning fewer than + maxentries then so be it. We assume that the redirector has + enough room for the fixed number of parameter bytes it has + requested. */ + int max_data_bytes = SVAL(inbuf, smb_mdrcnt); + char *params = *pparams; + char *pdata = *ppdata; + int dptr_num = SVAL(params,0); + int maxentries = SVAL(params,2); + uint16 info_level = SVAL(params,4); + uint32 resume_key = IVAL(params,6); + BOOL close_after_request = BITSETW(params+10,0); + BOOL close_if_end = BITSETW(params+10,1); + BOOL requires_resume_key = BITSETW(params+10,2); + BOOL continue_bit = BITSETW(params+10,3); + pstring resume_name; + pstring mask; + pstring directory; + char *p; + uint16 dirtype; + int numentries = 0; + int i, last_name_off=0; + BOOL finished = False; + BOOL dont_descend = False; + BOOL out_of_space = False; + int space_remaining; + + if (total_params < 12) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + *mask = *directory = *resume_name = 0; + + srvstr_pull(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE); + + DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \ close_after_request=%d, close_if_end = %d requires_resume_key = %d \ resume_key = %d resume name = %s continue=%d level = %d\n", - dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, - requires_resume_key, resume_key, resume_name, continue_bit, info_level)); - - switch (info_level) - { - case 1: - case 2: - case 3: - case 4: - case SMB_FIND_FILE_DIRECTORY_INFO: - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - case SMB_FIND_FILE_NAMES_INFO: - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - break; - default: - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - pdata = Realloc( *ppdata, max_data_bytes + 1024); - if(pdata == NULL) { - return ERROR_DOS(ERRDOS,ERRnomem); - } - *ppdata = pdata; - memset((char *)pdata,'\0',max_data_bytes + 1024); - - /* Realloc the params space */ - params = Realloc(*pparams, 6*SIZEOFWORD); - if( params == NULL ) { - return ERROR_DOS(ERRDOS,ERRnomem); - } - *pparams = params; - - /* Check that the dptr is valid */ - if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) - return ERROR_DOS(ERRDOS,ERRnofiles); - - string_set(&conn->dirpath,dptr_path(dptr_num)); - - /* Get the wildcard mask from the dptr */ - if((p = dptr_wcard(dptr_num))== NULL) { - DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num)); - return ERROR_DOS(ERRDOS,ERRnofiles); - } - pstrcpy(mask, p); - pstrcpy(directory,conn->dirpath); - - /* Get the attr mask from the dptr */ - dirtype = dptr_attr(dptr_num); - - DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n", - dptr_num, mask, dirtype, - (long)conn->dirptr, - TellDir(conn->dirptr))); - - /* We don't need to check for VOL here as this is returned by - a different TRANS2 call. */ - - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) - dont_descend = True; + dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, + requires_resume_key, resume_key, resume_name, continue_bit, info_level)); + + switch (info_level) { + case SMB_INFO_STANDARD: + case SMB_INFO_QUERY_EA_SIZE: + case SMB_FIND_FILE_DIRECTORY_INFO: + case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + case SMB_FIND_FILE_NAMES_INFO: + case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + break; + case SMB_FIND_FILE_UNIX: + if (!lp_unix_extensions()) + return(ERROR_DOS(ERRDOS,ERRunknownlevel)); + break; + default: + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + pdata = Realloc( *ppdata, max_data_bytes + 1024); + if(pdata == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + + *ppdata = pdata; + memset((char *)pdata,'\0',max_data_bytes + 1024); + + /* Realloc the params space */ + params = Realloc(*pparams, 6*SIZEOFWORD); + if( params == NULL ) + return ERROR_DOS(ERRDOS,ERRnomem); + + *pparams = params; + + /* Check that the dptr is valid */ + if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) + return ERROR_DOS(ERRDOS,ERRnofiles); + + string_set(&conn->dirpath,dptr_path(dptr_num)); + + /* Get the wildcard mask from the dptr */ + if((p = dptr_wcard(dptr_num))== NULL) { + DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num)); + return ERROR_DOS(ERRDOS,ERRnofiles); + } + + pstrcpy(mask, p); + pstrcpy(directory,conn->dirpath); + + /* Get the attr mask from the dptr */ + dirtype = dptr_attr(dptr_num); + + DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n", + dptr_num, mask, dirtype, + (long)conn->dirptr, + TellDir(conn->dirptr))); + + /* We don't need to check for VOL here as this is returned by + a different TRANS2 call. */ + + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn)))); + if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) + dont_descend = True; - p = pdata; - space_remaining = max_data_bytes; - out_of_space = False; - - /* - * Seek to the correct position. We no longer use the resume key but - * depend on the last file name instead. - */ - if(requires_resume_key && *resume_name && !continue_bit) - { - /* - * Fix for NT redirector problem triggered by resume key indexes - * changing between directory scans. We now return a resume key of 0 - * and instead look for the filename to continue from (also given - * to us by NT/95/smbfs/smbclient). If no other scans have been done between the - * findfirst/findnext (as is usual) then the directory pointer - * should already be at the correct place. Check this by scanning - * backwards looking for an exact (ie. case sensitive) filename match. - * If we get to the beginning of the directory and haven't found it then scan - * forwards again looking for a match. JRA. - */ - - int current_pos, start_pos; - char *dname = NULL; - void *dirptr = conn->dirptr; - start_pos = TellDir(dirptr); - for(current_pos = start_pos; current_pos >= 0; current_pos--) - { - DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos)); - - SeekDir(dirptr, current_pos); - dname = ReadDirName(dirptr); - - /* - * Remember, mangle_map is called by - * get_lanman2_dir_entry(), so the resume name - * could be mangled. Ensure we do the same - * here. - */ - - if(dname != NULL) - mangle_map( dname, False, True, SNUM(conn)); - - if(dname && strcsequal( resume_name, dname)) - { - SeekDir(dirptr, current_pos+1); - DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); - break; - } - } - - /* - * Scan forward from start if not found going backwards. - */ - - if(current_pos < 0) - { - DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos)); - SeekDir(dirptr, start_pos); - for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) - { - /* - * Remember, mangle_map is called by - * get_lanman2_dir_entry(), so the resume name - * could be mangled. Ensure we do the same - * here. - */ - - if(dname != NULL) - mangle_map( dname, False, True, SNUM(conn)); - - if(dname && strcsequal( resume_name, dname)) - { - SeekDir(dirptr, current_pos+1); - DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); - break; - } - } /* end for */ - } /* end if current_pos */ - } /* end if requires_resume_key && !continue_bit */ - - for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) - { - BOOL got_exact_match = False; - - /* this is a heuristic to avoid seeking the dirptr except when - absolutely necessary. It allows for a filename of about 40 chars */ - if (space_remaining < DIRLEN_GUESS && numentries > 0) - { - out_of_space = True; - finished = False; - } - else - { - finished = !get_lanman2_dir_entry(conn, - inbuf, outbuf, - mask,dirtype,info_level, - requires_resume_key,dont_descend, - &p,pdata,space_remaining, &out_of_space, &got_exact_match, - &last_name_off); - } + p = pdata; + space_remaining = max_data_bytes; + out_of_space = False; + + /* + * Seek to the correct position. We no longer use the resume key but + * depend on the last file name instead. + */ + + if(requires_resume_key && *resume_name && !continue_bit) { + + /* + * Fix for NT redirector problem triggered by resume key indexes + * changing between directory scans. We now return a resume key of 0 + * and instead look for the filename to continue from (also given + * to us by NT/95/smbfs/smbclient). If no other scans have been done between the + * findfirst/findnext (as is usual) then the directory pointer + * should already be at the correct place. Check this by scanning + * backwards looking for an exact (ie. case sensitive) filename match. + * If we get to the beginning of the directory and haven't found it then scan + * forwards again looking for a match. JRA. + */ + + int current_pos, start_pos; + char *dname = NULL; + void *dirptr = conn->dirptr; + start_pos = TellDir(dirptr); + for(current_pos = start_pos; current_pos >= 0; current_pos--) { + DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos)); + + SeekDir(dirptr, current_pos); + dname = ReadDirName(dirptr); + + /* + * Remember, mangle_map is called by + * get_lanman2_dir_entry(), so the resume name + * could be mangled. Ensure we do the same + * here. + */ + + if(dname != NULL) + mangle_map( dname, False, True, SNUM(conn)); + + if(dname && strcsequal( resume_name, dname)) { + SeekDir(dirptr, current_pos+1); + DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); + break; + } + } + + /* + * Scan forward from start if not found going backwards. + */ + + if(current_pos < 0) { + DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos)); + SeekDir(dirptr, start_pos); + for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) { + + /* + * Remember, mangle_map is called by + * get_lanman2_dir_entry(), so the resume name + * could be mangled. Ensure we do the same + * here. + */ + + if(dname != NULL) + mangle_map( dname, False, True, SNUM(conn)); + + if(dname && strcsequal( resume_name, dname)) { + SeekDir(dirptr, current_pos+1); + DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 )); + break; + } + } /* end for */ + } /* end if current_pos */ + } /* end if requires_resume_key && !continue_bit */ + + for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) { + BOOL got_exact_match = False; + + /* this is a heuristic to avoid seeking the dirptr except when + absolutely necessary. It allows for a filename of about 40 chars */ + if (space_remaining < DIRLEN_GUESS && numentries > 0) { + out_of_space = True; + finished = False; + } else { + finished = !get_lanman2_dir_entry(conn, + inbuf, outbuf, + mask,dirtype,info_level, + requires_resume_key,dont_descend, + &p,pdata,space_remaining, &out_of_space, &got_exact_match, + &last_name_off); + } - if (finished && out_of_space) - finished = False; + if (finished && out_of_space) + finished = False; - if (!finished && !out_of_space) - numentries++; + if (!finished && !out_of_space) + numentries++; - /* - * As an optimisation if we know we aren't looking - * for a wildcard name (ie. the name matches the wildcard exactly) - * then we can finish on any (first) match. - * This speeds up large directory searches. JRA. - */ + /* + * As an optimisation if we know we aren't looking + * for a wildcard name (ie. the name matches the wildcard exactly) + * then we can finish on any (first) match. + * This speeds up large directory searches. JRA. + */ - if(got_exact_match) - finished = True; + if(got_exact_match) + finished = True; - space_remaining = max_data_bytes - PTR_DIFF(p,pdata); - } + space_remaining = max_data_bytes - PTR_DIFF(p,pdata); + } - /* Check if we can close the dirptr */ - if(close_after_request || (finished && close_if_end)) - { - DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num)); - dptr_close(&dptr_num); /* This frees up the saved mask */ - } + /* Check if we can close the dirptr */ + if(close_after_request || (finished && close_if_end)) { + DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num)); + dptr_close(&dptr_num); /* This frees up the saved mask */ + } - /* Set up the return parameter block */ - SSVAL(params,0,numentries); - SSVAL(params,2,finished); - SSVAL(params,4,0); /* Never an EA error */ - SSVAL(params,6,last_name_off); + /* Set up the return parameter block */ + SSVAL(params,0,numentries); + SSVAL(params,2,finished); + SSVAL(params,4,0); /* Never an EA error */ + SSVAL(params,6,last_name_off); - send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata)); + send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata)); - if ((! *directory) && dptr_path(dptr_num)) - slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); + if ((! *directory) && dptr_path(dptr_num)) + slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); - DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", - smb_fn_name(CVAL(inbuf,smb_com)), - mask, directory, dirtype, numentries ) ); + DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", + smb_fn_name(CVAL(inbuf,smb_com)), + mask, directory, dirtype, numentries ) ); - return(-1); + return(-1); } /**************************************************************************** Reply to a TRANS2_QFSINFO (query filesystem info). ****************************************************************************/ -static int call_trans2qfsinfo(connection_struct *conn, - char *inbuf, char *outbuf, - int length, int bufsize, - char **pparams, char **ppdata) +static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf, + int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - int max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *pdata = *ppdata; - char *params = *pparams; - uint16 info_level = SVAL(params,0); - int data_len, len; - SMB_STRUCT_STAT st; - char *vname = volume_label(SNUM(conn)); - int snum = SNUM(conn); - char *fstype = lp_fstype(SNUM(conn)); - - DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); - - if(vfs_stat(conn,".",&st)!=0) { - DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); - return ERROR_DOS(ERRSRV,ERRinvdevice); - } - - pdata = Realloc(*ppdata, max_data_bytes + 1024); - if ( pdata == NULL ) { - return ERROR_DOS(ERRDOS,ERRnomem); - } - *ppdata = pdata; - memset((char *)pdata,'\0',max_data_bytes + 1024); - - switch (info_level) - { - case 1: - { - SMB_BIG_UINT dfree,dsize,bsize; - data_len = 18; - conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); - SIVAL(pdata,l1_idFileSystem,st.st_dev); - SIVAL(pdata,l1_cSectorUnit,bsize/512); - SIVAL(pdata,l1_cUnit,dsize); - SIVAL(pdata,l1_cUnitAvail,dfree); - SSVAL(pdata,l1_cbSector,512); - DEBUG(5,("call_trans2qfsinfo : bsize=%u, id=%x, cSectorUnit=%u, cUnit=%u, cUnitAvail=%u, cbSector=%d\n", - (unsigned int)bsize, (unsigned int)st.st_dev, ((unsigned int)bsize)/512, (unsigned int)dsize, - (unsigned int)dfree, 512)); - break; - } - case 2: - /* Return volume name */ - /* - * Add volume serial number - hash of a combination of - * the called hostname and the service name. - */ - SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) ); - len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, - STR_TERMINATE); - SCVAL(pdata,l2_vol_cch,len); - data_len = l2_vol_szVolLabel + len; - DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", - (unsigned)st.st_ctime, len, vname)); - break; + int max_data_bytes = SVAL(inbuf, smb_mdrcnt); + char *pdata = *ppdata; + char *params = *pparams; + uint16 info_level = SVAL(params,0); + int data_len, len; + SMB_STRUCT_STAT st; + char *vname = volume_label(SNUM(conn)); + int snum = SNUM(conn); + char *fstype = lp_fstype(SNUM(conn)); + + DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); + + if(vfs_stat(conn,".",&st)!=0) { + DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); + return ERROR_DOS(ERRSRV,ERRinvdevice); + } - case SMB_QUERY_FS_ATTRIBUTE_INFO: - SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH| - (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */ - SIVAL(pdata,4,255); /* Max filename component length */ - /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it - and will think we can't do long filenames */ - len = srvstr_push(outbuf, pdata+12, fstype, -1, 0); - SIVAL(pdata,8,len); - data_len = 12 + len; - break; + pdata = Realloc(*ppdata, max_data_bytes + 1024); + if ( pdata == NULL ) + return ERROR_DOS(ERRDOS,ERRnomem); - case SMB_QUERY_FS_LABEL_INFO: - len = srvstr_push(outbuf, pdata+4, vname, -1, STR_TERMINATE); - data_len = 4 + len; - SIVAL(pdata,0,len); - break; - case SMB_QUERY_FS_VOLUME_INFO: - /* - * Add volume serial number - hash of a combination of - * the called hostname and the service name. - */ - SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^ - (str_checksum(local_machine)<<16)); - - len = srvstr_push(outbuf, pdata+18, vname, -1, STR_TERMINATE); - SIVAL(pdata,12,len); - data_len = 18+len; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", - (int)strlen(vname),vname, lp_servicename(snum))); - break; - case SMB_QUERY_FS_SIZE_INFO: - { - SMB_BIG_UINT dfree,dsize,bsize; - data_len = 24; - conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); - SBIG_UINT(pdata,0,dsize); - SBIG_UINT(pdata,8,dfree); - SIVAL(pdata,16,bsize/512); - SIVAL(pdata,20,512); - break; - } - case SMB_QUERY_FS_DEVICE_INFO: - data_len = 8; - SIVAL(pdata,0,0); /* dev type */ - SIVAL(pdata,4,0); /* characteristics */ - break; - case SMB_MAC_QUERY_FS_INFO: - /* - * Thursby MAC extension... ONLY on NTFS filesystems - * once we do streams then we don't need this - */ - if (strequal(lp_fstype(SNUM(conn)),"NTFS")) { - data_len = 88; - SIVAL(pdata,84,0x100); /* Don't support mac... */ - break; - } - /* drop through */ - default: - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - - send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len); - - DEBUG( 4, ( "%s info_level = %d\n", - smb_fn_name(CVAL(inbuf,smb_com)), info_level) ); - - return -1; + *ppdata = pdata; + memset((char *)pdata,'\0',max_data_bytes + 1024); + + switch (info_level) { + case SMB_INFO_ALLOCATION: + { + SMB_BIG_UINT dfree,dsize,bsize; + data_len = 18; + conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + SIVAL(pdata,l1_idFileSystem,st.st_dev); + SIVAL(pdata,l1_cSectorUnit,bsize/512); + SIVAL(pdata,l1_cUnit,dsize); + SIVAL(pdata,l1_cUnitAvail,dfree); + SSVAL(pdata,l1_cbSector,512); + DEBUG(5,("call_trans2qfsinfo : bsize=%u, id=%x, cSectorUnit=%u, cUnit=%u, cUnitAvail=%u, cbSector=%d\n", + (unsigned int)bsize, (unsigned int)st.st_dev, ((unsigned int)bsize)/512, (unsigned int)dsize, + (unsigned int)dfree, 512)); + break; + } + + case SMB_INFO_VOLUME: + /* Return volume name */ + /* + * Add volume serial number - hash of a combination of + * the called hostname and the service name. + */ + SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) ); + len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, STR_TERMINATE); + SCVAL(pdata,l2_vol_cch,len); + data_len = l2_vol_szVolLabel + len; + DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", + (unsigned)st.st_ctime, len, vname)); + break; + + case SMB_QUERY_FS_ATTRIBUTE_INFO: + case SMB_FS_ATTRIBUTE_INFORMATION: + + SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH| + (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */ + SIVAL(pdata,4,255); /* Max filename component length */ + /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it + and will think we can't do long filenames */ + len = srvstr_push(outbuf, pdata+12, fstype, -1, 0); + SIVAL(pdata,8,len); + data_len = 12 + len; + break; + + case SMB_QUERY_FS_LABEL_INFO: + case SMB_FS_LABEL_INFORMATION: + len = srvstr_push(outbuf, pdata+4, vname, -1, STR_TERMINATE); + data_len = 4 + len; + SIVAL(pdata,0,len); + break; + + case SMB_QUERY_FS_VOLUME_INFO: + case SMB_FS_VOLUME_INFORMATION: + + /* + * Add volume serial number - hash of a combination of + * the called hostname and the service name. + */ + SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^ + (str_checksum(local_machine)<<16)); + + len = srvstr_push(outbuf, pdata+18, vname, -1, STR_TERMINATE); + SIVAL(pdata,12,len); + data_len = 18+len; + DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", + (int)strlen(vname),vname, lp_servicename(snum))); + break; + + case SMB_QUERY_FS_SIZE_INFO: + case SMB_FS_SIZE_INFORMATION: + { + SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; + data_len = 24; + conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + block_size = lp_block_size(snum); + if (bsize < block_size) { + SMB_BIG_UINT factor = block_size/bsize; + bsize = block_size; + dsize /= factor; + dfree /= factor; + } + if (bsize > block_size) { + SMB_BIG_UINT factor = bsize/block_size; + bsize = block_size; + dsize *= factor; + dfree *= factor; + } + bytes_per_sector = 512; + sectors_per_unit = bsize/bytes_per_sector; + DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \ +cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, + (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); + SBIG_UINT(pdata,0,dsize); + SBIG_UINT(pdata,8,dfree); + SIVAL(pdata,16,sectors_per_unit); + SIVAL(pdata,20,bytes_per_sector); + break; + } + + case SMB_FS_FULL_SIZE_INFORMATION: + { + SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector; + data_len = 32; + conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize); + block_size = lp_block_size(snum); + if (bsize < block_size) { + SMB_BIG_UINT factor = block_size/bsize; + bsize = block_size; + dsize /= factor; + dfree /= factor; + } + if (bsize > block_size) { + SMB_BIG_UINT factor = bsize/block_size; + bsize = block_size; + dsize *= factor; + dfree *= factor; + } + bytes_per_sector = 512; + sectors_per_unit = bsize/bytes_per_sector; + DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \ +cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, + (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); + SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */ + SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */ + SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */ + SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */ + SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */ + break; + } + + case SMB_QUERY_FS_DEVICE_INFO: + case SMB_FS_DEVICE_INFORMATION: + data_len = 8; + SIVAL(pdata,0,0); /* dev type */ + SIVAL(pdata,4,0); /* characteristics */ + break; + + case SMB_FS_OBJECTID_INFORMATION: + data_len = 64; + break; + + /* + * Query the version and capabilities of the CIFS UNIX extensions + * in use. + */ + + case SMB_QUERY_CIFS_UNIX_INFO: + if (!lp_unix_extensions()) + return ERROR_DOS(ERRDOS,ERRunknownlevel); + data_len = 12; + SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION); + SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION); + SBIG_UINT(pdata,4,((SMB_BIG_UINT)0)); /* No capabilities for now... */ + break; + + case SMB_MAC_QUERY_FS_INFO: + /* + * Thursby MAC extension... ONLY on NTFS filesystems + * once we do streams then we don't need this + */ + if (strequal(lp_fstype(SNUM(conn)),"NTFS")) { + data_len = 88; + SIVAL(pdata,84,0x100); /* Don't support mac... */ + break; + } + /* drop through */ + default: + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + + send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len); + + DEBUG( 4, ( "%s info_level = %d\n", smb_fn_name(CVAL(inbuf,smb_com)), info_level) ); + + return -1; } /**************************************************************************** @@ -1395,21 +1482,20 @@ static int call_trans2qfsinfo(connection_struct *conn, ****************************************************************************/ static int call_trans2setfsinfo(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, - char **pparams, char **ppdata) + char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - /* Just say yes we did it - there is nothing that - can be set here so it doesn't matter. */ - int outsize; - DEBUG(3,("call_trans2setfsinfo\n")); + /* Just say yes we did it - there is nothing that + can be set here so it doesn't matter. */ + int outsize; + DEBUG(3,("call_trans2setfsinfo\n")); - if (!CAN_WRITE(conn)) - return ERROR_DOS(ERRSRV,ERRaccess); + if (!CAN_WRITE(conn)) + return ERROR_DOS(ERRSRV,ERRaccess); - outsize = set_message(outbuf,10,0,True); + outsize = set_message(outbuf,10,0,True); - return outsize; + return outsize; } /**************************************************************************** @@ -1434,8 +1520,7 @@ NTSTATUS set_bad_path_error(int err, BOOL bad_path) static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **pparams,char **ppdata, - int total_data) + char **pparams, int total_params, char **ppdata, int total_data) { int max_data_bytes = SVAL(inbuf, smb_mdrcnt); char *params = *pparams; @@ -1448,6 +1533,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, unsigned int data_size; SMB_STRUCT_STAT sbuf; pstring fname, dos_fname; + char *fullpathname; char *base_name; char *p; SMB_OFF_T pos = 0; @@ -1456,9 +1542,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, int len; time_t c_time; - if (!params) { + if (!params) return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } if (tran_call == TRANSACT2_QFILEINFO) { files_struct *fsp = file_fsp(params,0); @@ -1474,16 +1559,25 @@ static int call_trans2qfilepathinfo(connection_struct *conn, */ pstrcpy(fname, fsp->fsp_name); unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn) || - (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf))) { - DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + 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)); } + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (vfs_lstat(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); + } + delete_pending = fsp->directory_delete_on_close; } else { /* @@ -1503,6 +1597,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, } } else { /* qpathinfo */ + if (total_params < 6) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + info_level = SVAL(params,0); DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); @@ -1512,17 +1609,28 @@ static int call_trans2qfilepathinfo(connection_struct *conn, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); unix_convert(fname,conn,0,&bad_path,&sbuf); - if (!check_name(fname,conn) || - (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf))) { - DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; + 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)); + } + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (vfs_lstat(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRbadpath)); } + } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); return(UNIXERROR(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)); @@ -1534,9 +1642,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, base_name = p+1; mode = dos_mode(conn,fname,&sbuf); + fullpathname = fname; size = sbuf.st_size; allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size); - if (mode & aDIR) size = 0; @@ -1568,12 +1676,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn, sbuf.st_mtime &= ~1; } - /* NT expects the name to be in an exact form */ - if (strequal(fname,".")) { + /* NT expects the name to be in an exact form of the *full* + filename. See the trans2 torture test */ + if (strequal(base_name,".")) { pstrcpy(dos_fname, "\\"); } else { snprintf(dos_fname, sizeof(dos_fname), "\\%s", fname); - string_replace( dos_fname, '/', '\\'); + string_replace(dos_fname, '/', '\\'); } switch (info_level) { @@ -1636,6 +1745,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, case SMB_FILE_STANDARD_INFORMATION: case SMB_QUERY_FILE_STANDARD_INFO: + data_size = 24; /* Fake up allocation size. */ SOFF_T(pdata,0,allocation_size); @@ -1658,8 +1768,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, pstrcpy(short_name,base_name); /* Mangle if not already 8.3 */ if(!mangle_is_8_3(short_name, True)) { - if(!mangle_map(short_name,True,True,SNUM(conn))) - *short_name = '\0'; + mangle_map(short_name,True,True,SNUM(conn)); } len = srvstr_push(outbuf, pdata+4, short_name, -1, STR_TERMINATE|STR_UPPER); data_size = 4 + len; @@ -1676,18 +1785,18 @@ static int call_trans2qfilepathinfo(connection_struct *conn, SIVAL(pdata,0,len); break; - case SMB_FILE_END_OF_FILE_INFORMATION: - case SMB_QUERY_FILE_END_OF_FILEINFO: - data_size = 8; - SOFF_T(pdata,0,size); - break; - case SMB_FILE_ALLOCATION_INFORMATION: case SMB_QUERY_FILE_ALLOCATION_INFO: data_size = 8; SOFF_T(pdata,0,allocation_size); break; + case SMB_FILE_END_OF_FILE_INFORMATION: + case SMB_QUERY_FILE_END_OF_FILEINFO: + data_size = 8; + SOFF_T(pdata,0,size); + break; + case SMB_QUERY_FILE_ALL_INFO: put_long_date(pdata,c_time); put_long_date(pdata+8,sbuf.st_atime); @@ -1793,6 +1902,14 @@ static int call_trans2qfilepathinfo(connection_struct *conn, break; } +#if 0 + /* + * NT4 server just returns "invalid query" to this - if we try to answer + * it then NTws gets a BSOD! (tridge). + * W2K seems to want this. JRA. + */ + case SMB_QUERY_FILE_STREAM_INFO: +#endif case SMB_FILE_STREAM_INFORMATION: if (mode & aDIR) { data_size = 0; @@ -1832,18 +1949,92 @@ static int call_trans2qfilepathinfo(connection_struct *conn, data_size = 8; break; -#if 0 - /* NT4 server just returns "invalid query" to this - if we try to answer - it then NTws gets a BSOD! (tridge) */ - case SMB_QUERY_FILE_STREAM_INFO: - SIVAL(pdata,0,pos); - SIVAL(pdata,4,(uint32)size); - SIVAL(pdata,12,(uint32)allocation_size); - len = srvstr_push(outbuf, pdata+24, fname, -1, STR_TERMINATE); - SIVAL(pdata,20,len); - data_size = 24 + len; + /* + * CIFS UNIX Extensions. + */ + + case SMB_QUERY_FILE_UNIX_BASIC: + + DEBUG(4,("call_trans2qfilepathinfo: st_mode=%o\n",(int)sbuf.st_mode)); + + SOFF_T(pdata,0,sbuf.st_size); /* File size 64 Bit */ + pdata += 8; + +#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) + SOFF_T(pdata,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */ +#else + /* Can't get the value - fake it using size. */ + SOFF_T(pdata,0,sbuf.st_size); /* Number of bytes used on disk - 64 Bit */ +#endif + pdata += 8; + + put_long_date(pdata,sbuf.st_ctime); /* Creation Time 64 Bit */ + put_long_date(pdata+8,sbuf.st_atime); /* Last access time 64 Bit */ + put_long_date(pdata+16,sbuf.st_mtime); /* Last modification time 64 Bit */ + pdata += 24; + + SIVAL(pdata,0,sbuf.st_uid); /* user id for the owner */ + SIVAL(pdata,4,0); + pdata += 8; + + SIVAL(pdata,0,sbuf.st_gid); /* group id of owner */ + SIVAL(pdata,4,0); + pdata += 8; + + SIVAL(pdata,0,unix_filetype(sbuf.st_mode)); + pdata += 4; + + SIVAL(pdata,0,unix_dev_major(sbuf.st_rdev)); /* Major device number if type is device */ + SIVAL(pdata,4,0); + pdata += 8; + + SIVAL(pdata,0,unix_dev_minor(sbuf.st_rdev)); /* Minor device number if type is device */ + SIVAL(pdata,4,0); + pdata += 8; + + SINO_T(pdata,0,(SMB_INO_T)sbuf.st_ino); /* inode number */ + pdata += 8; + + SIVAL(pdata,0, unix_perms_to_wire(sbuf.st_mode)); /* Standard UNIX file permissions */ + SIVAL(pdata,4,0); + pdata += 8; + + SIVAL(pdata,0,sbuf.st_nlink); /* number of hard links */ + SIVAL(pdata,4,0); + pdata += 8+1; + data_size = PTR_DIFF(pdata,(*ppdata)); + + { + int i; + DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC")); + + for (i=0; i<100; i++) + DEBUG(4,("%d=%x, ",i, (*ppdata)[i])); + DEBUG(4,("\n")); + } + break; + + case SMB_QUERY_FILE_UNIX_LINK: + { + pstring buffer; + +#ifdef S_ISLNK + if(!S_ISLNK(sbuf.st_mode)) + return(UNIXERROR(ERRSRV,ERRbadlink)); +#else + return(UNIXERROR(ERRDOS,ERRbadlink)); #endif + len = conn->vfs_ops.readlink(conn,fullpathname, buffer, sizeof(pstring)-1); /* read link */ + if (len == -1) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + buffer[len] = 0; + len = srvstr_push(outbuf, pdata, buffer, -1, STR_TERMINATE); + pdata += len; + data_size = PTR_DIFF(pdata,(*ppdata)); + + break; + } default: return ERROR_DOS(ERRDOS,ERRunknownlevel); @@ -1943,19 +2134,78 @@ NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close) } /**************************************************************************** + Returns true if this pathname is within the share, and thus safe. +****************************************************************************/ + +static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in, char *link_dest_out) +{ +#ifdef PATH_MAX + char resolved_name[PATH_MAX+1]; +#else + pstring resolved_name; +#endif + fstring last_component; + pstring link_dest; + pstring link_test; + char *p; + BOOL bad_path = False; + SMB_STRUCT_STAT sbuf; + + pstrcpy(link_dest, link_dest_in); + unix_convert(link_dest,conn,0,&bad_path,&sbuf); + + /* Store the UNIX converted path. */ + pstrcpy(link_dest_out, link_dest); + + p = strrchr(link_dest, '/'); + if (p) { + fstrcpy(last_component, p+1); + *p = '\0'; + } else { + fstrcpy(last_component, link_dest); + pstrcpy(link_dest, "./"); + } + + if (conn->vfs_ops.realpath(conn,link_dest,resolved_name) == NULL) + return -1; + + pstrcpy(link_dest, resolved_name); + pstrcat(link_dest, "/"); + pstrcat(link_dest, last_component); + + if (*link_dest != '/') { + /* Relative path. */ + pstrcpy(link_test, conn->connectpath); + pstrcat(link_test, "/"); + pstrcat(link_test, link_dest); + } else { + pstrcpy(link_test, link_dest); + } + + /* + * Check if the link is within the share. + */ + + if (strncmp(conn->connectpath, link_test, strlen(conn->connectpath))) { + errno = EACCES; + return -1; + } + return 0; +} + +/**************************************************************************** Reply to a TRANS2_SETFILEINFO (set file info by fileid). ****************************************************************************/ static int call_trans2setfilepathinfo(connection_struct *conn, - char *inbuf, char *outbuf, int length, - int bufsize, char **pparams, - char **ppdata, int total_data) + char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { char *params = *pparams; char *pdata = *ppdata; uint16 tran_call = SVAL(inbuf, smb_setup0); uint16 info_level; - int mode=0; + int dosmode=0; SMB_OFF_T size=0; struct utimbuf tvs; SMB_STRUCT_STAT sbuf; @@ -1963,6 +2213,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, int fd = -1; BOOL bad_path = False; files_struct *fsp = NULL; + uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE; + gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE; + mode_t unixmode = 0; if (tran_call == TRANSACT2_SETFILEINFO) { fsp = file_fsp(params,0); @@ -1977,11 +2230,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn, pstrcpy(fname, fsp->fsp_name); unix_convert(fname,conn,0,&bad_path,&sbuf); if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) { - DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); + set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRbadpath)); } } else if (fsp && fsp->print_file) { @@ -2007,29 +2257,30 @@ static int call_trans2setfilepathinfo(connection_struct *conn, fd = fsp->fd; if (vfs_fstat(fsp,fd,&sbuf) != 0) { - DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); + DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadfid)); } } } else { /* set path info */ + if (total_params < 6) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + info_level = SVAL(params,0); srvstr_pull(inbuf, fname, ¶ms[6], sizeof(fname), -1, STR_TERMINATE); unix_convert(fname,conn,0,&bad_path,&sbuf); if(!check_name(fname, conn)) { - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + set_bad_path_error(errno, bad_path); return(UNIXERROR(ERRDOS,ERRbadpath)); } - - if(!VALID_STAT(sbuf)) { - DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno))); - if((errno == ENOENT) && bad_path) { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } + + /* + * For CIFS UNIX extensions the target name may not exist. + */ + + 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)); } } @@ -2037,6 +2288,12 @@ static int call_trans2setfilepathinfo(connection_struct *conn, if (!CAN_WRITE(conn)) return ERROR_DOS(ERRSRV,ERRaccess); + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) + return ERROR_DOS(ERRDOS,ERRunknownlevel); + + 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)); @@ -2048,29 +2305,36 @@ static int call_trans2setfilepathinfo(connection_struct *conn, SSVAL(params,0,0); + if (fsp) { + /* the pending modtime overrides the current modtime */ + sbuf.st_mtime = fsp->pending_modtime; + } + size = sbuf.st_size; tvs.modtime = sbuf.st_mtime; tvs.actime = sbuf.st_atime; - mode = dos_mode(conn,fname,&sbuf); + dosmode = dos_mode(conn,fname,&sbuf); + unixmode = sbuf.st_mode; - if (total_data > 4 && IVAL(pdata,0) == total_data) { - /* uggh, EAs for OS2 */ - DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data)); - return ERROR_DOS(ERRDOS,ERReasnotsupported); - } + set_owner = VALID_STAT(sbuf) ? sbuf.st_uid : (uid_t)SMB_UID_NO_CHANGE; + set_grp = VALID_STAT(sbuf) ? sbuf.st_gid : (gid_t)SMB_GID_NO_CHANGE; switch (info_level) { case SMB_INFO_STANDARD: case SMB_INFO_QUERY_EA_SIZE: { + if (total_data < l1_cbFile+4) + 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); - mode = SVAL(pdata,l1_attrFile); + dosmode = SVAL(pdata,l1_attrFile); size = IVAL(pdata,l1_cbFile); + break; } @@ -2078,18 +2342,24 @@ static int call_trans2setfilepathinfo(connection_struct *conn, it's also not in the cifs6.txt spec. */ case SMB_INFO_QUERY_EAS_FROM_LIST: + if (total_data < 28) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + tvs.actime = make_unix_date2(pdata+8); tvs.modtime = make_unix_date2(pdata+12); size = IVAL(pdata,16); - mode = IVAL(pdata,24); + dosmode = IVAL(pdata,24); break; /* XXXX nor this. not in cifs6.txt, either. */ case SMB_INFO_QUERY_ALL_EAS: + if (total_data < 28) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + tvs.actime = make_unix_date2(pdata+8); tvs.modtime = make_unix_date2(pdata+12); size = IVAL(pdata,16); - mode = IVAL(pdata,24); + dosmode = IVAL(pdata,24); break; case SMB_SET_FILE_BASIC_INFO: @@ -2099,6 +2369,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, time_t write_time; time_t changed_time; + if (total_data < 36) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + /* Ignore create time at offset pdata. */ /* access time */ @@ -2109,21 +2382,28 @@ static int call_trans2setfilepathinfo(connection_struct *conn, tvs.modtime = MIN(write_time, changed_time); + if (write_time > tvs.modtime && write_time != 0xffffffff) { + tvs.modtime = write_time; + } /* Prefer a defined time to an undefined one. */ if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1) tvs.modtime = (write_time == (time_t)0 || write_time == (time_t)-1 ? changed_time : write_time); /* attributes */ - mode = IVAL(pdata,32); + dosmode = IVAL(pdata,32); break; } - case SMB_FILE_ALLOCATION_INFORMATION: + case SMB_FILE_ALLOCATION_INFORMATION: case SMB_SET_FILE_ALLOCATION_INFO: { int ret = -1; SMB_OFF_T allocation_size = IVAL(pdata,0); + + if (total_data < 8) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + #ifdef LARGE_SMB_OFF_T allocation_size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); #else /* LARGE_SMB_OFF_T */ @@ -2163,14 +2443,16 @@ static int call_trans2setfilepathinfo(connection_struct *conn, return(UNIXERROR(ERRDOS,ERRbadpath)); ret = vfs_allocate_file_space(new_fsp, allocation_size); if (vfs_fstat(new_fsp,new_fsp->fd,&new_sbuf) != 0) { - DEBUG(3,("fstat of fnum %d failed (%s)\n",new_fsp->fnum, strerror(errno))); + DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n", + new_fsp->fnum, strerror(errno))); ret = -1; } close_file(new_fsp,True); } else { ret = vfs_allocate_file_space(fsp, allocation_size); if (vfs_fstat(fsp,fd,&new_sbuf) != 0) { - DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); + DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n", + fsp->fnum, strerror(errno))); ret = -1; } } @@ -2184,9 +2466,12 @@ static int call_trans2setfilepathinfo(connection_struct *conn, break; } - case SMB_FILE_END_OF_FILE_INFORMATION: + case SMB_FILE_END_OF_FILE_INFORMATION: case SMB_SET_FILE_END_OF_FILE_INFO: { + if (total_data < 8) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + size = IVAL(pdata,0); #ifdef LARGE_SMB_OFF_T size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); @@ -2204,6 +2489,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, BOOL delete_on_close = (CVAL(pdata,0) ? True : False); NTSTATUS status; + if (total_data < 1) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + if (tran_call != TRANSACT2_SETFILEINFO) return ERROR_DOS(ERRDOS,ERRunknownlevel); @@ -2218,6 +2506,183 @@ static int call_trans2setfilepathinfo(connection_struct *conn, break; } + /* + * CIFS UNIX extensions. + */ + + case SMB_SET_FILE_UNIX_BASIC: + { + uint32 raw_unixmode; + + if (total_data < 100) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO && + IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) { + size=IVAL(pdata,0); /* first 8 Bytes are size */ +#ifdef LARGE_SMB_OFF_T + size |= (((SMB_OFF_T)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 */ + } + pdata+=24; /* ctime & st_blocks are not changed */ + tvs.actime = interpret_long_unix_date(pdata); /* access_time */ + tvs.modtime = interpret_long_unix_date(pdata+8); /* modification_time */ + pdata+=16; + set_owner = (uid_t)IVAL(pdata,0); + pdata += 8; + set_grp = (gid_t)IVAL(pdata,0); + pdata += 8; + raw_unixmode = IVAL(pdata,28); + unixmode = unix_perms_from_wire(conn, &sbuf, raw_unixmode); + dosmode = 0; /* Ensure dos mode change doesn't override this. */ + + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC: name = %s \ +size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", + fname, (double)size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode)); + + if (!VALID_STAT(sbuf)) { + + /* + * The only valid use of this is to create character and block + * devices, and named pipes. This is deprecated (IMHO) and + * a new info level should be used for mknod. JRA. + */ + +#if !defined(HAVE_MAKEDEV_FN) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); +#else /* HAVE_MAKEDEV_FN */ + uint32 file_type = IVAL(pdata,0); + uint32 dev_major = IVAL(pdata,4); + uint32 dev_minor = IVAL(pdata,12); + + uid_t myuid = geteuid(); + gid_t mygid = getegid(); + SMB_DEV_T dev; + + if (tran_call == TRANSACT2_SETFILEINFO) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + + if (raw_unixmode == SMB_MODE_NO_CHANGE) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + dev = makedev(dev_major, dev_minor); + + /* We can only create as the owner/group we are. */ + + if ((set_owner != myuid) && (set_owner != (uid_t)SMB_UID_NO_CHANGE)) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + if ((set_grp != mygid) && (set_grp != (gid_t)SMB_GID_NO_CHANGE)) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + + if (file_type != UNIX_TYPE_CHARDEV && file_type != UNIX_TYPE_BLKDEV && + file_type != UNIX_TYPE_FIFO) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \ +0%o for file %s\n", (double)dev, unixmode, fname )); + + /* Ok - do the mknod. */ + if (conn->vfs_ops.mknod(conn,dos_to_unix_static(fname), unixmode, dev) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + + SSVAL(params,0,0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + return(-1); +#endif /* HAVE_MAKEDEV_FN */ + + } + + /* + * Deal with the UNIX specific mode set. + */ + + if (raw_unixmode != SMB_MODE_NO_CHANGE) { + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n", + (unsigned int)unixmode, fname )); + if (vfs_chmod(conn,fname,unixmode) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + /* + * Deal with the UNIX specific uid set. + */ + + if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (sbuf.st_uid != set_owner)) { + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing owner %u for file %s\n", + (unsigned int)set_owner, fname )); + if (vfs_chown(conn,fname,set_owner, (gid_t)-1) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + /* + * Deal with the UNIX specific gid set. + */ + + if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (sbuf.st_gid != set_grp)) { + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n", + (unsigned int)set_owner, fname )); + if (vfs_chown(conn,fname,(uid_t)-1, set_grp) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + break; + } + + case SMB_SET_FILE_UNIX_LINK: + { + pstring link_dest; + /* Set a symbolic link. */ + /* Don't allow this if follow links is false. */ + + if (!lp_symlinks(SNUM(conn))) + return(ERROR_DOS(ERRDOS,ERRnoaccess)); + + /* Disallow if already exists. */ + if (VALID_STAT(sbuf)) + return(ERROR_DOS(ERRDOS,ERRbadpath)); + + srvstr_pull(inbuf, link_dest, pdata, sizeof(link_dest), -1, STR_TERMINATE); + + if (ensure_link_is_safe(conn, link_dest, link_dest) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n", + fname, link_dest )); + + if (conn->vfs_ops.symlink(conn,link_dest,fname) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + SSVAL(params,0,0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + return(-1); + } + + case SMB_SET_FILE_UNIX_HLINK: + { + pstring link_dest; + + /* Set a hard link. */ + + /* Disallow if already exists. */ + if (VALID_STAT(sbuf)) + return(ERROR_DOS(ERRDOS,ERRbadpath)); + + srvstr_pull(inbuf, link_dest, pdata, sizeof(link_dest), -1, STR_TERMINATE); + + if (ensure_link_is_safe(conn, link_dest, link_dest) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + + DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n", + fname, link_dest )); + + if (conn->vfs_ops.link(conn,link_dest,fname) != 0) + return(UNIXERROR(ERRDOS,ERRnoaccess)); + SSVAL(params,0,0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + return(-1); + } + default: return ERROR_DOS(ERRDOS,ERRunknownlevel); } @@ -2232,17 +2697,18 @@ static int call_trans2setfilepathinfo(connection_struct *conn, DEBUG(6,("actime: %s " , ctime(&tvs.actime))); DEBUG(6,("modtime: %s ", ctime(&tvs.modtime))); DEBUG(6,("size: %.0f ", (double)size)); - DEBUG(6,("mode: %x\n" , mode)); if (S_ISDIR(sbuf.st_mode)) - mode |= aDIR; + dosmode |= aDIR; else - mode &= ~aDIR; + dosmode &= ~aDIR; + + DEBUG(6,("dosmode: %x\n" , dosmode)); if(!((info_level == SMB_SET_FILE_END_OF_FILE_INFO) || (info_level == SMB_SET_FILE_ALLOCATION_INFO) || (info_level == SMB_FILE_ALLOCATION_INFORMATION) || - (info_level == SMB_FILE_END_OF_FILE_INFORMATION))) { + (info_level == SMB_FILE_END_OF_FILE_INFORMATION))) { /* * Only do this test if we are not explicitly @@ -2263,7 +2729,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, * NT does this a lot. It's actually pointless * setting the time here, as it will be overwritten * on the next write, so we save the request - * away and will set it on file code. JRA. + * away and will set it on file close. JRA. */ if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) { @@ -2281,11 +2747,11 @@ static int call_trans2setfilepathinfo(connection_struct *conn, } /* check the mode isn't different, before changing it */ - if ((mode != 0) && (mode != dos_mode(conn, fname, &sbuf))) { + if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, &sbuf))) { - DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, mode )); + DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, dosmode )); - if(file_chmod(conn, fname, mode, NULL)) { + if(file_chmod(conn, fname, dosmode, NULL)) { DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno))); return(UNIXERROR(ERRDOS,ERRnoaccess)); } @@ -2331,7 +2797,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, } SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); return(-1); @@ -2343,48 +2808,45 @@ static int call_trans2setfilepathinfo(connection_struct *conn, static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, - char **pparams, char **ppdata) + char **pparams, int total_params, char **ppdata, int total_data) { - char *params = *pparams; - pstring directory; - int ret = -1; - SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; + char *params = *pparams; + pstring directory; + int ret = -1; + SMB_STRUCT_STAT sbuf; + BOOL bad_path = False; - if (!CAN_WRITE(conn)) - return ERROR_DOS(ERRSRV,ERRaccess); + if (!CAN_WRITE(conn)) + return ERROR_DOS(ERRSRV,ERRaccess); - srvstr_pull(inbuf, directory, ¶ms[4], sizeof(directory), -1, STR_TERMINATE); + if (total_params < 4) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); + srvstr_pull(inbuf, directory, ¶ms[4], sizeof(directory), -1, STR_TERMINATE); - unix_convert(directory,conn,0,&bad_path,&sbuf); - if (check_name(directory,conn)) - ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); + DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); + + unix_convert(directory,conn,0,&bad_path,&sbuf); + if (check_name(directory,conn)) + ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); - if(ret < 0) - { - DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - /* Realloc the parameter and data sizes */ - params = Realloc(*pparams,2); - if(params == NULL) { - return ERROR_DOS(ERRDOS,ERRnomem); - } - *pparams = params; - - SSVAL(params,0,0); - - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + if(ret < 0) { + DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); + set_bad_path_error(errno, bad_path); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + + /* Realloc the parameter and data sizes */ + params = Realloc(*pparams,2); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + *pparams = params; + + SSVAL(params,0,0); + + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - return(-1); + return(-1); } /**************************************************************************** @@ -2393,44 +2855,45 @@ static int call_trans2mkdir(connection_struct *conn, ****************************************************************************/ static int call_trans2findnotifyfirst(connection_struct *conn, - char *inbuf, char *outbuf, - int length, int bufsize, - char **pparams, char **ppdata) + char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - static uint16 fnf_handle = 257; - char *params = *pparams; - uint16 info_level = SVAL(params,4); - - DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level)); - - switch (info_level) - { - case 1: - case 2: - break; - default: - return ERROR_DOS(ERRDOS,ERRunknownlevel); - } - - /* Realloc the parameter and data sizes */ - params = Realloc(*pparams,6); - if(params == NULL) { - return ERROR_DOS(ERRDOS,ERRnomem); - } - *pparams = params; - - SSVAL(params,0,fnf_handle); - SSVAL(params,2,0); /* No changes */ - SSVAL(params,4,0); /* No EA errors */ - - fnf_handle++; - - if(fnf_handle == 0) - fnf_handle = 257; - - send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0); + static uint16 fnf_handle = 257; + char *params = *pparams; + uint16 info_level; + + if (total_params < 6) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + info_level = SVAL(params,4); + DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level)); + + switch (info_level) { + case 1: + case 2: + break; + default: + return ERROR_DOS(ERRDOS,ERRunknownlevel); + } + + /* Realloc the parameter and data sizes */ + params = Realloc(*pparams,6); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + *pparams = params; + + SSVAL(params,0,fnf_handle); + SSVAL(params,2,0); /* No changes */ + SSVAL(params,4,0); /* No EA errors */ + + fnf_handle++; + + if(fnf_handle == 0) + fnf_handle = 257; + + send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0); - return(-1); + return(-1); } /**************************************************************************** @@ -2439,27 +2902,25 @@ static int call_trans2findnotifyfirst(connection_struct *conn, ****************************************************************************/ static int call_trans2findnotifynext(connection_struct *conn, - char *inbuf, char *outbuf, - int length, int bufsize, - char **pparams, char **ppdata) + char *inbuf, char *outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - char *params = *pparams; + char *params = *pparams; - DEBUG(3,("call_trans2findnotifynext\n")); + DEBUG(3,("call_trans2findnotifynext\n")); - /* Realloc the parameter and data sizes */ - params = Realloc(*pparams,4); - if(params == NULL) { - return ERROR_DOS(ERRDOS,ERRnomem); - } - *pparams = params; + /* Realloc the parameter and data sizes */ + params = Realloc(*pparams,4); + if(params == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + *pparams = params; - SSVAL(params,0,0); /* No changes */ - SSVAL(params,2,0); /* No EA errors */ + SSVAL(params,0,0); /* No changes */ + SSVAL(params,2,0); /* No EA errors */ - send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0); - return(-1); + return(-1); } /**************************************************************************** @@ -2467,29 +2928,33 @@ static int call_trans2findnotifynext(connection_struct *conn, ****************************************************************************/ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, - char* outbuf, int length, int bufsize, - char** pparams, char** ppdata) + char* outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - char *params = *pparams; - pstring pathname; - int reply_size = 0; - int max_referral_level = SVAL(params,0); + char *params = *pparams; + pstring pathname; + int reply_size = 0; + int max_referral_level; + DEBUG(10,("call_trans2getdfsreferral\n")); - DEBUG(10,("call_trans2getdfsreferral\n")); + if (total_params < 2) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); - if(!lp_host_msdfs()) - return ERROR_DOS(ERRDOS,ERRbadfunc); + max_referral_level = SVAL(params,0); - srvstr_pull(inbuf, pathname, ¶ms[2], sizeof(pathname), -1, STR_TERMINATE); + if(!lp_host_msdfs()) + return ERROR_DOS(ERRDOS,ERRbadfunc); - if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0) - return ERROR_DOS(ERRDOS,ERRbadfile); + srvstr_pull(inbuf, pathname, ¶ms[2], sizeof(pathname), -1, STR_TERMINATE); + + if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0) + return ERROR_DOS(ERRDOS,ERRbadfile); - SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES); - send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size); + SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES); + send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size); - return(-1); + return(-1); } #define LMCAT_SPL 0x53 @@ -2500,32 +2965,31 @@ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, ****************************************************************************/ static int call_trans2ioctl(connection_struct *conn, char* inbuf, - char* outbuf, int length, int bufsize, - char** pparams, char** ppdata) + char* outbuf, int length, int bufsize, + char **pparams, int total_params, char **ppdata, int total_data) { - char *pdata = *ppdata; - files_struct *fsp = file_fsp(inbuf,smb_vwv15); - - if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) && - (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { - pdata = Realloc(*ppdata, 32); - if(pdata == NULL) { - return ERROR_DOS(ERRDOS,ERRnomem); - } - *ppdata = pdata; - - /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2 - CAN ACCEPT THIS IN UNICODE. JRA. */ - - SSVAL(pdata,0,fsp->print_jobid); /* Job number */ - srvstr_push( outbuf, pdata + 2, global_myname, 15, STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */ - srvstr_push( outbuf, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */ - send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32); - return(-1); - } else { - DEBUG(2,("Unknown TRANS2_IOCTL\n")); - return ERROR_DOS(ERRSRV,ERRerror); - } + char *pdata = *ppdata; + files_struct *fsp = file_fsp(inbuf,smb_vwv15); + + if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) && + (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { + pdata = Realloc(*ppdata, 32); + if(pdata == NULL) + return ERROR_DOS(ERRDOS,ERRnomem); + *ppdata = pdata; + + /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2 + CAN ACCEPT THIS IN UNICODE. JRA. */ + + SSVAL(pdata,0,fsp->print_jobid); /* Job number */ + srvstr_push( outbuf, pdata + 2, global_myname, 15, STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */ + srvstr_push( outbuf, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */ + send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32); + return(-1); + } else { + DEBUG(2,("Unknown TRANS2_IOCTL\n")); + return ERROR_DOS(ERRSRV,ERRerror); + } } /**************************************************************************** @@ -2736,93 +3200,84 @@ int reply_trans2(connection_struct *conn, switch(tran_call) { case TRANSACT2_OPEN: START_PROFILE_NESTED(Trans2_open); - outsize = call_trans2open(conn, - inbuf, outbuf, bufsize, - ¶ms, &data); + outsize = call_trans2open(conn, inbuf, outbuf, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_open); break; case TRANSACT2_FINDFIRST: START_PROFILE_NESTED(Trans2_findfirst); - outsize = call_trans2findfirst(conn, inbuf, outbuf, - bufsize, ¶ms, &data); + outsize = call_trans2findfirst(conn, inbuf, outbuf, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_findfirst); break; case TRANSACT2_FINDNEXT: START_PROFILE_NESTED(Trans2_findnext); - outsize = call_trans2findnext(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data); + outsize = call_trans2findnext(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_findnext); break; case TRANSACT2_QFSINFO: START_PROFILE_NESTED(Trans2_qfsinfo); - outsize = call_trans2qfsinfo(conn, inbuf, outbuf, - length, bufsize, ¶ms, - &data); + outsize = call_trans2qfsinfo(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_qfsinfo); break; case TRANSACT2_SETFSINFO: START_PROFILE_NESTED(Trans2_setfsinfo); - outsize = call_trans2setfsinfo(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data); + outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_setfsinfo); break; case TRANSACT2_QPATHINFO: case TRANSACT2_QFILEINFO: START_PROFILE_NESTED(Trans2_qpathinfo); - outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data, total_data); + outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_qpathinfo); break; case TRANSACT2_SETPATHINFO: case TRANSACT2_SETFILEINFO: START_PROFILE_NESTED(Trans2_setpathinfo); - outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data, - total_data); + outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_setpathinfo); break; case TRANSACT2_FINDNOTIFYFIRST: START_PROFILE_NESTED(Trans2_findnotifyfirst); - outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data); + outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_findnotifyfirst); break; case TRANSACT2_FINDNOTIFYNEXT: START_PROFILE_NESTED(Trans2_findnotifynext); - outsize = call_trans2findnotifynext(conn, inbuf, outbuf, - length, bufsize, - ¶ms, &data); + outsize = call_trans2findnotifynext(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_findnotifynext); break; case TRANSACT2_MKDIR: START_PROFILE_NESTED(Trans2_mkdir); - outsize = call_trans2mkdir(conn, inbuf, outbuf, length, - bufsize, ¶ms, &data); + outsize = call_trans2mkdir(conn, inbuf, outbuf, length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_mkdir); break; case TRANSACT2_GET_DFS_REFERRAL: START_PROFILE_NESTED(Trans2_get_dfs_referral); - outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, - bufsize, ¶ms, &data); + outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_get_dfs_referral); break; case TRANSACT2_IOCTL: START_PROFILE_NESTED(Trans2_ioctl); - outsize = call_trans2ioctl(conn,inbuf,outbuf,length, - bufsize,¶ms,&data); + outsize = call_trans2ioctl(conn,inbuf,outbuf,length, bufsize, + ¶ms, total_params, &data, total_data); END_PROFILE_NESTED(Trans2_ioctl); break; default: diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index ac0b535c13d..a18f62c9cc8 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -465,11 +465,11 @@ BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_N if (ret) { DEBUG(10, - ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %u)\n", + ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n", domain, name, sid_to_string(sid,psid), - (unsigned int)*name_type )); + sid_type_lookup(*name_type), (unsigned int)*name_type)); return True; - } else if (winbind_lookup_name(domain, name, psid, name_type) || (*name_type != SID_NAME_USER) ) { + } else 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), @@ -504,7 +504,7 @@ BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE sid_copy(&tmp_sid, sid); sid_split_rid(&tmp_sid, &rid); - if (sid_equal(&global_sam_sid, &tmp_sid)) { + 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); @@ -521,7 +521,7 @@ BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE 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); + lookup_known_rid(&tmp_sid, rid, name, name_type); } return True; } @@ -578,7 +578,8 @@ DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid) } } - local_gid_to_sid(psid, gid); + /* Make sure we report failure, (when psid == NULL) */ + psid = local_gid_to_sid(psid, gid); DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid))); @@ -597,7 +598,7 @@ BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype) fstring sid_str; /* if we know its local then don't try winbindd */ - if (sid_compare_domain(&global_sam_sid, psid) == 0) { + if (sid_compare_domain(get_global_sam_sid(), psid) == 0) { return local_sid_to_uid(puid, psid, sidtype); } diff --git a/source3/smbd/vfs-wrap.c b/source3/smbd/vfs-wrap.c index fadc435a2fa..394086dc075 100644 --- a/source3/smbd/vfs-wrap.c +++ b/source3/smbd/vfs-wrap.c @@ -147,7 +147,7 @@ ssize_t vfswrap_read(files_struct *fsp, int fd, void *data, size_t n) ssize_t result; START_PROFILE_BYTES(syscall_read, n); - result = read(fd, data, n); + result = sys_read(fd, data, n); END_PROFILE(syscall_read); return result; } @@ -157,7 +157,7 @@ ssize_t vfswrap_write(files_struct *fsp, int fd, const void *data, size_t n) ssize_t result; START_PROFILE_BYTES(syscall_write, n); - result = write(fd, data, n); + result = sys_write(fd, data, n); END_PROFILE(syscall_write); return result; } diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 4e2e353ed8a..5e1dc68bdb4 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -32,7 +32,7 @@ struct vfs_syminfo { very important. They must be in the same order as defined in vfs.h. Change at your own peril. */ -struct vfs_ops default_vfs_ops = { +static struct vfs_ops default_vfs_ops = { /* Disk operations */ @@ -139,7 +139,7 @@ static BOOL vfs_init_custom(connection_struct *conn) /* Open object file */ if ((conn->dl_handle = sys_dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW | RTLD_GLOBAL)) == NULL) { - DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)), dlerror())); + DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)), sys_dlerror())); return False; } @@ -222,7 +222,7 @@ BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_ /******************************************************************* vfs getwd wrapper ********************************************************************/ -char *vfs_getwd(connection_struct *conn, char *path) +static char *vfs_getwd(connection_struct *conn, char *path) { return conn->vfs_ops.getwd(conn,path); } @@ -562,7 +562,7 @@ int vfs_ChDir(connection_struct *conn, char *path) /* number of list structures for a caching GetWd function. */ #define MAX_GETWDCACHE (50) -struct { +static struct { SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */ SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */ char *dos_path; /* The pathname in DOS format. */ |