diff options
58 files changed, 1365 insertions, 326 deletions
diff --git a/README.Coding b/README.Coding new file mode 100644 index 00000000000..ba9e8be08c5 --- /dev/null +++ b/README.Coding @@ -0,0 +1,215 @@ +## +## Coding conventions in the Samba 3.0 tree +## + +=========== +Quick Start +=========== + +Coding style guidelines are about reducing the number of unnecessary +reformatting patches and making things easier developers to work together. +You don't have to like them or even agree with them, but once put in place +we all have to abide by them (or vote to change them). However, coding +style should never outweigh coding itself and so the the guidelines +described here are hopefully easier enough to follow as they are very +common and supported by tools and editors. + +The basic style, also mentioned in the SAMBA_4_0/prog_guide.txt is the +Linux kernel coding style (See Documentation/CodingStyle in the kernel +source tree). The closely matches what most Samba developers use already +anyways. + +But to save you the trouble of reading the Linux kernel style guide, here +are the highlights. + + +* Maximum Line Width is 80 Characters + The reason is not for people with low-res screens but rather sticking + to 80 columns prevents you from easily nesting more than one level of + if statements or other code blocks. Use source/script/count_80_col.pl + to check your changes. + +* Use 8 Space Tabs to Indent + No whitespace filler. + +* No Trailing Whitespace + Use source/script/strip_trail_ws.pl to clean you files before committing. + +* Follow the K&R guidelines. We won't go throw them all here. You have + a copy of "The C Programming Language" anyways right? You can also use + the format_indent.sh script found in source/script/ if all else fails. + + + +============ +Editor Hints +============ + +Emacs +----- +Add the follow to your $HOME/.emacs file: + + (add-hook 'c-mode-hook + (lambda () + (c-set-style "linux") + (c-toggle-auto-state))) + + +Vi +-- +(Thanks to SATOH Fumiyasu <fumiyas@osstech.jp> for these hints): + +For the basic vi editor including with all variants of *nix, add the +following to $HOME/.exrc: + + set tabstop=8 + set shiftwidth=8 + +For Vim, the following settings in $HOME/.vimrc will also deal with +displaying trailing whitespace: + + if has("syntax") && (&t_Co > 2 || has("gui_running")) + syntax on + function! ActivateInvisibleCharIndicator() + syntax match TrailingSpace "[ \t]\+$" display containedin=ALL + highlight TrailingSpace ctermbg=Red + endf + autocmd BufNewFile,BufRead * call ActivateInvisibleCharIndicator() + endif + + +========================= +FAQ & Statement Reference +========================= + +Comments +-------- + +Comments should always use the standard C syntax. I.e. /* ... */. C++ +style comments are not currently allowed. + + +Indention & Whitespace & 80 columns +----------------------------------- + +To avoid confusion, indentations are to be 8 character with tab (not +8 ' ' characters. When wrapping parameters for function calls, +alignment parameter list with the first parameter on the previous line. +Use tabs to get as close as possible and then fill in the final 7 +characters or less with whitespace. For example, + + var1 = foo(arg1, arg2, + arg3); + +The previous example is intended to illustrate alignment of function +parameters across lines and not as encourage for gratuitous line +splitting. Never split a line before columns 70 - 79 unless you +have a really good reason. Be smart about formatting. + + +If, switch, & Code blocks +------------------------- + +Always follow an 'if' keyword with a space but don't include additional +spaces following or preceding the parentheses in the conditional. +This is good: + + if (x == 1) + +This is bad: + + if ( x == 1 ) + +Yes we have a lot of code that uses the second form and we are trying +to clean it up without being overly intrusive. + +Note that this is a rule about parentheses following keywords and not +functions. Don't insert a space between the name and left parentheses when +invoking functions. + +Braces for code blocks used by for, if, switch, while, do..while, etc... +should begin on the same line as the statement keyword and end on a line +of their own. NOTE: Functions are different and the beginning left brace +should begin on a line of its own. + +If the beginning statement has to be broken across lines due to length, +the beginning brace should be on a line of its own. + +The exception to the ending rule is when the closing brace is followed by +another language keyword such as else or the closing while in a do..while +loop. + +Good examples: + + if (x == 1) { + printf("good\n"); + } + + for (x=1; + x<10; + x++) + { + print("%d\n", x); + } + + do { + printf("also good\n"); + } while (1); + +Bad examples: + + while (1) + { + print("I'm in a loop!\n"); } + + +Goto +---- + +While many people have been academically taught that goto's are fundamentally +evil, then can greatly enhance readability and reduce memory leaks when used +as the single exit point from a function. But in no Samba world what so ever +is a goto outside of a function or block of code a good idea. + +Good Examples: + +int function foo(int y) +{ + int *z = NULL; + int ret = 0; + + if ( y < 10 ) { + z = malloc(sizeof(int)*y); + if (!z) { + ret = 1; + goto done; + } + } + + print("Allocated %d elements.\n", y); + + done: + if (z) + free(z); + + return ret; +} + + +Checking Pointer Values +----------------------- + +When invoking functions that return pointer values, either of the following +are acceptable. Use you best judgement and choose the more readable option. +Remember that many other people will review it. + + if ((x = malloc(sizeof(short)*10)) == NULL ) { + fprintf(stderr, "Unable to alloc memory!\n"); + } + +or + + x = malloc(sizeof(short)*10); + if (!x) { + fprintf(stderr, "Unable to alloc memory!\n"); + } diff --git a/source/aclocal.m4 b/source/aclocal.m4 index d36749a5f50..0b9bc0b689c 100644 --- a/source/aclocal.m4 +++ b/source/aclocal.m4 @@ -362,23 +362,6 @@ AC_DEFUN(jm_ICONV, jm_cv_func_iconv=yes jm_cv_lib_iconv="iconv") LIBS="$jm_save_LIBS" - - if test "$jm_cv_lib_iconv" != yes; then - jm_save_LIBS="$LIBS" - LIBS="$LIBS -lbiconv" - AC_TRY_LINK([#include <stdlib.h> -#include <biconv.h>], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - jm_cv_lib_iconv=yes - jm_cv_func_iconv=yes - jm_cv_include="biconv.h" - jm_cv_biconv=yes - jm_cv_lib_iconv="biconv") - - LIBS="$jm_save_LIBS" - fi fi fi fi diff --git a/source/auth/auth_server.c b/source/auth/auth_server.c index 3e29c246491..d490b1a467b 100644 --- a/source/auth/auth_server.c +++ b/source/auth/auth_server.c @@ -49,6 +49,8 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) p = pserver; while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) { + NTSTATUS status; + standard_sub_basic(current_user_info.smb_name, current_user_info.domain, desthost, sizeof(desthost)); strupper_m(desthost); @@ -72,11 +74,14 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) return NULL; } - if (cli_connect(cli, desthost, &dest_ip)) { + status = cli_connect(cli, desthost, &dest_ip); + if (NT_STATUS_IS_OK(status)) { DEBUG(3,("connected to password server %s\n",desthost)); connected_ok = True; break; } + DEBUG(10,("server_cryptkey: failed to connect to server %s. Error %s\n", + desthost, nt_errstr(status) )); } if (!connected_ok) { diff --git a/source/client/client.c b/source/client/client.c index 727e8db1f11..d05a2b8975a 100644 --- a/source/client/client.c +++ b/source/client/client.c @@ -2649,7 +2649,8 @@ static int cmd_rename(void) pstring src,dest; pstring buf,buf2; struct cli_state *targetcli; - pstring targetname; + pstring targetsrc; + pstring targetdest; pstrcpy(src,cur_dir); pstrcpy(dest,cur_dir); @@ -2663,13 +2664,21 @@ static int cmd_rename(void) pstrcat(src,buf); pstrcat(dest,buf2); - if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) { - d_printf("chown %s: %s\n", src, cli_errstr(cli)); + if ( !cli_resolve_path( "", cli, src, &targetcli, targetsrc ) ) { + d_printf("rename %s: %s\n", src, cli_errstr(cli)); + return 1; + } + + if ( !cli_resolve_path( "", cli, dest, &targetcli, targetdest ) ) { + d_printf("rename %s: %s\n", dest, cli_errstr(cli)); return 1; } - if (!cli_rename(targetcli, targetname, dest)) { - d_printf("%s renaming files\n",cli_errstr(targetcli)); + if (!cli_rename(targetcli, targetsrc, targetdest)) { + d_printf("%s renaming files %s -> %s \n", + cli_errstr(targetcli), + targetsrc, + targetdest); return 1; } @@ -3796,6 +3805,7 @@ static int do_message_op(void) fstring server_name; char name_type_hex[10]; int msg_port; + NTSTATUS status; make_nmb_name(&calling, calling_name, 0x0); make_nmb_name(&called , desthost, name_type); @@ -3812,12 +3822,17 @@ static int do_message_op(void) msg_port = port ? port : 139; - if (!(cli=cli_initialise()) || (cli_set_port(cli, msg_port) != msg_port) || - !cli_connect(cli, server_name, &ip)) { + if (!(cli=cli_initialise()) || (cli_set_port(cli, msg_port) != msg_port)) { d_printf("Connection to %s failed\n", desthost); return 1; } + status = cli_connect(cli, server_name, &ip); + if (!NT_STATUS_IS_OK(status)) { + d_printf("Connection to %s failed. Error %s\n", desthost, nt_errstr(status)); + return 1; + } + if (!cli_session_request(cli, &calling, &called)) { d_printf("session request failed\n"); cli_cm_shutdown(); diff --git a/source/client/smbmount.c b/source/client/smbmount.c index cce03e59a94..b1462dbddf1 100644 --- a/source/client/smbmount.c +++ b/source/client/smbmount.c @@ -152,7 +152,7 @@ static struct cli_state *do_connection(char *the_service) /* have to open a new connection */ if (!(c=cli_initialise()) || (cli_set_port(c, smb_port) != smb_port) || - !cli_connect(c, server_n, &ip)) { + !NT_STATUS_IS_OK(cli_connect(c, server_n, &ip))) { DEBUG(0,("%d: Connection to %s failed\n", sys_getpid(), server_n)); if (c) { cli_shutdown(c); diff --git a/source/configure.in b/source/configure.in index f16766e0510..74fc8732f09 100644 --- a/source/configure.in +++ b/source/configure.in @@ -1591,6 +1591,14 @@ case "$host_os" in esac ######################################################## +# Check if attropen() is present if this is Solaris +case "$host_os" in + *solaris*) + AC_CHECK_FUNCS(attropen) + ;; +esac + +######################################################## # Do xattr functions take additional options like on Darwin? if test x"$ac_cv_func_getxattr" = x"yes" ; then AC_CACHE_CHECK([whether xattr interface takes additional options], smb_attr_cv_xattr_add_opt, [ diff --git a/source/include/includes.h b/source/include/includes.h index f8c2b50fd3d..3ddfc7d96d6 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -225,6 +225,10 @@ typedef int ber_int_t; #include <sys/attributes.h> #endif +#ifndef ENOATTR +#define ENOATTR ENODATA +#endif + /* mutually exclusive (SuSE 8.2) */ #if HAVE_ATTR_XATTR_H #include <attr/xattr.h> @@ -757,8 +761,6 @@ struct functable2 { struct printjob; -struct smb_ldap_privates; - /* forward declarations from smbldap.c */ #include "smbldap.h" diff --git a/source/include/rpc_samr.h b/source/include/rpc_samr.h index 9a5484598a4..575cd78ef2f 100644 --- a/source/include/rpc_samr.h +++ b/source/include/rpc_samr.h @@ -262,7 +262,19 @@ typedef struct sam_user_info_25 uint32 acb_info; /* account info (ACB_xxxx bit-mask) */ uint32 fields_present; - uint32 unknown_5[5]; + uint16 logon_divs; /* 0x0000 00a8 which is 168 which is num hrs in a week */ + /* uint8 pad[2] */ + uint32 ptr_logon_hrs; /* pointer to logon hours */ + + /* Was unknown_5. */ + uint16 bad_password_count; + uint16 logon_count; + + uint8 padding1[6]; + + uint8 passmustchange; /* 0x00 must change = 0x01 */ + + uint8 padding2; uint8 pass[532]; @@ -276,6 +288,8 @@ typedef struct sam_user_info_25 UNISTR2 uni_workstations; /* login from workstations unicode string */ UNISTR2 uni_comment; UNISTR2 uni_munged_dial ; /* munged path name and dial-back tel no */ + LOGON_HRS logon_hrs; + } SAM_USER_INFO_25; /* SAM_USER_INFO_26 */ diff --git a/source/include/smb_macros.h b/source/include/smb_macros.h index d26433359be..a16ea7500f2 100644 --- a/source/include/smb_macros.h +++ b/source/include/smb_macros.h @@ -166,6 +166,7 @@ #define ERROR_DOS(class,code) error_packet(outbuf,class,code,NT_STATUS_OK,__LINE__,__FILE__) #define ERROR_NT(status) error_packet(outbuf,0,0,status,__LINE__,__FILE__) +#define ERROR_OPEN(status) error_open(outbuf,status,__LINE__,__FILE__) #define ERROR_FORCE_NT(status) error_packet(outbuf,-1,-1,status,__LINE__,__FILE__) #define ERROR_BOTH(status,class,code) error_packet(outbuf,class,code,status,__LINE__,__FILE__) diff --git a/source/lib/iconv.c b/source/lib/iconv.c index 6e040b77f17..90e2faab6fb 100644 --- a/source/lib/iconv.c +++ b/source/lib/iconv.c @@ -544,6 +544,8 @@ static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft, uint8 *uc = (uint8 *)*outbuf; while (in_left >= 1 && out_left >= 2) { + unsigned int codepoint; + if ((c[0] & 0x80) == 0) { uc[0] = c[0]; uc[1] = 0; @@ -560,8 +562,14 @@ static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft, errno = EILSEQ; goto error; } - uc[1] = (c[0]>>2) & 0x7; - uc[0] = (c[0]<<6) | (c[1]&0x3f); + codepoint = (c[1]&0x3f) | ((c[0]&0x1f)<<6); + if (codepoint < 0x80) { + /* don't accept UTF-8 characters that are not minimally packed */ + errno = EILSEQ; + goto error; + } + uc[1] = codepoint >> 8; + uc[0] = codepoint & 0xff; c += 2; in_left -= 2; out_left -= 2; @@ -576,8 +584,14 @@ static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft, errno = EILSEQ; goto error; } - uc[1] = ((c[0]&0xF)<<4) | ((c[1]>>2)&0xF); - uc[0] = (c[1]<<6) | (c[2]&0x3f); + codepoint = (c[2]&0x3f) | ((c[1]&0x3f)<<6) | ((c[0]&0xf)<<12); + if (codepoint < 0x800) { + /* don't accept UTF-8 characters that are not minimally packed */ + errno = EILSEQ; + goto error; + } + uc[1] = codepoint >> 8; + uc[0] = codepoint & 0xff; c += 3; in_left -= 3; out_left -= 2; @@ -586,7 +600,6 @@ static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft, } if ((c[0] & 0xf8) == 0xf0) { - unsigned int codepoint; if (in_left < 4 || (c[1] & 0xc0) != 0x80 || (c[2] & 0xc0) != 0x80 || @@ -599,16 +612,10 @@ static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft, ((c[2]&0x3f)<<6) | ((c[1]&0x3f)<<12) | ((c[0]&0x7)<<18); - if (codepoint < 0x10000) { - /* accept UTF-8 characters that are not - minimally packed, but pack the result */ - uc[0] = (codepoint & 0xFF); - uc[1] = (codepoint >> 8); - c += 4; - in_left -= 4; - out_left -= 2; - uc += 2; - continue; + if (codepoint < 0x10000 || codepoint > 0x10ffff) { + /* don't accept UTF-8 characters that are not minimally packed */ + errno = EILSEQ; + goto error; } codepoint -= 0x10000; diff --git a/source/lib/messages.c b/source/lib/messages.c index 8e2456d5a5a..88b5f3ab936 100644 --- a/source/lib/messages.c +++ b/source/lib/messages.c @@ -281,12 +281,14 @@ static NTSTATUS message_send_pid_internal(struct process_id pid, int msg_type, if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) { DEBUG(0,("message_send_pid_internal: failed to get " "chainlock with timeout %ul.\n", timeout)); + SAFE_FREE(dbuf.dptr); return NT_STATUS_IO_TIMEOUT; } } else { if (tdb_chainlock(tdb, kbuf) == -1) { DEBUG(0,("message_send_pid_internal: failed to get " "chainlock.\n")); + SAFE_FREE(dbuf.dptr); return NT_STATUS_LOCK_NOT_GRANTED; } } @@ -303,12 +305,14 @@ static NTSTATUS message_send_pid_internal(struct process_id pid, int msg_type, if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock " "with timeout %ul.\n", timeout)); + SAFE_FREE(dbuf.dptr); return NT_STATUS_IO_TIMEOUT; } } else { if (tdb_chainlock(tdb, kbuf) == -1) { DEBUG(0,("message_send_pid_internal: failed to get " "chainlock.\n")); + SAFE_FREE(dbuf.dptr); return NT_STATUS_LOCK_NOT_GRANTED; } } diff --git a/source/lib/pidfile.c b/source/lib/pidfile.c index 89ab6d799b7..42ecede1175 100644 --- a/source/lib/pidfile.c +++ b/source/lib/pidfile.c @@ -100,7 +100,8 @@ void pidfile_create(const char *program_name) /* full/relative path provided */ short_configfile++; } - slprintf( name, sizeof( name)-1, "%s-%s", program_name, short_configfile+1); + slprintf( name, sizeof( name)-1, "%s-%s", program_name, + short_configfile ); } slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_piddir(), name); diff --git a/source/lib/system.c b/source/lib/system.c index eaebc7190f0..1094cd20d61 100644 --- a/source/lib/system.c +++ b/source/lib/system.c @@ -4,6 +4,7 @@ Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Jeremy Allison 1998-2005 Copyright (C) Timur Bakeyev 2005 + Copyright (C) Bjoern Jacke 2006-2007 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 @@ -1561,6 +1562,17 @@ int sys_dup2(int oldfd, int newfd) SAFE_FREE(msgbuf); } +/******** Solaris EA helper function prototypes ********/ +#ifdef HAVE_ATTROPEN +#define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP +int solaris_write_xattr(int attrfd, const char *value, size_t size); +ssize_t solaris_read_xattr(int attrfd, void *value, size_t size); +ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size); +int solaris_unlinkat(int attrdirfd, const char *name); +int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode); +int solaris_openat(int fildes, const char *path, int oflag, mode_t mode); +#endif + /************************************************************************** Wrappers for extented attribute calls. Based on the Linux package with support for IRIX and (Net|Free)BSD also. Expand as other systems have them. @@ -1609,6 +1621,14 @@ ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t si retval = attr_get(path, attrname, (char *)value, &valuelength, flags); return retval ? retval : valuelength; +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrfd = solaris_attropen(path, name, O_RDONLY, 0); + if (attrfd >= 0) { + ret = solaris_read_xattr(attrfd, value, size); + close(attrfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -1652,6 +1672,14 @@ ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t s retval = attr_get(path, attrname, (char *)value, &valuelength, flags); return retval ? retval : valuelength; +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0); + if (attrfd >= 0) { + ret = solaris_read_xattr(attrfd, value, size); + close(attrfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -1697,6 +1725,14 @@ ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size) retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags); return retval ? retval : valuelength; +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0); + if (attrfd >= 0) { + ret = solaris_read_xattr(attrfd, value, size); + close(attrfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -1881,6 +1917,14 @@ ssize_t sys_listxattr (const char *path, char *list, size_t size) return bsd_attr_list(0, arg, list, size); #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H) return irix_attr_list(path, 0, list, size, 0); +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0); + if (attrdirfd >= 0) { + ret = solaris_list_xattr(attrdirfd, list, size); + close(attrdirfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -1902,6 +1946,14 @@ ssize_t sys_llistxattr (const char *path, char *list, size_t size) return bsd_attr_list(1, arg, list, size); #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H) return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW); +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0); + if (attrdirfd >= 0) { + ret = solaris_list_xattr(attrdirfd, list, size); + close(attrdirfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -1925,6 +1977,14 @@ ssize_t sys_flistxattr (int filedes, char *list, size_t size) return bsd_attr_list(2, arg, list, size); #elif defined(HAVE_ATTR_LISTF) return irix_attr_list(NULL, filedes, list, size, 0); +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0); + if (attrdirfd >= 0) { + ret = solaris_list_xattr(attrdirfd, list, size); + close(attrdirfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -1956,6 +2016,14 @@ int sys_removexattr (const char *path, const char *name) if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; return attr_remove(path, attrname, flags); +#elif defined(HAVE_ATTROPEN) + int ret = -1; + int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0); + if (attrdirfd >= 0) { + ret = solaris_unlinkat(attrdirfd, name); + close(attrdirfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -1985,6 +2053,14 @@ int sys_lremovexattr (const char *path, const char *name) if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; return attr_remove(path, attrname, flags); +#elif defined(HAVE_ATTROPEN) + int ret = -1; + int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0); + if (attrdirfd >= 0) { + ret = solaris_unlinkat(attrdirfd, name); + close(attrdirfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -2016,6 +2092,14 @@ int sys_fremovexattr (int filedes, const char *name) if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; return attr_removef(filedes, attrname, flags); +#elif defined(HAVE_ATTROPEN) + int ret = -1; + int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0); + if (attrdirfd >= 0) { + ret = solaris_unlinkat(attrdirfd, name); + close(attrdirfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -2074,6 +2158,17 @@ int sys_setxattr (const char *path, const char *name, const void *value, size_t if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; return attr_set(path, attrname, (const char *)value, size, myflags); +#elif defined(HAVE_ATTROPEN) + int ret = -1; + int myflags = O_RDWR; + if (flags & XATTR_CREATE) myflags |= O_EXCL; + if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; + int attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE); + if (attrfd >= 0) { + ret = solaris_write_xattr(attrfd, value, size); + close(attrfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -2126,6 +2221,17 @@ int sys_lsetxattr (const char *path, const char *name, const void *value, size_t if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; return attr_set(path, attrname, (const char *)value, size, myflags); +#elif defined(HAVE_ATTROPEN) + int ret = -1; + int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW; + if (flags & XATTR_CREATE) myflags |= O_EXCL; + if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; + int attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE); + if (attrfd >= 0) { + ret = solaris_write_xattr(attrfd, value, size); + close(attrfd); + } + return ret; #else errno = ENOSYS; return -1; @@ -2179,12 +2285,147 @@ int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; return attr_setf(filedes, attrname, (const char *)value, size, myflags); +#elif defined(HAVE_ATTROPEN) + int ret = -1; + int myflags = O_RDWR | O_XATTR; + if (flags & XATTR_CREATE) myflags |= O_EXCL; + if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; + int attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE); + if (attrfd >= 0) { + ret = solaris_write_xattr(attrfd, value, size); + close(attrfd); + } + return ret; #else errno = ENOSYS; return -1; #endif } +/************************************************************************** + helper functions for Solaris' EA support +****************************************************************************/ +#ifdef HAVE_ATTROPEN +static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size) +{ + struct stat sbuf; + + if (fstat(attrfd, &sbuf) == -1) { + errno = ENOATTR; + return -1; + } + + /* This is to return the current size of the named extended attribute */ + if (size == 0) { + return sbuf.st_size; + } + + /* check size and read xattr */ + if (sbuf.st_size > size) { + errno = ERANGE; + return -1; + } + + return read(attrfd, value, sbuf.st_size); +} + +static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size) +{ + ssize_t len = 0; + int stop = 0; + DIR *dirp; + struct dirent *de; + int newfd = dup(attrdirfd); + /* CAUTION: The originating file descriptor should not be + used again following the call to fdopendir(). + For that reason we dup() the file descriptor + here to make things more clear. */ + dirp = fdopendir(newfd); + + while ((de = readdir(dirp))) { + size_t listlen = strlen(de->d_name); + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { + /* we don't want "." and ".." here: */ + DEBUG(10,("skipped EA %s\n",de->d_name)); + continue; + } + + if (size == 0) { + /* return the current size of the list of extended attribute names*/ + len += listlen + 1; + } else { + /* check size and copy entrieѕ + nul into list. */ + if ((len + listlen + 1) > size) { + errno = ERANGE; + len = -1; + break; + } else { + safe_strcpy(list + len, de->d_name, listlen); + pstrcpy(list + len, de->d_name); + len += listlen; + list[len] = '\0'; + ++len; + } + } + } + + if (closedir(dirp) == -1) { + DEBUG(0,("closedir dirp failed: %s\n",strerror(errno))); + return -1; + } + return len; +} + +static int solaris_unlinkat(int attrdirfd, const char *name) +{ + if (unlinkat(attrdirfd, name, 0) == -1) { + if (errno == ENOENT) { + errno = ENOATTR; + } + return -1; + } + return 0; +} + +static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode) +{ + int filedes = attropen(path, attrpath, oflag, mode); + if (filedes == -1) { + DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno))); + if (errno == EINVAL) { + errno = ENOTSUP; + } else { + errno = ENOATTR; + } + } + return filedes; +} + +static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode) +{ + int filedes = openat(fildes, path, oflag, mode); + if (filedes == -1) { + DEBUG(10,("openat FAILED: fd: %s, path: %s, errno: %s\n",filedes,path,strerror(errno))); + if (errno == EINVAL) { + errno = ENOTSUP; + } else { + errno = ENOATTR; + } + } + return filedes; +} + +static int solaris_write_xattr(int attrfd, const char *value, size_t size) +{ + if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) { + return 0; + } else { + DEBUG(10,("solaris_write_xattr FAILED!\n")); + return -1; + } +} +#endif /*HAVE_ATTROPEN*/ + /**************************************************************************** Return the major devicenumber for UNIX extensions. ****************************************************************************/ diff --git a/source/lib/util.c b/source/lib/util.c index 90100d83374..6ce260d5e54 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -1833,8 +1833,7 @@ const char *readdirname(SMB_STRUCT_DIR *p) BOOL is_in_path(const char *name, name_compare_entry *namelist, BOOL case_sensitive) { - pstring last_component; - char *p; + const char *last_component; /* if we have no list it's obviously not in the path */ if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) { @@ -1844,8 +1843,12 @@ BOOL is_in_path(const char *name, name_compare_entry *namelist, BOOL case_sensit DEBUG(8, ("is_in_path: %s\n", name)); /* Get the last component of the unix name. */ - p = strrchr_m(name, '/'); - pstrcpy(last_component, p ? ++p : name); + last_component = strrchr_m(name, '/'); + if (!last_component) { + last_component = name; + } else { + last_component++; /* Go past '/' */ + } for(; namelist->name != NULL; namelist++) { if(namelist->is_wild) { @@ -1862,7 +1865,6 @@ BOOL is_in_path(const char *name, name_compare_entry *namelist, BOOL case_sensit } } DEBUG(8,("is_in_path: match not found\n")); - return False; } @@ -2748,7 +2750,7 @@ BOOL ms_has_wild_w(const smb_ucs2_t *s) of the ".." name. *******************************************************************/ -BOOL mask_match(const char *string, char *pattern, BOOL is_case_sensitive) +BOOL mask_match(const char *string, const char *pattern, BOOL is_case_sensitive) { if (strcmp(string,"..") == 0) string = "."; @@ -2764,7 +2766,7 @@ BOOL mask_match(const char *string, char *pattern, BOOL is_case_sensitive) pattern translation. *******************************************************************/ -BOOL mask_match_search(const char *string, char *pattern, BOOL is_case_sensitive) +BOOL mask_match_search(const char *string, const char *pattern, BOOL is_case_sensitive) { if (strcmp(string,"..") == 0) string = "."; diff --git a/source/libads/dns.c b/source/libads/dns.c index f16cea25554..bf51625797a 100644 --- a/source/libads/dns.c +++ b/source/libads/dns.c @@ -606,8 +606,6 @@ static char *sitename_key(const char *realm) /**************************************************************************** Store the AD client sitename. We store indefinately as every new CLDAP query will re-write this. - If the sitename is "Default-First-Site-Name" we don't store it - as this isn't a valid DNS name. ****************************************************************************/ BOOL sitename_store(const char *realm, const char *sitename) @@ -621,7 +619,7 @@ BOOL sitename_store(const char *realm, const char *sitename) } if (!realm || (strlen(realm) == 0)) { - DEBUG(0,("no realm\n")); + DEBUG(0,("sitename_store: no realm\n")); return False; } @@ -692,7 +690,7 @@ BOOL stored_sitename_changed(const char *realm, const char *sitename) char *new_sitename; if (!realm || (strlen(realm) == 0)) { - DEBUG(0,("no realm\n")); + DEBUG(0,("stored_sitename_changed: no realm\n")); return False; } diff --git a/source/libads/ldap.c b/source/libads/ldap.c index 452a2285313..5d498abb1c0 100644 --- a/source/libads/ldap.c +++ b/source/libads/ldap.c @@ -2618,7 +2618,7 @@ ADS_STATUS ads_site_dn_for_machine(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const c if (*site_dn == NULL) { ads_msgfree(ads, res); ads_memfree(ads, dn); - ADS_ERROR(LDAP_NO_MEMORY); + return ADS_ERROR(LDAP_NO_MEMORY); } ads_memfree(ads, dn); diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c index dd84db319eb..d458ce2757c 100644 --- a/source/libsmb/cliconnect.c +++ b/source/libsmb/cliconnect.c @@ -584,6 +584,7 @@ static BOOL cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob, DATA_B NT_STATUS_MORE_PROCESSING_REQUIRED)) { DEBUG(0, ("cli_session_setup_blob: recieve failed (%s)\n", nt_errstr(cli_get_nt_error(cli)) )); + cli->vuid = 0; return False; } } @@ -770,6 +771,9 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use ntlmssp_end(&ntlmssp_state); + if (!NT_STATUS_IS_OK(nt_status)) { + cli->vuid = 0; + } return nt_status; } @@ -1402,7 +1406,7 @@ BOOL cli_session_request(struct cli_state *cli, Open the client sockets. ****************************************************************************/ -BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip) +NTSTATUS cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip) { int name_type = 0x20; char *p; @@ -1420,7 +1424,7 @@ BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip) if (!ip || is_zero_ip(*ip)) { if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) { - return False; + return NT_STATUS_BAD_NETWORK_NAME; } if (ip) *ip = cli->dest_ip; } else { @@ -1445,12 +1449,12 @@ BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip) if (cli->fd == -1) { DEBUG(1,("Error connecting to %s (%s)\n", ip?inet_ntoa(*ip):host,strerror(errno))); - return False; + return map_nt_error_from_unix(errno); } set_socket_options(cli->fd,user_socket_options); - return True; + return NT_STATUS_OK; } /** @@ -1504,15 +1508,12 @@ again: DEBUG(3,("Connecting to host=%s\n", dest_host)); - if (!cli_connect(cli, dest_host, &ip)) { - DEBUG(1,("cli_start_connection: failed to connect to %s (%s)\n", - nmb_namestr(&called), inet_ntoa(ip))); + nt_status = cli_connect(cli, dest_host, &ip); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n", + nmb_namestr(&called), inet_ntoa(ip), nt_errstr(nt_status) )); cli_shutdown(cli); - if (is_zero_ip(ip)) { - return NT_STATUS_BAD_NETWORK_NAME; - } else { - return NT_STATUS_CONNECTION_REFUSED; - } + return nt_status; } if (retry) @@ -1657,6 +1658,7 @@ BOOL attempt_netbios_session_request(struct cli_state **ppcli, const char *srcho } if (!cli_session_request(*ppcli, &calling, &called)) { + NTSTATUS status; struct nmb_name smbservername; make_nmb_name(&smbservername , "*SMBSERVER", 0x20); @@ -1686,7 +1688,8 @@ with error %s.\n", desthost, cli_errstr(*ppcli) )); return False; } - if (!cli_connect(*ppcli, desthost, pdest_ip) || + status = cli_connect(*ppcli, desthost, pdest_ip); + if (!NT_STATUS_IS_OK(status) || !cli_session_request(*ppcli, &calling, &smbservername)) { DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \ name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) )); diff --git a/source/libsmb/clidfs.c b/source/libsmb/clidfs.c index 4009b98b418..d5e31b5eb85 100644 --- a/source/libsmb/clidfs.c +++ b/source/libsmb/clidfs.c @@ -69,6 +69,7 @@ static struct cli_state *do_connect( const char *server, const char *share, pstring servicename; char *sharename; fstring newserver, newshare; + NTSTATUS status; /* make a copy so we don't modify the global string 'service' */ pstrcpy(servicename, share); @@ -94,11 +95,15 @@ static struct cli_state *do_connect( const char *server, const char *share, ip = dest_ip; /* have to open a new connection */ - if (!(c=cli_initialise()) || (cli_set_port(c, port) != port) || - !cli_connect(c, server_n, &ip)) { + if (!(c=cli_initialise()) || (cli_set_port(c, port) != port)) { d_printf("Connection to %s failed\n", server_n); return NULL; } + status = cli_connect(c, server_n, &ip); + if (!NT_STATUS_IS_OK(status)) { + d_printf("Connection to %s failed (Error %s)\n", server_n, nt_errstr(status)); + return NULL; + } c->protocol = max_protocol; c->use_kerberos = use_kerberos; diff --git a/source/libsmb/errormap.c b/source/libsmb/errormap.c index cb5e8311cad..35da0f962be 100644 --- a/source/libsmb/errormap.c +++ b/source/libsmb/errormap.c @@ -1521,6 +1521,9 @@ const struct unix_error_map unix_dos_nt_errmap[] = { { ENOMEM, ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY }, { EISDIR, ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY}, { EMLINK, ERRDOS, ERRgeneral, NT_STATUS_TOO_MANY_LINKS }, +#ifdef ELOOP + { ELOOP, ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND }, +#endif #ifdef EDQUOT { EDQUOT, ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL }, /* Windows apps need this, not NT_STATUS_QUOTA_EXCEEDED */ #endif @@ -1542,6 +1545,34 @@ const struct unix_error_map unix_dos_nt_errmap[] = { #ifdef ENOBUFS { ENOBUFS, ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES }, #endif + { EAGAIN, ERRDOS, 111, NT_STATUS_NETWORK_BUSY }, +#ifdef EADDRINUSE + { EADDRINUSE, ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, +#endif +#ifdef ENETUNREACH + { ENETUNREACH, ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE}, +#endif +#ifdef EHOSTUNREACH + { EHOSTUNREACH, ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE}, +#endif +#ifdef ECONNREFUSED + { ECONNREFUSED, ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED}, +#endif +#ifdef ETIMEDOUT + { ETIMEDOUT, ERRHRD, 121, NT_STATUS_IO_TIMEOUT}, +#endif +#ifdef ECONNABORTED + { ECONNABORTED, ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED}, +#endif +#ifdef ENODEV + { ENODEV, ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST}, +#endif +#ifdef EPIPE + {EPIPE, ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, +#endif +#ifdef EWOULDBLOCK + { EWOULDBLOCK, ERRDOS, 111, NT_STATUS_NETWORK_BUSY }, +#endif { 0, 0, 0, NT_STATUS_OK } }; diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c index e04a6385a07..e13b21f1115 100644 --- a/source/libsmb/libsmbclient.c +++ b/source/libsmb/libsmbclient.c @@ -675,7 +675,8 @@ smbc_server(SMBCCTX *context, int port_try_first; int port_try_next; const char *username_used; - + NTSTATUS status; + zero_ip(&ip); ZERO_STRUCT(c); @@ -795,17 +796,19 @@ smbc_server(SMBCCTX *context, c->port = port_try_first; - if (!cli_connect(c, server_n, &ip)) { + status = cli_connect(c, server_n, &ip); + if (!NT_STATUS_IS_OK(status)) { /* First connection attempt failed. Try alternate port. */ c->port = port_try_next; - if (!cli_connect(c, server_n, &ip)) { - cli_shutdown(c); - errno = ETIMEDOUT; - return NULL; - } - } + status = cli_connect(c, server_n, &ip); + if (!NT_STATUS_IS_OK(status)) { + cli_shutdown(c); + errno = ETIMEDOUT; + return NULL; + } + } if (!cli_session_request(c, &calling, &called)) { cli_shutdown(c); @@ -3442,8 +3445,6 @@ static off_t smbc_telldir_ctx(SMBCCTX *context, SMBCFILE *dir) { - off_t ret_val; /* Squash warnings about cast */ - if (!context || !context->internal || !context->internal->_initialized) { @@ -3466,12 +3467,16 @@ smbc_telldir_ctx(SMBCCTX *context, } + /* See if we're already at the end. */ + if (dir->dir_next == NULL) { + /* We are. */ + return -1; + } + /* * We return the pointer here as the offset */ - ret_val = (off_t)(long)dir->dir_next; - return ret_val; - + return (off_t)(long)dir->dir_next->dirent; } /* @@ -3542,6 +3547,11 @@ smbc_lseekdir_ctx(SMBCCTX *context, } + if (offset == -1) { /* Seek to the end of the list */ + dir->dir_next = NULL; + return 0; + } + /* Now, run down the list and make sure that the entry is OK */ /* This may need to be changed if we change the format of the list */ @@ -4534,6 +4544,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_nt_owner) { @@ -4581,6 +4592,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_nt_group) { @@ -4626,6 +4638,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_nt_acl) { @@ -4716,6 +4729,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } } @@ -4790,6 +4804,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_dos_size) { @@ -4834,6 +4849,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_dos_create_time && @@ -4876,6 +4892,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_dos_access_time) { @@ -4917,6 +4934,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_dos_write_time) { @@ -4958,6 +4976,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_dos_change_time) { @@ -4999,6 +5018,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_dos_inode) { @@ -5043,6 +5063,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } /* Restore name pointer to its original value */ @@ -5137,8 +5158,8 @@ cacl_set(TALLOC_CTX *ctx, switch (mode) { case SMBC_XATTR_MODE_REMOVE_ALL: old->dacl->num_aces = 0; - SAFE_FREE(old->dacl->aces); - SAFE_FREE(old->dacl); + prs_mem_free(old->dacl->aces); + prs_mem_free(&old->dacl); old->dacl = NULL; dacl = old->dacl; break; @@ -5157,8 +5178,8 @@ cacl_set(TALLOC_CTX *ctx, } old->dacl->num_aces--; if (old->dacl->num_aces == 0) { - SAFE_FREE(old->dacl->aces); - SAFE_FREE(old->dacl); + prs_mem_free(&old->dacl->aces); + prs_mem_free(&old->dacl); old->dacl = NULL; } found = True; diff --git a/source/libsmb/passchange.c b/source/libsmb/passchange.c index 5b4b0896c0f..bfa513d002f 100644 --- a/source/libsmb/passchange.c +++ b/source/libsmb/passchange.c @@ -39,7 +39,7 @@ NTSTATUS remote_password_change(const char *remote_machine, const char *user_nam *err_str = '\0'; if(!resolve_name( remote_machine, &ip, 0x20)) { - slprintf(err_str, err_str_len-1, "unable to find an IP address for machine %s.\n", + slprintf(err_str, err_str_len-1, "Unable to find an IP address for machine %s.\n", remote_machine ); return NT_STATUS_UNSUCCESSFUL; } @@ -49,10 +49,10 @@ NTSTATUS remote_password_change(const char *remote_machine, const char *user_nam return NT_STATUS_NO_MEMORY; } - if (!cli_connect(cli, remote_machine, &ip)) { - slprintf(err_str, err_str_len-1, "unable to connect to SMB server on machine %s. Error was : %s.\n", - remote_machine, cli_errstr(cli) ); - result = cli_nt_error(cli); + result = cli_connect(cli, remote_machine, &ip); + if (!NT_STATUS_IS_OK(result)) { + slprintf(err_str, err_str_len-1, "Unable to connect to SMB server on machine %s. Error was : %s.\n", + remote_machine, nt_errstr(result) ); cli_shutdown(cli); return result; } diff --git a/source/locking/locking.c b/source/locking/locking.c index 56d8ff206fe..a0debcd8de5 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -41,6 +41,8 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_LOCKING +#define NO_LOCKING_COUNT (-1) + /* the locking database handle */ static TDB_CONTEXT *tdb; @@ -224,11 +226,19 @@ struct byte_range_lock *do_lock(files_struct *fsp, blocking_lock, plock_pid); - /* blocking ie. pending, locks also count here, - * as this is an efficiency counter to avoid checking - * the lock db. on close. JRA. */ + if (lock_flav == WINDOWS_LOCK && + fsp->current_lock_count != NO_LOCKING_COUNT) { + /* blocking ie. pending, locks also count here, + * as this is an efficiency counter to avoid checking + * the lock db. on close. JRA. */ - fsp->current_lock_count++; + fsp->current_lock_count++; + } else { + /* Notice that this has had a POSIX lock request. + * We can't count locks after this so forget them. + */ + fsp->current_lock_count = NO_LOCKING_COUNT; + } return br_lck; } @@ -276,8 +286,11 @@ NTSTATUS do_unlock(files_struct *fsp, return NT_STATUS_RANGE_NOT_LOCKED; } - SMB_ASSERT(fsp->current_lock_count > 0); - fsp->current_lock_count--; + if (lock_flav == WINDOWS_LOCK && + fsp->current_lock_count != NO_LOCKING_COUNT) { + SMB_ASSERT(fsp->current_lock_count > 0); + fsp->current_lock_count--; + } return NT_STATUS_OK; } @@ -326,8 +339,11 @@ NTSTATUS do_lock_cancel(files_struct *fsp, return NT_STATUS_DOS(ERRDOS, ERRcancelviolation); } - SMB_ASSERT(fsp->current_lock_count > 0); - fsp->current_lock_count--; + if (lock_flav == WINDOWS_LOCK && + fsp->current_lock_count != NO_LOCKING_COUNT) { + SMB_ASSERT(fsp->current_lock_count > 0); + fsp->current_lock_count--; + } return NT_STATUS_OK; } @@ -913,6 +929,14 @@ BOOL is_valid_share_mode_entry(const struct share_mode_entry *e) { int num_props = 0; + if (e->op_type == UNUSED_SHARE_MODE_ENTRY) { + /* cope with dead entries from the process not + existing. These should not be considered valid, + otherwise we end up doing zero timeout sharing + violation */ + return False; + } + num_props += ((e->op_type == NO_OPLOCK) ? 1 : 0); num_props += (EXCLUSIVE_OPLOCK_TYPE(e->op_type) ? 1 : 0); num_props += (LEVEL_II_OPLOCK_TYPE(e->op_type) ? 1 : 0); diff --git a/source/modules/nfs4_acls.h b/source/modules/nfs4_acls.h index 469a50af56a..13f373c16cc 100644 --- a/source/modules/nfs4_acls.h +++ b/source/modules/nfs4_acls.h @@ -138,7 +138,7 @@ size_t smb_get_nt_acl_nfs4(files_struct *fsp, * when applicable */ typedef BOOL (*set_nfs4acl_native_fn_t)(files_struct *, SMB4ACL_T *); -BOOL smb_set_nt_acl_nfs4(files_struct *fsp, +NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd, set_nfs4acl_native_fn_t set_nfs4_native); diff --git a/source/modules/vfs_readahead.c b/source/modules/vfs_readahead.c index 9c20acebd94..e0f137af81f 100644 --- a/source/modules/vfs_readahead.c +++ b/source/modules/vfs_readahead.c @@ -160,7 +160,7 @@ static int readahead_connect(struct vfs_handle_struct *handle, handle->data = (void *)rhd; handle->free_data = free_readahead_data; - return 0; + return SMB_VFS_NEXT_CONNECT(handle, service, user); } /******************************************************************* diff --git a/source/nmbd/nmbd_synclists.c b/source/nmbd/nmbd_synclists.c index 7fe39676c6f..fa1a41a5af7 100644 --- a/source/nmbd/nmbd_synclists.c +++ b/source/nmbd/nmbd_synclists.c @@ -71,6 +71,7 @@ static void sync_child(char *name, int nm_type, struct cli_state *cli; uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0; struct nmb_name called, calling; + NTSTATUS status; /* W2K DMB's return empty browse lists on port 445. Use 139. * Patch from Andy Levine andyl@epicrealm.com. @@ -81,7 +82,12 @@ static void sync_child(char *name, int nm_type, return; } - if (!cli_set_port(cli, 139) || !cli_connect(cli, name, &ip)) { + if (!cli_set_port(cli, 139)) { + return; + } + + status = cli_connect(cli, name, &ip); + if (!NT_STATUS_IS_OK(status)) { return; } diff --git a/source/nsswitch/nss_info.c b/source/nsswitch/nss_info.c index d2516296629..8c18162deb4 100644 --- a/source/nsswitch/nss_info.c +++ b/source/nsswitch/nss_info.c @@ -156,7 +156,7 @@ static BOOL parse_nss_parm( const char *config, char **backend, char **domain ) if ( !parse_nss_parm(nss_list[i], &backend, &domain) ) { DEBUG(0,("nss_init: failed to parse \"%s\"!\n", - nss_list[0])); + nss_list[i])); continue; } diff --git a/source/nsswitch/nss_info_template.c b/source/nsswitch/nss_info_template.c index 2a144288021..845371e53ba 100644 --- a/source/nsswitch/nss_info_template.c +++ b/source/nsswitch/nss_info_template.c @@ -42,7 +42,7 @@ static NTSTATUS nss_template_get_info( struct nss_domain_entry *e, char **homedir, char **shell, char **gecos, - uint32 *gid ) + gid_t *gid ) { if ( !homedir || !shell || !gecos ) return NT_STATUS_INVALID_PARAMETER; diff --git a/source/nsswitch/wbinfo.c b/source/nsswitch/wbinfo.c index 6db37fca80f..467afe82457 100644 --- a/source/nsswitch/wbinfo.c +++ b/source/nsswitch/wbinfo.c @@ -1459,37 +1459,16 @@ int main(int argc, char **argv, char **envp) break; } case 'K': { - BOOL got_error = False; uint32 flags = WBFLAG_PAM_KRB5 | WBFLAG_PAM_CACHED_LOGIN | WBFLAG_PAM_FALLBACK_AFTER_KRB5 | WBFLAG_PAM_INFO3_TEXT; - fstring tok; - int i; - const char *arg[] = { NULL, NULL }; - const char *cctypes[] = { "FILE", - "KCM", - "KCM:0", - "Garbage", - NULL, - "0"}; - - arg[0] = string_arg; - - while (next_token(arg, tok, LIST_SEP, sizeof(tok))) { - - for (i=0; i < ARRAY_SIZE(cctypes); i++) { - if (!wbinfo_auth_krb5(tok, cctypes[i], flags)) { - d_fprintf(stderr, "Could not authenticate user [%s] with " - "Kerberos (ccache: %s)\n", tok, cctypes[i]); - got_error = True; - } - } - } - if (got_error) + if (!wbinfo_auth_krb5(string_arg, "FILE", flags)) { + d_fprintf(stderr, "Could not authenticate user [%s] with " + "Kerberos (ccache: %s)\n", string_arg, "FILE"); goto done; - + } break; } case 'k': diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c index 9a0ade55416..d2daf7830db 100644 --- a/source/nsswitch/winbindd_util.c +++ b/source/nsswitch/winbindd_util.c @@ -37,14 +37,6 @@ extern struct winbindd_methods passdb_methods; **/ -/** - * Used to clobber name fields that have an undefined value. - * - * Correct code should never look at a field that has this value. - **/ - -static const fstring name_deadbeef = "<deadbeef>"; - /* The list of trusted domains. Note that the list can be deleted and recreated using the init_domain_list() function so pointers to individual winbindd_domain structures cannot be made. Keep a copy of diff --git a/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c index 24df6279341..afcb463a631 100644 --- a/source/passdb/pdb_ldap.c +++ b/source/passdb/pdb_ldap.c @@ -1611,7 +1611,7 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, ber_printf (ber, "{"); ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, utf8_dn); ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, utf8_password); - ber_printf (ber, "N}"); + ber_printf (ber, "n}"); if ((rc = ber_flatten (ber, &bv))<0) { DEBUG(0,("ldapsam_modify_entry: ber_flatten returns a value <0\n")); diff --git a/source/rpc_parse/parse_samr.c b/source/rpc_parse/parse_samr.c index fc35ccbe2bb..4410348abee 100644 --- a/source/rpc_parse/parse_samr.c +++ b/source/rpc_parse/parse_samr.c @@ -6064,9 +6064,26 @@ static BOOL sam_io_user_info25(const char *desc, SAM_USER_INFO_25 * usr, prs_str if(!prs_uint32("fields_present ", ps, depth, &usr->fields_present)) return False; - if(!prs_uint32s(False, "unknown_5 ", ps, depth, usr->unknown_5, 5)) + if(!prs_uint16("logon_divs ", ps, depth, &usr->logon_divs)) /* logon divisions per week */ + return False; + if(!prs_align(ps)) + return False; + if(!prs_uint32("ptr_logon_hrs ", ps, depth, &usr->ptr_logon_hrs)) + return False; + + if(!prs_uint16("bad_password_count ", ps, depth, &usr->bad_password_count)) + return False; + if(!prs_uint16("logon_count ", ps, depth, &usr->logon_count)) return False; + if(!prs_uint8s(False, "padding1 ", ps, depth, usr->padding1, sizeof(usr->padding1))) + return False; + if(!prs_uint8("passmustchange ", ps, depth, &usr->passmustchange)) + return False; + if(!prs_uint8("padding2 ", ps, depth, &usr->padding2)) + return False; + + if(!prs_uint8s(False, "password ", ps, depth, usr->pass, sizeof(usr->pass))) return False; @@ -6102,13 +6119,11 @@ static BOOL sam_io_user_info25(const char *desc, SAM_USER_INFO_25 * usr, prs_str if(!smb_io_unistr2("uni_munged_dial ", &usr->uni_munged_dial, usr->hdr_munged_dial.buffer, ps, depth)) return False; -#if 0 /* JRA - unknown... */ /* ok, this is only guess-work (as usual) */ if (usr->ptr_logon_hrs) { if(!sam_io_logon_hrs("logon_hrs", &usr->logon_hrs, ps, depth)) return False; } -#endif return True; } diff --git a/source/rpc_server/srv_samr_nt.c b/source/rpc_server/srv_samr_nt.c index c924c75453d..3343f16f35d 100644 --- a/source/rpc_server/srv_samr_nt.c +++ b/source/rpc_server/srv_samr_nt.c @@ -3372,11 +3372,17 @@ static BOOL set_user_info_pw(uint8 *pass, struct samu *pwd) uint32 len; pstring plaintext_buf; uint32 acct_ctrl; + time_t last_set_time; + enum pdb_value_state last_set_state; DEBUG(5, ("Attempting administrator password change for user %s\n", pdb_get_username(pwd))); acct_ctrl = pdb_get_acct_ctrl(pwd); + /* we need to know if it's expired, because this is an admin change, not a + user change, so it's still expired when we're done */ + last_set_state = pdb_get_init_flags(pwd, PDB_PASSLASTSET); + last_set_time = pdb_get_pass_last_set_time(pwd); ZERO_STRUCT(plaintext_buf); @@ -3418,6 +3424,9 @@ static BOOL set_user_info_pw(uint8 *pass, struct samu *pwd) } ZERO_STRUCT(plaintext_buf); + + /* restore last set time as this is an admin change, not a user pw change */ + pdb_set_pass_last_set_time (pwd, last_set_time, last_set_state); DEBUG(5,("set_user_info_pw: pdb_update_pwd()\n")); diff --git a/source/rpc_server/srv_samr_util.c b/source/rpc_server/srv_samr_util.c index 8acc1785ef6..42ad462ee77 100644 --- a/source/rpc_server/srv_samr_util.c +++ b/source/rpc_server/srv_samr_util.c @@ -670,4 +670,47 @@ void copy_id25_to_sam_passwd(struct samu *to, SAM_USER_INFO_25 *from) pdb_set_acct_ctrl(to, from->acb_info, PDB_CHANGED); } } + + if (from->fields_present & ACCT_LOGON_HOURS) { + DEBUG(15,("INFO_25 LOGON_DIVS: %08X -> %08X\n",pdb_get_logon_divs(to),from->logon_divs)); + if (from->logon_divs != pdb_get_logon_divs(to)) { + pdb_set_logon_divs(to, from->logon_divs, PDB_CHANGED); + } + + DEBUG(15,("INFO_25 LOGON_HRS.LEN: %08X -> %08X\n",pdb_get_hours_len(to),from->logon_hrs.len)); + if (from->logon_hrs.len != pdb_get_hours_len(to)) { + pdb_set_hours_len(to, from->logon_hrs.len, PDB_CHANGED); + } + + DEBUG(15,("INFO_25 LOGON_HRS.HOURS: %s -> %s\n",pdb_get_hours(to),from->logon_hrs.hours)); + /* Fix me: only update if it changes --metze */ + pdb_set_hours(to, from->logon_hrs.hours, PDB_CHANGED); + } + + if (from->fields_present & ACCT_BAD_PWD_COUNT) { + DEBUG(10,("INFO_25 BAD_PASSWORD_COUNT: %08X -> %08X\n",pdb_get_bad_password_count(to),from->bad_password_count)); + if (from->bad_password_count != pdb_get_bad_password_count(to)) { + pdb_set_bad_password_count(to, from->bad_password_count, PDB_CHANGED); + } + } + + if (from->fields_present & ACCT_NUM_LOGONS) { + DEBUG(10,("INFO_25 LOGON_COUNT: %08X -> %08X\n",pdb_get_logon_count(to),from->logon_count)); + if (from->logon_count != pdb_get_logon_count(to)) { + pdb_set_logon_count(to, from->logon_count, PDB_CHANGED); + } + } + + /* If the must change flag is set, the last set time goes to zero. + the must change and can change fields also do, but they are + calculated from policy, not set from the wire */ + + if (from->fields_present & ACCT_EXPIRED_FLAG) { + DEBUG(10,("INFO_25 PASS_MUST_CHANGE_AT_NEXT_LOGON: %02X\n",from->passmustchange)); + if (from->passmustchange == PASS_MUST_CHANGE_AT_NEXT_LOGON) { + pdb_set_pass_last_set_time(to, 0, PDB_CHANGED); + } else { + pdb_set_pass_last_set_time(to, time(NULL),PDB_CHANGED); + } + } } diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c index 03a407ad557..4cf43f04e49 100644 --- a/source/rpc_server/srv_spoolss_nt.c +++ b/source/rpc_server/srv_spoolss_nt.c @@ -2263,6 +2263,7 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint *type = REG_DWORD; if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) ) return WERR_NOMEM; + SIVAL(*data, 0, 0x00); *needed = 0x4; return WERR_OK; } diff --git a/source/script/mkversion.sh b/source/script/mkversion.sh index 57840549213..aee7d0a1188 100755 --- a/source/script/mkversion.sh +++ b/source/script/mkversion.sh @@ -104,7 +104,7 @@ echo "$0: 'include/version.h' created for Samba(\"${SAMBA_VERSION_STRING}\")" if test -n "${SAMBA_VERSION_VENDOR_SUFFIX}";then echo -n "$0: with VENDOR_SUFFIX = \"" echo -n ${SAMBA_VERSION_VENDOR_SUFFIX} | sed 's/"//g' - if test -n ${SAMBA_VENDOR_PATCH}; then + if test -n "${SAMBA_VENDOR_PATCH}"; then echo -n "-${SAMBA_VENDOR_PATCH}" fi echo "\"" diff --git a/source/services/services_db.c b/source/services/services_db.c index 5b4f58d766d..c8ba273e30f 100644 --- a/source/services/services_db.c +++ b/source/services/services_db.c @@ -416,7 +416,7 @@ void svcctl_init_keys( void ) REG_KEY_ALL ); if ( !W_ERROR_IS_OK(wresult) ) { - DEBUG(0,("init_services_keys: key lookup failed! (%s)\n", + DEBUG(0,("svcctl_init_keys: key lookup failed! (%s)\n", dos_errstr(wresult))); return; } @@ -424,7 +424,7 @@ void svcctl_init_keys( void ) /* lookup the available subkeys */ if ( !(subkeys = TALLOC_ZERO_P( key, REGSUBKEY_CTR )) ) { - DEBUG(0,("init_services_keys: talloc() failed!\n")); + DEBUG(0,("svcctl_init_keys: talloc() failed!\n")); regkey_close_internal( key ); return; } diff --git a/source/smbd/close.c b/source/smbd/close.c index 6a496f16a6e..a094d8a4da0 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -153,6 +153,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, struct share_mode_lock *lck; SMB_STRUCT_STAT sbuf; NTSTATUS status = NT_STATUS_OK; + int ret; /* * Lock the share entries, and determine if we should delete @@ -245,8 +246,14 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, /* We can only delete the file if the name we have is still valid and hasn't been renamed. */ - - if(SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) != 0) { + + if (fsp->posix_open) { + ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf); + } else { + ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf); + } + + if (ret != 0) { DEBUG(5,("close_remove_share_mode: file %s. Delete on close " "was set and stat failed with error %s\n", fsp->fsp_name, strerror(errno) )); diff --git a/source/smbd/error.c b/source/smbd/error.c index 0860b7d1d91..fa344e372e5 100644 --- a/source/smbd/error.c +++ b/source/smbd/error.c @@ -132,3 +132,22 @@ int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, in error_packet_set(outbuf, eclass, ecode, ntstatus, line, file); return outsize; } + +/******************************************************************************* + Special error map processing needed for returning DOS errors on open calls. +*******************************************************************************/ + +int error_open(char *outbuf, NTSTATUS status, int line, const char *file) +{ + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) { + /* + * We hit an existing file, and if we're returning DOS + * error codes OBJECT_NAME_COLLISION would map to + * ERRDOS/183, we need to return ERRDOS/80, see bug + * 4852. + */ + return error_packet(outbuf, ERRDOS, ERRfilexists, + NT_STATUS_OBJECT_NAME_COLLISION, line, file); + } + return error_packet(outbuf,0,0,status,line,file); +} diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index 1227d12b08e..a5f8242d06e 100644 --- a/source/smbd/fileio.c +++ b/source/smbd/fileio.c @@ -509,15 +509,20 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", write_path = 3; - } else if ( (pos >= wcp->file_size) && + } else if ( (pos >= wcp->file_size) && (n == 1) && - (pos < wcp->offset + 2*wcp->alloc_size) && - (wcp->file_size == wcp->offset + wcp->data_size)) { + (wcp->file_size == wcp->offset + wcp->data_size) && + (pos < wcp->file_size + wcp->alloc_size)) { /* - +---------------+ - | Cached data | - +---------------+ + + End of file ---->| + + +---------------+---------------+ + | Cached data | Cache buffer | + +---------------+---------------+ + + |<------- allocated size ---------------->| +--------+ | 1 Byte | @@ -525,13 +530,18 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", MS-Office seems to do this a lot to determine if there's enough space on the filesystem to write a new file. - */ - SMB_BIG_UINT new_start = wcp->offset + wcp->data_size; + Change to : + + End of file ---->| + +-----------------------+--------+ + | Zeroed Cached data | 1 Byte | + +-----------------------+--------+ + */ flush_write_cache(fsp, WRITE_FLUSH); - wcp->offset = new_start; - wcp->data_size = pos - new_start + 1; + wcp->offset = wcp->file_size; + wcp->data_size = pos - wcp->file_size + 1; memset(wcp->data, '\0', wcp->data_size); memcpy(wcp->data + wcp->data_size-1, data, 1); diff --git a/source/smbd/filename.c b/source/smbd/filename.c index eb86a0efd16..570297bf69f 100644 --- a/source/smbd/filename.c +++ b/source/smbd/filename.c @@ -392,20 +392,25 @@ NTSTATUS unix_convert(connection_struct *conn, * these two errors. */ - /* ENOENT and ENOTDIR both map to NT_STATUS_OBJECT_PATH_NOT_FOUND - in the filename walk. */ + /* ENOENT, ENOTDIR and ELOOP all map to + * NT_STATUS_OBJECT_PATH_NOT_FOUND + * in the filename walk. */ - if (errno == ENOENT || errno == ENOTDIR) { + if (errno == ENOENT || + errno == ENOTDIR || + errno == ELOOP) { return NT_STATUS_OBJECT_PATH_NOT_FOUND; } return map_nt_error_from_unix(errno); } - + /* ENOENT is the only valid error here. */ if (errno != ENOENT) { - /* ENOENT and ENOTDIR both map to NT_STATUS_OBJECT_PATH_NOT_FOUND - in the filename walk. */ - if (errno == ENOTDIR) { + /* ENOTDIR and ELOOP both map to + * NT_STATUS_OBJECT_PATH_NOT_FOUND + * in the filename walk. */ + if (errno == ENOTDIR || + errno == ELOOP) { return NT_STATUS_OBJECT_PATH_NOT_FOUND; } return map_nt_error_from_unix(errno); diff --git a/source/smbd/msdfs.c b/source/smbd/msdfs.c index 7b660899d55..74acf3d37e3 100644 --- a/source/smbd/msdfs.c +++ b/source/smbd/msdfs.c @@ -388,7 +388,8 @@ static NTSTATUS dfs_path_lookup(connection_struct *conn, pstrcpy(localpath, pdp->reqpath); status = unix_convert(conn, localpath, search_flag, NULL, &sbuf); - if (!NT_STATUS_IS_OK(status)) { + if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, + NT_STATUS_OBJECT_PATH_NOT_FOUND)) { return status; } @@ -420,6 +421,14 @@ static NTSTATUS dfs_path_lookup(connection_struct *conn, } /* + * localpath comes out of unix_convert, so it has + * no trailing backslash. Make sure that canon_dfspath hasn't either. + * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>. + */ + + trim_char(canon_dfspath,0,'/'); + + /* * Redirect if any component in the path is a link. * We do this by walking backwards through the * local path, chopping off the last component diff --git a/source/smbd/notify.c b/source/smbd/notify.c index 7b831c2f560..df9d8ad1378 100644 --- a/source/smbd/notify.c +++ b/source/smbd/notify.c @@ -27,7 +27,7 @@ struct notify_change_request { struct files_struct *fsp; /* backpointer for cancel by mid */ char request_buf[smb_size]; uint32 filter; - uint32 current_bufsize; + uint32 max_param; struct notify_mid_map *mid_map; void *backend_data; }; @@ -47,19 +47,40 @@ struct notify_mid_map { uint16 mid; }; +static BOOL notify_change_record_identical(struct notify_change *c1, + struct notify_change *c2) +{ + /* Note this is deliberately case sensitive. */ + if (c1->action == c2->action && + strcmp(c1->name, c2->name) == 0) { + return True; + } + return False; +} + static BOOL notify_marshall_changes(int num_changes, - struct notify_change *changes, - prs_struct *ps) + uint32 max_offset, + struct notify_change *changes, + prs_struct *ps) { int i; UNISTR uni_name; for (i=0; i<num_changes; i++) { - struct notify_change *c = &changes[i]; + struct notify_change *c; size_t namelen; uint32 u32_tmp; /* Temp arg to prs_uint32 to avoid * signed/unsigned issues */ + /* Coalesce any identical records. */ + while (i+1 < num_changes && + notify_change_record_identical(&changes[i], + &changes[i+1])) { + i++; + } + + c = &changes[i]; + namelen = convert_string_allocate( NULL, CH_UNIX, CH_UTF16LE, c->name, strlen(c->name)+1, &uni_name.buffer, True); @@ -90,6 +111,11 @@ static BOOL notify_marshall_changes(int num_changes, prs_set_offset(ps, prs_offset(ps)-2); SAFE_FREE(uni_name.buffer); + + if (prs_offset(ps) > max_offset) { + /* Too much data for client. */ + return False; + } } return True; @@ -125,7 +151,7 @@ static void change_notify_reply_packet(const char *request_buf, "failed."); } -void change_notify_reply(const char *request_buf, +void change_notify_reply(const char *request_buf, uint32 max_param, struct notify_change_buf *notify_buf) { char *outbuf = NULL; @@ -134,13 +160,19 @@ void change_notify_reply(const char *request_buf, if (notify_buf->num_changes == -1) { change_notify_reply_packet(request_buf, NT_STATUS_OK); + notify_buf->num_changes = 0; return; } - if (!prs_init(&ps, 0, NULL, False) - || !notify_marshall_changes(notify_buf->num_changes, + prs_init(&ps, 0, NULL, MARSHALL); + + if (!notify_marshall_changes(notify_buf->num_changes, max_param, notify_buf->changes, &ps)) { - change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY); + /* + * We exceed what the client is willing to accept. Send + * nothing. + */ + change_notify_reply_packet(request_buf, NT_STATUS_OK); goto done; } @@ -206,7 +238,7 @@ NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter, return status; } -NTSTATUS change_notify_add_request(const char *inbuf, +NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param, uint32 filter, BOOL recursive, struct files_struct *fsp) { @@ -223,11 +255,11 @@ NTSTATUS change_notify_add_request(const char *inbuf, map->req = request; memcpy(request->request_buf, inbuf, sizeof(request->request_buf)); - request->current_bufsize = 0; + request->max_param = max_param; request->filter = filter; request->fsp = fsp; request->backend_data = NULL; - + DLIST_ADD_END(fsp->notify->requests, request, struct notify_change_request *); @@ -399,6 +431,7 @@ static void notify_fsp(files_struct *fsp, uint32 action, const char *name) */ change_notify_reply(fsp->notify->requests->request_buf, + fsp->notify->requests->max_param, fsp->notify); change_notify_remove_request(fsp->notify->requests); diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index 6da1bba8b9b..5a9e0a9367b 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -716,18 +716,6 @@ int reply_ntcreate_and_X(connection_struct *conn, create_options, new_file_attributes, &info, &fsp); - - restore_case_semantics(conn, file_attributes); - - if(!NT_STATUS_IS_OK(status)) { - if (!use_nt_status() && NT_STATUS_EQUAL( - status, NT_STATUS_OBJECT_NAME_COLLISION)) { - status = NT_STATUS_DOS(ERRDOS, ERRfilexists); - } - END_PROFILE(SMBntcreateX); - return ERROR_NT(status); - } - } else { /* @@ -756,7 +744,7 @@ int reply_ntcreate_and_X(connection_struct *conn, oplock_request, &info, &fsp); - if (!NT_STATUS_IS_OK(status)) { + if (!NT_STATUS_IS_OK(status)) { /* We cheat here. There are two cases we * care about. One is a directory rename, * where the NT client will attempt to @@ -788,7 +776,7 @@ int reply_ntcreate_and_X(connection_struct *conn, END_PROFILE(SMBntcreateX); return ERROR_FORCE_NT(NT_STATUS_FILE_IS_A_DIRECTORY); } - + oplock_request = 0; status = open_directory(conn, fname, &sbuf, access_mask, @@ -798,29 +786,23 @@ int reply_ntcreate_and_X(connection_struct *conn, new_file_attributes, &info, &fsp); - if(!NT_STATUS_IS_OK(status)) { - restore_case_semantics(conn, file_attributes); - if (!use_nt_status() && NT_STATUS_EQUAL( - status, NT_STATUS_OBJECT_NAME_COLLISION)) { - status = NT_STATUS_DOS(ERRDOS, ERRfilexists); - } - END_PROFILE(SMBntcreateX); - return ERROR_NT(status); - } - } else { - restore_case_semantics(conn, file_attributes); - END_PROFILE(SMBntcreateX); - if (open_was_deferred(SVAL(inbuf,smb_mid))) { - /* We have re-scheduled this call. */ - return -1; - } - return ERROR_NT(status); } - } + } } - + restore_case_semantics(conn, file_attributes); + if(!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBntcreateX); + + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + return -1; + } + + return ERROR_OPEN(status); + } + file_len = sbuf.st_size; fattr = dos_mode(conn,fname,&sbuf); if(fattr == 0) { @@ -1416,11 +1398,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o create_options, new_file_attributes, &info, &fsp); - if(!NT_STATUS_IS_OK(status)) { - restore_case_semantics(conn, file_attributes); - return ERROR_NT(status); - } - } else { /* @@ -1436,7 +1413,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o oplock_request, &info, &fsp); - if (!NT_STATUS_IS_OK(status)) { + if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { @@ -1448,7 +1425,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o restore_case_semantics(conn, file_attributes); return ERROR_FORCE_NT(NT_STATUS_FILE_IS_A_DIRECTORY); } - + oplock_request = 0; status = open_directory(conn, fname, &sbuf, access_mask, @@ -1457,26 +1434,26 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o create_options, new_file_attributes, &info, &fsp); - if(!NT_STATUS_IS_OK(status)) { - restore_case_semantics(conn, file_attributes); - return ERROR_NT(status); - } - } else { - restore_case_semantics(conn, file_attributes); - if (open_was_deferred(SVAL(inbuf,smb_mid))) { - /* We have re-scheduled this call. */ - return -1; - } - return ERROR_NT(status); } - } + } + } + + restore_case_semantics(conn, file_attributes); + if(!NT_STATUS_IS_OK(status)) { + + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + return -1; + } + + return ERROR_OPEN(status); } /* * According to the MS documentation, the only time the security * descriptor is applied to the opened file is iff we *created* the * file; an existing file stays the same. - * + * * Also, it seems (from observation) that you can open the file with * any access mask but you can still write the sd. We need to override * the granted access before we call set_sd @@ -1979,7 +1956,7 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, * here. */ - change_notify_reply(inbuf, fsp->notify); + change_notify_reply(inbuf, max_param_count, fsp->notify); /* * change_notify_reply() above has independently sent its @@ -1992,7 +1969,8 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, * No changes pending, queue the request */ - status = change_notify_add_request(inbuf, filter, recursive, fsp); + status = change_notify_add_request(inbuf, max_param_count, filter, + recursive, fsp); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index 7eda998547e..def918b29fb 100644 --- a/source/smbd/posix_acls.c +++ b/source/smbd/posix_acls.c @@ -47,7 +47,7 @@ typedef struct canon_ace { DOM_SID trustee; enum ace_owner owner_type; enum ace_attribute attr; - posix_id unix_ug; + posix_id unix_ug; BOOL inherited; } canon_ace; @@ -828,20 +828,23 @@ static BOOL nt4_compatible_acls(void) not get. Deny entries are implicit on get with ace->perms = 0. ****************************************************************************/ -static SEC_ACCESS map_canon_ace_perms(int snum, int *pacl_type, DOM_SID *powner_sid, canon_ace *ace, BOOL directory_ace) +static SEC_ACCESS map_canon_ace_perms(int snum, + int *pacl_type, + mode_t perms, + BOOL directory_ace) { SEC_ACCESS sa; uint32 nt_mask = 0; *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED; - if (lp_acl_map_full_control(snum) && ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) { + if (lp_acl_map_full_control(snum) && ((perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) { if (directory_ace) { nt_mask = UNIX_DIRECTORY_ACCESS_RWX; } else { nt_mask = UNIX_ACCESS_RWX; } - } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) { + } else if ((perms & ALL_ACE_PERMS) == (mode_t)0) { /* * Windows NT refuses to display ACEs with no permissions in them (but * they are perfectly legal with Windows 2000). If the ACE has empty @@ -857,18 +860,18 @@ static SEC_ACCESS map_canon_ace_perms(int snum, int *pacl_type, DOM_SID *powner_ nt_mask = 0; } else { if (directory_ace) { - nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 ); - nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 ); - nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 ); + nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 ); + nt_mask |= ((perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 ); + nt_mask |= ((perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 ); } else { - nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 ); - nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 ); - nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 ); + nt_mask |= ((perms & S_IRUSR) ? UNIX_ACCESS_R : 0 ); + nt_mask |= ((perms & S_IWUSR) ? UNIX_ACCESS_W : 0 ); + nt_mask |= ((perms & S_IXUSR) ? UNIX_ACCESS_X : 0 ); } } DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n", - (unsigned int)ace->perms, (unsigned int)nt_mask )); + (unsigned int)perms, (unsigned int)nt_mask )); init_sec_access(&sa,nt_mask); return sa; @@ -2889,26 +2892,37 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) } memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) ); - + /* * Create the NT ACE list from the canonical ace lists. */ - + ace = file_ace; for (i = 0; i < num_acls; i++, ace = ace->next) { SEC_ACCESS acc; - acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, &owner_sid, ace, fsp->is_directory); - init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0); + acc = map_canon_ace_perms(SNUM(conn), + &nt_acl_type, + ace->perms, + fsp->is_directory); + init_sec_ace(&nt_ace_list[num_aces++], + &ace->trustee, + nt_acl_type, + acc, + ace->inherited ? + SEC_ACE_FLAG_INHERITED_ACE : 0); } - /* The User must have access to a profile share - even if we can't map the SID. */ + /* The User must have access to a profile share - even + * if we can't map the SID. */ if (lp_profile_acls(SNUM(conn))) { SEC_ACCESS acc; init_sec_access(&acc,FILE_GENERIC_ALL); - init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, + init_sec_ace(&nt_ace_list[num_aces++], + &global_sid_Builtin_Users, + SEC_ACE_TYPE_ACCESS_ALLOWED, acc, 0); } @@ -2916,18 +2930,27 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) for (i = 0; i < num_def_acls; i++, ace = ace->next) { SEC_ACCESS acc; - - acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, &owner_sid, ace, fsp->is_directory); - init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, - SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| - SEC_ACE_FLAG_INHERIT_ONLY| - (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0)); + + acc = map_canon_ace_perms(SNUM(conn), + &nt_acl_type, + ace->perms, + fsp->is_directory); + init_sec_ace(&nt_ace_list[num_aces++], + &ace->trustee, + nt_acl_type, + acc, + SEC_ACE_FLAG_OBJECT_INHERIT| + SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY| + (ace->inherited ? + SEC_ACE_FLAG_INHERITED_ACE : 0)); } - /* The User must have access to a profile share - even if we can't map the SID. */ + /* The User must have access to a profile share - even + * if we can't map the SID. */ if (lp_profile_acls(SNUM(conn))) { SEC_ACCESS acc; - + init_sec_access(&acc,FILE_GENERIC_ALL); init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| @@ -3076,6 +3099,198 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) return ret; } +static NTSTATUS append_ugw_ace(files_struct *fsp, + SMB_STRUCT_STAT *psbuf, + mode_t unx_mode, + int ugw, + SEC_ACE *se) +{ + mode_t perms; + SEC_ACCESS acc; + int acl_type; + DOM_SID trustee; + + switch (ugw) { + case S_IRUSR: + perms = unix_perms_to_acl_perms(unx_mode, + S_IRUSR, + S_IWUSR, + S_IXUSR); + uid_to_sid(&trustee, psbuf->st_uid ); + break; + case S_IRGRP: + perms = unix_perms_to_acl_perms(unx_mode, + S_IRGRP, + S_IWGRP, + S_IXGRP); + gid_to_sid(&trustee, psbuf->st_gid ); + break; + case S_IROTH: + perms = unix_perms_to_acl_perms(unx_mode, + S_IROTH, + S_IWOTH, + S_IXOTH); + sid_copy(&trustee, &global_sid_World); + break; + default: + return NT_STATUS_INVALID_PARAMETER; + } + acc = map_canon_ace_perms(SNUM(fsp->conn), + &acl_type, + perms, + fsp->is_directory); + + init_sec_ace(se, + &trustee, + acl_type, + acc, + 0); + return NT_STATUS_OK; +} + +/**************************************************************************** + If this is an +****************************************************************************/ + +static NTSTATUS append_parent_acl(files_struct *fsp, + SMB_STRUCT_STAT *psbuf, + SEC_DESC *psd, + SEC_DESC **pp_new_sd) +{ + SEC_DESC *parent_sd = NULL; + files_struct *parent_fsp = NULL; + TALLOC_CTX *mem_ctx = talloc_parent(psd); + char *parent_name = NULL; + SEC_ACE *new_ace = NULL; + unsigned int num_aces = psd->dacl->num_aces; + SMB_STRUCT_STAT sbuf; + NTSTATUS status; + int info; + size_t sd_size; + unsigned int i, j; + mode_t unx_mode; + + ZERO_STRUCT(sbuf); + + if (mem_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (!parent_dirname_talloc(mem_ctx, + fsp->fsp_name, + &parent_name, + NULL)) { + return NT_STATUS_NO_MEMORY; + } + + /* Create a default mode for u/g/w. */ + unx_mode = unix_mode(fsp->conn, + aARCH | (fsp->is_directory ? aDIR : 0), + fsp->fsp_name, + parent_name); + + status = open_directory(fsp->conn, + parent_name, + &sbuf, + FILE_READ_ATTRIBUTES, /* Just a stat open */ + FILE_SHARE_NONE, /* Ignored for stat opens */ + FILE_OPEN, + 0, + 0, + &info, + &parent_fsp); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + sd_size = SMB_VFS_GET_NT_ACL(parent_fsp, parent_fsp->fsp_name, + DACL_SECURITY_INFORMATION, &parent_sd ); + + close_file(parent_fsp, NORMAL_CLOSE); + + if (!sd_size) { + return NT_STATUS_ACCESS_DENIED; + } + + /* + * Make room for potentially all the ACLs from + * the parent, plus the user/group/other triple. + */ + + num_aces += parent_sd->dacl->num_aces + 3; + + if((new_ace = TALLOC_ZERO_ARRAY(mem_ctx, SEC_ACE, + num_aces)) == NULL) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10,("append_parent_acl: parent ACL has %u entries. New " + "ACL has %u entries\n", + parent_sd->dacl->num_aces, num_aces )); + + /* Start by copying in all the given ACE entries. */ + for (i = 0; i < psd->dacl->num_aces; i++) { + sec_ace_copy(&new_ace[i], &psd->dacl->aces[i]); + } + + /* + * Note that we're ignoring "inherit permissions" here + * as that really only applies to newly created files. JRA. + */ + + /* + * Append u/g/w. + */ + + status = append_ugw_ace(fsp, psbuf, unx_mode, S_IRUSR, &new_ace[i++]); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = append_ugw_ace(fsp, psbuf, unx_mode, S_IRGRP, &new_ace[i++]); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = append_ugw_ace(fsp, psbuf, unx_mode, S_IROTH, &new_ace[i++]); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Finally append any inherited ACEs. */ + for (j = 0; j < parent_sd->dacl->num_aces; j++) { + SEC_ACE *se = &parent_sd->dacl->aces[j]; + uint32 i_flags = se->flags & (SEC_ACE_FLAG_OBJECT_INHERIT| + SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY); + + if (fsp->is_directory) { + if (i_flags == SEC_ACE_FLAG_OBJECT_INHERIT) { + /* Should only apply to a file - ignore. */ + continue; + } + } else { + if ((i_flags & (SEC_ACE_FLAG_OBJECT_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY)) != + SEC_ACE_FLAG_OBJECT_INHERIT) { + /* Should not apply to a file - ignore. */ + continue; + } + } + sec_ace_copy(&new_ace[i], se); + if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) { + new_ace[i].flags &= ~(SEC_ACE_FLAG_VALID_INHERIT); + } + new_ace[i].flags |= SEC_ACE_FLAG_INHERITED_ACE; + i++; + } + + parent_sd->dacl->aces = new_ace; + parent_sd->dacl->num_aces = i; + + *pp_new_sd = parent_sd; + return status; +} + /**************************************************************************** Reply to set a security descriptor on an fsp. security_info_sent is the description of the following NT ACL. @@ -3087,7 +3302,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) connection_struct *conn = fsp->conn; uid_t user = (uid_t)-1; gid_t grp = (gid_t)-1; - SMB_STRUCT_STAT sbuf; + SMB_STRUCT_STAT sbuf; DOM_SID file_owner_sid; DOM_SID file_grp_sid; canon_ace *file_ace_list = NULL; @@ -3167,12 +3382,12 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) } else { int ret; - + if(fsp->fh->fd == -1) ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf); else ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf); - + if(ret != 0) return False; } @@ -3188,6 +3403,18 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid); + if ((security_info_sent & DACL_SECURITY_INFORMATION) && + psd->dacl != NULL && + (psd->type & (SE_DESC_DACL_AUTO_INHERITED| + SE_DESC_DACL_AUTO_INHERIT_REQ))== + (SE_DESC_DACL_AUTO_INHERITED| + SE_DESC_DACL_AUTO_INHERIT_REQ) ) { + NTSTATUS status = append_parent_acl(fsp, &sbuf, psd, &psd); + if (!NT_STATUS_IS_OK(status)) { + return False; + } + } + acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid, &file_ace_list, &dir_ace_list, security_info_sent, psd); diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 99c3b478e47..55f62a26f7c 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1321,7 +1321,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, /* We have re-scheduled this call. */ return -1; } - return ERROR_NT(status); + return ERROR_OPEN(status); } size = sbuf.st_size; @@ -1455,7 +1455,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt /* We have re-scheduled this call. */ return -1; } - return ERROR_NT(status); + return ERROR_OPEN(status); } /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size, @@ -1644,7 +1644,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, /* We have re-scheduled this call. */ return -1; } - return ERROR_NT(status); + return ERROR_OPEN(status); } ts[0] = get_atimespec(&sbuf); /* atime. */ @@ -1746,7 +1746,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, /* We have re-scheduled this call. */ return -1; } - return ERROR_NT(status); + return ERROR_OPEN(status); } outsize = set_message(outbuf,1,0,True); @@ -2126,6 +2126,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size status = unlink_internals(conn, dirtype, name, path_contains_wcard, True); if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBunlink); if (open_was_deferred(SVAL(inbuf,smb_mid))) { /* We have re-scheduled this call. */ return -1; diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index e5a699047fd..b2ce5b8c26d 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -866,13 +866,13 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i open_attr, oplock_request, &smb_action, &fsp); - + if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(SVAL(inbuf,smb_mid))) { /* We have re-scheduled this call. */ return -1; } - return ERROR_NT(status); + return ERROR_OPEN(status); } size = get_file_size(sbuf); @@ -1999,11 +1999,11 @@ static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbu complain (it thinks we're asking for the directory above the shared path or an invalid name). Catch this as the resume name is only compared, never used in a file access. JRA. */ - if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) { - pstrcpy(resume_name, ".."); - } else if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_OBJECT_NAME_INVALID)) { - pstrcpy(resume_name, "."); - } else { + srvstr_pull(inbuf, resume_name, params+12, + sizeof(resume_name), total_params - 12, + STR_TERMINATE); + + if (!(ISDOT(resume_name) || ISDOTDOT(resume_name))) { return ERROR_NT(ntstatus); } } @@ -4845,17 +4845,24 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, allocation_size = smb_roundup(conn, allocation_size); } - if(allocation_size == get_file_size(*psbuf)) { - return NT_STATUS_OK; - } - DEBUG(10,("smb_set_file_allocation_info: file %s : setting new allocation size to %.0f\n", fname, (double)allocation_size )); - + if (fsp && fsp->fh->fd != -1) { /* Open file handle. */ - if (vfs_allocate_file_space(fsp, allocation_size) == -1) { - return map_nt_error_from_unix(errno); + /* Only change if needed. */ + if (allocation_size != get_file_size(*psbuf)) { + if (vfs_allocate_file_space(fsp, allocation_size) == -1) { + return map_nt_error_from_unix(errno); + } + } + /* But always update the time. */ + if (null_timespec(fsp->pending_modtime)) { + /* + * This is equivalent to a write. Ensure it's seen immediately + * if there are no pending writes. + */ + set_filetime(fsp->conn, fsp->fsp_name, timespec_current()); } return NT_STATUS_OK; } @@ -4870,17 +4877,27 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, FILE_ATTRIBUTE_NORMAL, FORCE_OPLOCK_BREAK_TO_NONE, NULL, &new_fsp); - + if (!NT_STATUS_IS_OK(status)) { /* NB. We check for open_was_deferred in the caller. */ return status; } - if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) { - status = map_nt_error_from_unix(errno); - close_file(new_fsp,NORMAL_CLOSE); - return status; + + /* Only change if needed. */ + if (allocation_size != get_file_size(*psbuf)) { + if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) { + status = map_nt_error_from_unix(errno); + close_file(new_fsp,NORMAL_CLOSE); + return status; + } } + /* Changing the allocation size should set the last mod time. */ + /* Don't need to call set_filetime as this will be flushed on + * close. */ + + fsp_set_pending_modtime(new_fsp, timespec_current()); + close_file(new_fsp,NORMAL_CLOSE); return NT_STATUS_OK; } @@ -5525,7 +5542,10 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, NTSTATUS status = NT_STATUS_OK; files_struct *fsp = NULL; uint16 flags = 0; + char del = 1; int info = 0; + int i; + struct share_mode_lock *lck = NULL; if (total_data < 2) { return NT_STATUS_INVALID_PARAMETER; @@ -5553,12 +5573,11 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, DELETE_ACCESS, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, - FILE_DELETE_ON_CLOSE, + 0, FILE_FLAG_POSIX_SEMANTICS|0777, - &info, + &info, &fsp); } else { - char del = 1; status = open_file_ntcreate(conn, fname, @@ -5571,26 +5590,59 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, 0, /* No oplock, but break existing ones. */ &info, &fsp); - /* - * For file opens we must set the delete on close - * after the open. - */ + } - if (!NT_STATUS_IS_OK(status)) { - return status; - } + if (!NT_STATUS_IS_OK(status)) { + return status; + } - status = smb_set_file_disposition_info(conn, - &del, - 1, - fsp, - fname, - psbuf); + /* + * Don't lie to client. If we can't really delete due to + * non-POSIX opens return SHARING_VIOLATION. + */ + + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); + if (lck == NULL) { + DEBUG(0, ("smb_posix_unlink: Could not get share mode " + "lock for file %s\n", fsp->fsp_name)); + close_file(fsp, NORMAL_CLOSE); + return NT_STATUS_INVALID_PARAMETER; + } + + /* + * See if others still have the file open. If this is the case, then + * don't delete. If all opens are POSIX delete we can set the delete + * on close disposition. + */ + for (i=0; i<lck->num_share_modes; i++) { + struct share_mode_entry *e = &lck->share_modes[i]; + if (is_valid_share_mode_entry(e)) { + if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) { + continue; + } + /* Fail with sharing violation. */ + close_file(fsp, NORMAL_CLOSE); + TALLOC_FREE(lck); + return NT_STATUS_SHARING_VIOLATION; + } } + /* + * Set the delete on close. + */ + status = smb_set_file_disposition_info(conn, + &del, + 1, + fsp, + fname, + psbuf); + if (!NT_STATUS_IS_OK(status)) { + close_file(fsp, NORMAL_CLOSE); + TALLOC_FREE(lck); return status; } + TALLOC_FREE(lck); return close_file(fsp, NORMAL_CLOSE); } @@ -5986,6 +6038,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); } + if (info_level == SMB_POSIX_PATH_OPEN) { + return ERROR_OPEN(status); + } return ERROR_NT(status); } diff --git a/source/tdb/common/io.c b/source/tdb/common/io.c index 9a8e270dcc6..cccc9ecc1a6 100644 --- a/source/tdb/common/io.c +++ b/source/tdb/common/io.c @@ -221,7 +221,16 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad if (ftruncate(tdb->fd, size+addition) == -1) { char b = 0; - if (pwrite(tdb->fd, &b, 1, (size+addition) - 1) != 1) { + ssize_t written = pwrite(tdb->fd, &b, 1, (size+addition) - 1); + if (written == 0) { + /* try once more, potentially revealing errno */ + written = pwrite(tdb->fd, &b, 1, (size+addition) - 1); + } + if (written == 0) { + /* again - give up, guessing errno */ + errno = ENOSPC; + } + if (written != 1) { TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n", size+addition, strerror(errno))); return -1; @@ -233,15 +242,28 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad disk. This must be done with write, not via mmap */ memset(buf, TDB_PAD_BYTE, sizeof(buf)); while (addition) { - int n = addition>sizeof(buf)?sizeof(buf):addition; - int ret = pwrite(tdb->fd, buf, n, size); - if (ret != n) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of %d failed (%s)\n", - n, strerror(errno))); + size_t n = addition>sizeof(buf)?sizeof(buf):addition; + ssize_t written = pwrite(tdb->fd, buf, n, size); + if (written == 0) { + /* prevent infinite loops: try _once_ more */ + written = pwrite(tdb->fd, buf, n, size); + } + if (written == 0) { + /* give up, trying to provide a useful errno */ + TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write " + "returned 0 twice: giving up!\n")); + errno = ENOSPC; + return -1; + } else if (written == -1) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of " + "%d bytes failed (%s)\n", n, strerror(errno))); return -1; + } else if (written != n) { + TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote " + "only %d of %d bytes - retrying\n", written,n)); } - addition -= n; - size += n; + addition -= written; + size += written; } return 0; } diff --git a/source/tdb/common/open.c b/source/tdb/common/open.c index c7fd3f66564..402352d3af2 100644 --- a/source/tdb/common/open.c +++ b/source/tdb/common/open.c @@ -50,7 +50,9 @@ static unsigned int default_tdb_hash(TDB_DATA *key) static int tdb_new_database(struct tdb_context *tdb, int hash_size) { struct tdb_header *newdb; - int size, ret = -1; + size_t size; + int ret = -1; + ssize_t written; /* We make it up in memory, then write it out if not internal */ size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t); @@ -79,10 +81,22 @@ static int tdb_new_database(struct tdb_context *tdb, int hash_size) memcpy(&tdb->header, newdb, sizeof(tdb->header)); /* Don't endian-convert the magic food! */ memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1); - if (write(tdb->fd, newdb, size) != size) { - ret = -1; - } else { + /* we still have "ret == -1" here */ + written = write(tdb->fd, newdb, size); + if (written == size) { ret = 0; + } else if (written != -1) { + /* call write once again, this usually should return -1 and + * set errno appropriately */ + size -= written; + written = write(tdb->fd, newdb+written, size); + if (written == size) { + ret = 0; + } else if (written >= 0) { + /* a second incomplete write - we give up. + * guessing the errno... */ + errno = ENOSPC; + } } fail: @@ -217,13 +231,16 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, } } + errno = 0; if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header) || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0 || (tdb->header.version != TDB_VERSION && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION))))) { /* its not a valid database - possibly initialise it */ if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) { - errno = EIO; /* ie bad format or something */ + if (errno == 0) { + errno = EIO; /* ie bad format or something */ + } goto fail; } rev = (tdb->flags & TDB_CONVERT); diff --git a/source/tdb/common/tdb.c b/source/tdb/common/tdb.c index bf43701d2ed..3e8358b00d2 100644 --- a/source/tdb/common/tdb.c +++ b/source/tdb/common/tdb.c @@ -566,8 +566,12 @@ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf) if (dbuf.dptr == NULL) { dbuf.dptr = (char *)malloc(new_dbuf.dsize); } else { - dbuf.dptr = (char *)realloc(dbuf.dptr, + char *new_dptr = (char *)realloc(dbuf.dptr, dbuf.dsize + new_dbuf.dsize); + if (new_dptr == NULL) { + free(dbuf.dptr); + } + dbuf.dptr = new_dptr; } if (dbuf.dptr == NULL) { diff --git a/source/tdb/common/tdbback.c b/source/tdb/common/tdbback.c index 28de85c29f8..1339bd22172 100644 --- a/source/tdb/common/tdbback.c +++ b/source/tdb/common/tdbback.c @@ -77,7 +77,7 @@ static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state; if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) { - fprintf(stderr,"Failed to insert into %s\n", tdb_name(tdb)); + fprintf(stderr,"Failed to insert into %s\n", tdb_name(tdb_new)); failed = 1; return 1; } diff --git a/source/torture/locktest.c b/source/torture/locktest.c index d248a9459db..ff14b803a73 100644 --- a/source/torture/locktest.c +++ b/source/torture/locktest.c @@ -165,6 +165,7 @@ static struct cli_state *connect_one(char *share, int snum) struct in_addr ip; fstring myname; static int count; + NTSTATUS status; fstrcpy(server,share+2); share = strchr_m(server,'\\'); @@ -185,11 +186,17 @@ static struct cli_state *connect_one(char *share, int snum) zero_ip(&ip); /* have to open a new connection */ - if (!(c=cli_initialise()) || !cli_connect(c, server_n, &ip)) { + if (!(c=cli_initialise())) { DEBUG(0,("Connection to %s failed\n", server_n)); return NULL; } + status = cli_connect(c, server_n, &ip); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Connection to %s failed. Error %s\n", server_n, nt_errstr(status) )); + return NULL; + } + c->use_kerberos = use_kerberos; if (!cli_session_request(c, &calling, &called)) { diff --git a/source/torture/masktest.c b/source/torture/masktest.c index 0d6c0b16f28..e98cf81f333 100644 --- a/source/torture/masktest.c +++ b/source/torture/masktest.c @@ -170,6 +170,7 @@ static struct cli_state *connect_one(char *share) char *server_n; char *server; struct in_addr ip; + NTSTATUS status; server = share+2; share = strchr_m(server,'\\'); @@ -188,11 +189,17 @@ static struct cli_state *connect_one(char *share) zero_ip(&ip); /* have to open a new connection */ - if (!(c=cli_initialise()) || !cli_connect(c, server_n, &ip)) { + if (!(c=cli_initialise())) { DEBUG(0,("Connection to %s failed\n", server_n)); return NULL; } + status = cli_connect(c, server_n, &ip); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Connection to %s failed. Error %s\n", server_n, nt_errstr(status) )); + return NULL; + } + c->protocol = max_protocol; if (!cli_session_request(c, &calling, &called)) { diff --git a/source/torture/torture.c b/source/torture/torture.c index 925cac3f32c..8ca2eb58981 100644 --- a/source/torture/torture.c +++ b/source/torture/torture.c @@ -102,6 +102,7 @@ static struct cli_state *open_nbt_connection(void) struct nmb_name called, calling; struct in_addr ip; struct cli_state *c; + NTSTATUS status; make_nmb_name(&calling, myname, 0x0); make_nmb_name(&called , host, 0x20); @@ -115,8 +116,9 @@ static struct cli_state *open_nbt_connection(void) c->port = port_to_use; - if (!cli_connect(c, host, &ip)) { - printf("Failed to connect with %s\n", host); + status = cli_connect(c, host, &ip); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to connect with %s. Error %s\n", host, nt_errstr(status) ); return NULL; } @@ -131,8 +133,9 @@ static struct cli_state *open_nbt_connection(void) * Well, that failed, try *SMBSERVER ... * However, we must reconnect as well ... */ - if (!cli_connect(c, host, &ip)) { - printf("Failed to connect with %s\n", host); + status = cli_connect(c, host, &ip); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to connect with %s. Error %s\n", host, nt_errstr(status) ); return NULL; } diff --git a/source/utils/net.c b/source/utils/net.c index 7b97476a25e..a030531947a 100644 --- a/source/utils/net.c +++ b/source/utils/net.c @@ -999,6 +999,10 @@ static struct functable net_func[] = { opt_user_name = getenv("LOGNAME"); } + if (!opt_user_name) { + opt_user_name = ""; + } + if (!opt_workgroup) { opt_workgroup = smb_xstrdup(lp_workgroup()); } diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c index 52af6e68d77..75b631c351f 100644 --- a/source/utils/net_ads.c +++ b/source/utils/net_ads.c @@ -1720,7 +1720,7 @@ static int net_ads_dns_register(int argc, const char **argv) #endif if (argc > 0) { - d_fprintf(stderr, "net ads dns register <name> <ip>\n"); + d_fprintf(stderr, "net ads dns register\n"); return -1; } diff --git a/source/utils/net_rpc.c b/source/utils/net_rpc.c index c300a7171ce..fee994b7519 100644 --- a/source/utils/net_rpc.c +++ b/source/utils/net_rpc.c @@ -6314,6 +6314,7 @@ BOOL net_rpc_check(unsigned flags) BOOL ret = False; struct in_addr server_ip; char *server_name = NULL; + NTSTATUS status; /* flags (i.e. server type) may depend on command */ if (!net_find_server(NULL, flags, &server_ip, &server_name)) @@ -6323,7 +6324,8 @@ BOOL net_rpc_check(unsigned flags) return False; } - if (!cli_connect(cli, server_name, &server_ip)) + status = cli_connect(cli, server_name, &server_ip); + if (!NT_STATUS_IS_OK(status)) goto done; if (!attempt_netbios_session_request(&cli, global_myname(), server_name, &server_ip)) diff --git a/source/utils/net_time.c b/source/utils/net_time.c index f6269627dab..5e952780d32 100644 --- a/source/utils/net_time.c +++ b/source/utils/net_time.c @@ -29,14 +29,16 @@ static time_t cli_servertime(const char *host, struct in_addr *ip, int *zone) struct nmb_name calling, called; time_t ret = 0; struct cli_state *cli = NULL; + NTSTATUS status; cli = cli_initialise(); if (!cli) { goto done; } - if (!cli_connect(cli, host, ip)) { - fprintf(stderr,"Can't contact server\n"); + status = cli_connect(cli, host, ip); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr,"Can't contact server %s. Error %s\n", host, nt_errstr(status)); goto done; } diff --git a/source/web/diagnose.c b/source/web/diagnose.c index b53e139ca94..5f05d8ac9e9 100644 --- a/source/web/diagnose.c +++ b/source/web/diagnose.c @@ -60,12 +60,14 @@ BOOL nmbd_running(void) then closing it */ BOOL smbd_running(void) { + NTSTATUS status; struct cli_state *cli; if ((cli = cli_initialise()) == NULL) return False; - if (!cli_connect(cli, global_myname(), &loopback_ip)) { + status = cli_connect(cli, global_myname(), &loopback_ip); + if (!NT_STATUS_IS_OK(status)) { cli_shutdown(cli); return False; } |