summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/smb.conf.default11
-rw-r--r--packaging/RedHat/samba.spec.tmpl3
-rw-r--r--source/Makefile.in8
-rw-r--r--source/VERSION4
-rw-r--r--source/auth/auth_util.c55
-rw-r--r--source/client/client.c24
-rw-r--r--source/client/clitar.c6
-rw-r--r--source/client/smbspool.c20
-rw-r--r--source/configure.in66
-rw-r--r--source/include/client.h1
-rw-r--r--source/include/debug.h2
-rw-r--r--source/include/includes.h5
-rw-r--r--source/include/local.h5
-rw-r--r--source/include/rpc_dce.h3
-rw-r--r--source/include/rpc_netlogon.h42
-rw-r--r--source/include/rpc_samr.h15
-rw-r--r--source/include/safe_string.h2
-rw-r--r--source/include/smb.h65
-rw-r--r--source/include/smbldap.h3
-rw-r--r--source/lib/afs_settoken.c14
-rw-r--r--source/lib/charcnv.c2
-rw-r--r--source/lib/iconv.c6
-rw-r--r--source/lib/interface.c12
-rw-r--r--source/lib/smbldap.c25
-rw-r--r--source/lib/snprintf.c2
-rw-r--r--source/lib/time.c6
-rw-r--r--source/lib/username.c31
-rw-r--r--source/lib/util.c18
-rw-r--r--source/lib/util_sock.c22
-rw-r--r--source/lib/util_str.c2
-rw-r--r--source/libads/kerberos.c4
-rw-r--r--source/libads/kerberos_keytab.c554
-rw-r--r--source/libads/kerberos_verify.c313
-rw-r--r--source/libads/krb5_setpw.c49
-rw-r--r--source/libads/ldap.c410
-rw-r--r--source/libads/sasl.c4
-rw-r--r--source/libsmb/asn1.c12
-rw-r--r--source/libsmb/clientgen.c19
-rw-r--r--source/libsmb/clikrb5.c29
-rw-r--r--source/libsmb/clispnego.c12
-rw-r--r--source/libsmb/conncache.c2
-rw-r--r--source/libsmb/namequery.c391
-rw-r--r--source/libsmb/ntlmssp.c2
-rw-r--r--source/libsmb/smb_signing.c46
-rw-r--r--source/locking/brlock.c4
-rw-r--r--source/locking/locking.c408
-rw-r--r--source/nmbd/nmbd_browsesync.c5
-rw-r--r--source/nmbd/nmbd_winsserver.c7
-rw-r--r--source/nsswitch/winbindd.c13
-rw-r--r--source/nsswitch/winbindd_cache.c6
-rw-r--r--source/nsswitch/winbindd_cm.c46
-rw-r--r--source/nsswitch/winbindd_group.c52
-rw-r--r--source/nsswitch/winbindd_passdb.c11
-rw-r--r--source/nsswitch/winbindd_rpc.c34
-rw-r--r--source/nsswitch/winbindd_util.c2
-rw-r--r--source/param/loadparm.c94
-rw-r--r--source/passdb/login_cache.c3
-rw-r--r--source/passdb/lookup_sid.c11
-rw-r--r--source/passdb/passdb.c1
-rw-r--r--source/passdb/pdb_ldap.c25
-rw-r--r--source/printing/notify.c2
-rw-r--r--source/printing/nt_printing.c12
-rw-r--r--source/printing/print_cups.c47
-rw-r--r--source/printing/printing.c30
-rw-r--r--source/printing/printing_db.c4
-rw-r--r--source/rpc_client/cli_netlogon.c11
-rw-r--r--source/rpc_client/cli_pipe.c11
-rw-r--r--source/rpc_parse/parse_net.c67
-rw-r--r--source/rpc_parse/parse_prs.c5
-rw-r--r--source/rpc_parse/parse_samr.c49
-rw-r--r--source/rpc_server/srv_lsa_nt.c14
-rw-r--r--source/rpc_server/srv_netlog.c11
-rw-r--r--source/rpc_server/srv_netlog_nt.c69
-rw-r--r--source/rpc_server/srv_pipe.c2
-rw-r--r--source/rpc_server/srv_pipe_hnd.c2
-rw-r--r--source/rpc_server/srv_samr_util.c6
-rw-r--r--source/rpc_server/srv_spoolss_nt.c22
-rw-r--r--source/rpc_server/srv_srvsvc_nt.c34
-rw-r--r--source/rpcclient/cmd_spoolss.c79
-rw-r--r--source/sam/idmap.c29
-rw-r--r--source/sam/idmap_ldap.c8
-rw-r--r--source/script/mkproto.awk4
-rw-r--r--source/smbd/blocking.c2
-rw-r--r--source/smbd/close.c34
-rw-r--r--source/smbd/conn.c2
-rw-r--r--source/smbd/connection.c8
-rw-r--r--source/smbd/dir.c3
-rw-r--r--source/smbd/dosmode.c13
-rw-r--r--source/smbd/error.c11
-rw-r--r--source/smbd/filename.c27
-rw-r--r--source/smbd/lanman.c4
-rw-r--r--source/smbd/mangle_hash.c6
-rw-r--r--source/smbd/msdfs.c4
-rw-r--r--source/smbd/negprot.c19
-rw-r--r--source/smbd/notify_hash.c2
-rw-r--r--source/smbd/nttrans.c236
-rw-r--r--source/smbd/open.c375
-rw-r--r--source/smbd/oplock.c80
-rw-r--r--source/smbd/posix_acls.c42
-rw-r--r--source/smbd/process.c257
-rw-r--r--source/smbd/quotas.c204
-rw-r--r--source/smbd/reply.c187
-rw-r--r--source/smbd/server.c10
-rw-r--r--source/smbd/service.c41
-rw-r--r--source/smbd/session.c4
-rw-r--r--source/smbd/sesssetup.c4
-rw-r--r--source/smbd/trans2.c77
-rw-r--r--source/smbd/uid.c7
-rw-r--r--source/smbd/utmp.c4
-rw-r--r--source/smbd/vfs.c36
-rw-r--r--source/tdb/Makefile5
-rw-r--r--source/torture/torture.c4
-rw-r--r--source/torture/vfstest.c2
-rw-r--r--source/utils/net_ads.c453
-rw-r--r--source/utils/net_rpc.c86
-rw-r--r--source/utils/ntlm_auth.c48
-rw-r--r--source/utils/smbcacls.c5
117 files changed, 4711 insertions, 1158 deletions
diff --git a/examples/smb.conf.default b/examples/smb.conf.default
index 839fede1233..58d38aa9f7d 100644
--- a/examples/smb.conf.default
+++ b/examples/smb.conf.default
@@ -4,7 +4,12 @@
# many!) most of which are not shown in this example
#
# For a step to step guide on installing, configuring and using samba,
-# read the Samba HOWTO Collection.
+# read the Samba-HOWTO-Collection. This may be obtained from:
+# http://www.samba.org/samba/docs/Samba-HOWTO-Collection.pdf
+#
+# Many working examples of smb.conf files can be found in the
+# Samba-Guide which is generated daily and can be downloaded from:
+# http://www.samba.org/samba/docs/Samba-Guide.pdf
#
# Any line which starts with a ; (semi-colon) or a # (hash)
# is a comment and is ignored. In this example we will use a #
@@ -17,7 +22,7 @@
#======================= Global Settings =====================================
[global]
-# workgroup = NT-Domain-Name or Workgroup-Name, eg: REDHAT4
+# workgroup = NT-Domain-Name or Workgroup-Name, eg: MIDEARTH
workgroup = MYGROUP
# server string is the equivalent of the NT Description field
@@ -25,7 +30,7 @@
# Security mode. Defines in which mode Samba will operate. Possible
# values are share, user, server, domain and ads. Most people will want
-# user level security. See the HOWTO Collection for details.
+# user level security. See the Samba-HOWTO-Collection for details.
security = user
# This option is important for security. It allows you to restrict
diff --git a/packaging/RedHat/samba.spec.tmpl b/packaging/RedHat/samba.spec.tmpl
index 06237af7260..aafb9bd2188 100644
--- a/packaging/RedHat/samba.spec.tmpl
+++ b/packaging/RedHat/samba.spec.tmpl
@@ -16,7 +16,8 @@ Source998: filter-requires-samba_rh8.sh
Source999: filter-requires-samba_rh9.sh
Packager: Gerald Carter [Samba-Team] <jerry@samba.org>
-Requires: pam pam-devel kernel glibc
+Requires: pam openldap krb5-libs
+BuildRequires: openldap-devel krb5-devel pam-devel
Prereq: chkconfig fileutils /sbin/ldconfig
Provides: samba = %{version}
Obsoletes: samba-common, samba-client, samba-swat
diff --git a/source/Makefile.in b/source/Makefile.in
index c8d2b959a4d..398ad4e0e3f 100644
--- a/source/Makefile.in
+++ b/source/Makefile.in
@@ -228,7 +228,7 @@ KRBCLIENT_OBJ = libads/kerberos.o libads/ads_status.o
LIBADS_OBJ = libads/ldap.o libads/ldap_printer.o libads/sasl.o \
libads/krb5_setpw.o libads/ldap_user.o \
- libads/ads_struct.o \
+ libads/ads_struct.o libads/kerberos_keytab.o \
libads/disp_sec.o libads/ads_utils.o libads/ldap_utils.o \
libads/ads_ldap.o libads/authdata.o
@@ -1315,9 +1315,9 @@ installswat: installdirs installmsg
@$(SHELL) $(srcdir)/script/installswat.sh $(DESTDIR)$(SWATDIR) $(srcdir)
installclientlib: installdirs libsmbclient
- @$(SHELL) $(srcdir)/script/installdirs.sh $(DESTDIR)${prefix}/lib
- -$(INSTALLCLIENTCMD_SH) bin/libsmbclient.@SHLIBEXT@ $(DESTDIR)${prefix}/lib
- -$(INSTALLCLIENTCMD_A) bin/libsmbclient.a $(DESTDIR)${prefix}/lib
+ @$(SHELL) $(srcdir)/script/installdirs.sh $(DESTDIR)$(LIBDIR)
+ -$(INSTALLCLIENTCMD_SH) bin/libsmbclient.@SHLIBEXT@ $(DESTDIR)$(LIBDIR)
+ -$(INSTALLCLIENTCMD_A) bin/libsmbclient.a $(DESTDIR)$(LIBDIR)
@$(SHELL) $(srcdir)/script/installdirs.sh $(DESTDIR)${prefix}/include
-$(INSTALLCMD) $(srcdir)/include/libsmbclient.h $(DESTDIR)${prefix}/include
diff --git a/source/VERSION b/source/VERSION
index e493805fdb4..5a7d9836c85 100644
--- a/source/VERSION
+++ b/source/VERSION
@@ -29,7 +29,7 @@ SAMBA_VERSION_RELEASE=5
# e.g. SAMBA_VERSION_PRE_RELEASE=1 #
# -> "2.2.9pre1" #
########################################################
-SAMBA_VERSION_PRE_RELEASE=1
+SAMBA_VERSION_PRE_RELEASE=2
########################################################
# For 'rc' releases the version will be #
@@ -51,7 +51,7 @@ SAMBA_VERSION_RC_RELEASE=
# e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes #
# -> "3.0.0-SVN-build-199" #
########################################################
-SAMBA_VERSION_IS_SVN_SNAPSHOT=
+SAMBA_VERSION_IS_SVN_SNAPSHOT=yes
########################################################
# This can be set by vendors if they want... #
diff --git a/source/auth/auth_util.c b/source/auth/auth_util.c
index 9a03e7fe13c..5e8f18881fb 100644
--- a/source/auth/auth_util.c
+++ b/source/auth/auth_util.c
@@ -972,25 +972,25 @@ struct passwd *smb_getpwnam( char *domuser, fstring save_username, BOOL create )
{
struct passwd *pw = NULL;
char *p;
- fstring mapped_username;
- fstring strip_username;
+ fstring username;
/* we only save a copy of the username it has been mangled
by winbindd use default domain */
save_username[0] = '\0';
-
- /* save a local copy of the username and run it through the
- username map */
- fstrcpy( mapped_username, domuser );
- map_username( mapped_username );
+ /* don't call map_username() here since it has to be done higher
+ up the stack so we don't call it mutliple times */
+
+ fstrcpy( username, domuser );
- p = strchr_m( mapped_username, *lp_winbind_separator() );
+ p = strchr_m( username, *lp_winbind_separator() );
/* code for a DOMAIN\user string */
if ( p ) {
+ fstring strip_username;
+
pw = Get_Pwnam( domuser );
if ( pw ) {
/* make sure we get the case of the username correct */
@@ -999,8 +999,10 @@ struct passwd *smb_getpwnam( char *domuser, fstring save_username, BOOL create )
if ( !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) {
char *domain;
- domain = mapped_username;
+ /* split the domain and username into 2 strings */
*p = '\0';
+ domain = username;
+
fstr_sprintf(save_username, "%s%c%s", domain, *lp_winbind_separator(), pw->pw_name);
}
else
@@ -1011,26 +1013,26 @@ struct passwd *smb_getpwnam( char *domuser, fstring save_username, BOOL create )
}
/* setup for lookup of just the username */
- /* remember that p and mapped_username are overlapping memory */
+ /* remember that p and username are overlapping memory */
p++;
fstrcpy( strip_username, p );
- fstrcpy( mapped_username, strip_username );
+ fstrcpy( username, strip_username );
}
/* just lookup a plain username */
- pw = Get_Pwnam(mapped_username);
+ pw = Get_Pwnam(username);
/* Create local user if requested. */
if ( !pw && create ) {
/* Don't add a machine account. */
- if (mapped_username[strlen(mapped_username)-1] == '$')
+ if (username[strlen(username)-1] == '$')
return NULL;
- auth_add_user_script(NULL, mapped_username);
- pw = Get_Pwnam(mapped_username);
+ auth_add_user_script(NULL, username);
+ pw = Get_Pwnam(username);
}
/* one last check for a valid passwd struct */
@@ -1207,7 +1209,7 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
/* Create a 'combined' list of all SIDs we might want in the SD */
- all_group_SIDs = malloc(sizeof(DOM_SID) * (info3->num_groups2 +info3->num_other_sids));
+ all_group_SIDs = malloc(sizeof(DOM_SID) * (info3->num_groups2 + info3->num_other_sids + n_lgroupSIDs));
if (!all_group_SIDs) {
DEBUG(0, ("malloc() failed for DOM_SID list!\n"));
@@ -1216,12 +1218,6 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
return NT_STATUS_NO_MEMORY;
}
-#if 0 /* JERRY -- no such thing as local groups in current code */
- /* Copy the 'local' sids */
- memcpy(all_group_SIDs, lgroupSIDs, sizeof(DOM_SID) * n_lgroupSIDs);
- SAFE_FREE(lgroupSIDs);
-#endif
-
/* and create (by appending rids) the 'domain' sids */
for (i = 0; i < info3->num_groups2; i++) {
@@ -1254,13 +1250,22 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
sid_copy(&all_group_SIDs[info3->num_groups2 + i],
&info3->other_sids[i].sid);
}
+
+
+ /* add local alias sids */
+
+ for (i = 0; i < n_lgroupSIDs; i++) {
+ sid_copy(&all_group_SIDs[info3->num_groups2 +
+ info3->num_other_sids + i],
+ &lgroupSIDs[i]);
+ }
/* Where are the 'global' sids... */
/* can the user be guest? if yes, where is it stored? */
nt_status = create_nt_user_token(&user_sid, &group_sid,
- info3->num_groups2 + info3->num_other_sids,
+ info3->num_groups2 + info3->num_other_sids + n_lgroupSIDs,
all_group_SIDs, False, &token);
if ( !NT_STATUS_IS_OK(nt_status) ) {
@@ -1425,8 +1430,10 @@ BOOL is_trusted_domain(const char* dom_name)
/* if we are a DC, then check for a direct trust relationships */
- if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
+ if ( IS_DC ) {
become_root();
+ DEBUG (5,("is_trusted_domain: Checking for domain trust with [%s]\n",
+ dom_name ));
ret = secrets_fetch_trusted_domain_password(dom_name, &pass, &trustdom_sid, &lct);
unbecome_root();
SAFE_FREE(pass);
diff --git a/source/client/client.c b/source/client/client.c
index a0470315f82..1fccfaa581c 100644
--- a/source/client/client.c
+++ b/source/client/client.c
@@ -1571,7 +1571,7 @@ static int cmd_open(void)
}
pstrcat(mask,buf);
- cli_open(cli, mask, O_RDWR, DENY_ALL);
+ cli_nt_create(cli, mask, FILE_READ_DATA);
return 0;
}
@@ -1869,6 +1869,21 @@ static int cmd_lowercase(void)
}
/****************************************************************************
+ Toggle the case sensitive flag.
+****************************************************************************/
+
+static int cmd_setcase(void)
+{
+ BOOL orig_case_sensitive = cli_set_case_sensitive(cli, False);
+
+ cli_set_case_sensitive(cli, !orig_case_sensitive);
+ DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
+ "on":"off"));
+
+ return 0;
+}
+
+/****************************************************************************
Toggle the recurse flag.
****************************************************************************/
@@ -2179,6 +2194,7 @@ static struct
{"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}},
{"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
{"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
+ {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
{"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
{"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
{"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
@@ -2563,9 +2579,10 @@ static void readline_callback(void)
Process commands on stdin.
****************************************************************************/
-static void process_stdin(void)
+static int process_stdin(void)
{
const char *ptr;
+ int rc = 0;
while (1) {
pstring tok;
@@ -2593,13 +2610,14 @@ static void process_stdin(void)
if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
if ((i = process_tok(tok)) >= 0) {
- commands[i].fn();
+ rc = commands[i].fn();
} else if (i == -2) {
d_printf("%s: command abbreviation ambiguous\n",tok);
} else {
d_printf("%s: command not found\n",tok);
}
}
+ return rc;
}
/*****************************************************
diff --git a/source/client/clitar.c b/source/client/clitar.c
index e43b3e4cc50..64c194b54da 100644
--- a/source/client/clitar.c
+++ b/source/client/clitar.c
@@ -1357,9 +1357,8 @@ int cmd_tar(void)
if (!tar_parseargs(argcl, argl, buf, 0))
return 1;
- process_tar();
SAFE_FREE(argl);
- return 0;
+ return process_tar();
}
/****************************************************************************
@@ -1368,6 +1367,7 @@ Command line (option) version
int process_tar(void)
{
+ int rc = 0;
initarbuf();
switch(tar_type) {
case 'x':
@@ -1445,7 +1445,7 @@ int process_tar(void)
clipn = 0;
must_free_cliplist = False;
}
- return(0);
+ return rc;
}
/****************************************************************************
diff --git a/source/client/smbspool.c b/source/client/smbspool.c
index 5daefec5a55..a67ccadb90b 100644
--- a/source/client/smbspool.c
+++ b/source/client/smbspool.c
@@ -36,7 +36,7 @@ extern BOOL in_client; /* Boolean for client library */
*/
static void list_devices(void);
-static struct cli_state *smb_connect(const char *, const char *, const char *, const char *, const char *);
+static struct cli_state *smb_connect(const char *, const char *, int, const char *, const char *, const char *);
static int smb_print(struct cli_state *, char *, FILE *);
@@ -50,6 +50,7 @@ static int smb_print(struct cli_state *, char *, FILE *);
{
int i; /* Looping var */
int copies; /* Number of copies */
+ int port; /* Port number */
char uri[1024], /* URI */
*sep, /* Pointer to separator */
*password; /* Password */
@@ -87,7 +88,7 @@ static int smb_print(struct cli_state *, char *, FILE *);
fputs(" The DEVICE_URI environment variable can also contain the\n", stderr);
fputs(" destination printer:\n", stderr);
fputs("\n", stderr);
- fputs(" smb://[username:password@][workgroup/]server/printer\n", stderr);
+ fputs(" smb://[username:password@][workgroup/]server[:port]/printer\n", stderr);
return (1);
}
@@ -179,7 +180,17 @@ static int smb_print(struct cli_state *, char *, FILE *);
}
else
workgroup = NULL;
+
+ if ((sep = strrchr_m(server, ':')) != NULL)
+ {
+ *sep++ = '\0';
+ port=atoi(sep);
+ }
+ else
+ port=0;
+
+
/*
* Setup the SAMBA server state...
*/
@@ -201,7 +212,7 @@ static int smb_print(struct cli_state *, char *, FILE *);
do
{
- if ((cli = smb_connect(workgroup, server, printer, username, password)) == NULL)
+ if ((cli = smb_connect(workgroup, server, port, printer, username, password)) == NULL)
{
if (getenv("CLASS") == NULL)
{
@@ -267,6 +278,7 @@ list_devices(void)
static struct cli_state * /* O - SMB connection */
smb_connect(const char *workgroup, /* I - Workgroup */
const char *server, /* I - Server */
+ const int port, /* I - Port */
const char *share, /* I - Printer */
const char *username, /* I - Username */
const char *password) /* I - Password */
@@ -281,7 +293,7 @@ smb_connect(const char *workgroup, /* I - Workgroup */
get_myname(myname);
- nt_status = cli_full_connection(&c, myname, server, NULL, 0, share, "?????",
+ nt_status = cli_full_connection(&c, myname, server, NULL, port, share, "?????",
username, workgroup, password, 0, Undefined, NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
diff --git a/source/configure.in b/source/configure.in
index e1fc69b4b79..e57076a346a 100644
--- a/source/configure.in
+++ b/source/configure.in
@@ -11,6 +11,11 @@ AC_ENABLE_SHARED
SMB_VERSION_STRING=`cat include/version.h | grep 'SAMBA_VERSION_OFFICIAL_STRING' | cut -d '"' -f2`
echo "SAMBA VERSION: ${SMB_VERSION_STRING}"
+SAMBA_VERSION_SVN_REVISION=`cat include/version.h | grep 'SAMBA_VERSION_SVN_REVISION' | cut -d ' ' -f3-`
+if test -n "${SAMBA_VERSION_SVN_REVISION}";then
+ echo "BUILD REVISION: ${SAMBA_VERSION_SVN_REVISION}"
+fi
+
#################################################
# Directory handling stuff to support both the
# legacy SAMBA directories and FHS compliant
@@ -707,10 +712,12 @@ if test x$enable_cups != xno; then
AC_PATH_PROG(CUPS_CONFIG, cups-config)
if test "x$CUPS_CONFIG" != x; then
- AC_DEFINE(HAVE_CUPS,1,[Whether we have CUPS])
+ AC_DEFINE(HAVE_CUPS,1,[Whether we have CUPS])
CFLAGS="$CFLAGS `$CUPS_CONFIG --cflags`"
LDFLAGS="$LDFLAGS `$CUPS_CONFIG --ldflags`"
PRINT_LIBS="$PRINT_LIBS `$CUPS_CONFIG --libs`"
+ elif test x$enable_cups == xyes; then
+ AC_MSG_ERROR(Cups support required but cups-config not located. Make sure cups-devel related files are installed.)
fi
fi
@@ -2708,6 +2715,7 @@ if test x"$with_ads_support" != x"no"; then
# now see if we can find the krb5 libs in standard paths
# or as specified above
AC_CHECK_LIB_EXT(krb5, KRB5_LIBS, krb5_mk_req_extended)
+ AC_CHECK_LIB_EXT(krb5, KRB5_LIBS, krb5_kt_compare)
########################################################
# now see if we can find the gssapi libs in standard paths
@@ -2730,6 +2738,9 @@ if test x"$with_ads_support" != x"no"; then
AC_CHECK_FUNC_EXT(krb5_free_ktypes, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(krb5_free_data_contents, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(krb5_principal_get_comp_string, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_free_unparsed_name, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_free_keytab_entry_contents, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_kt_free_entry, $KRB5_LIBS)
LIBS="$LIBS $KRB5_LIBS"
@@ -2812,6 +2823,18 @@ if test x"$with_ads_support" != x"no"; then
[Whether the AP_OPTS_USE_SUBKEY ap option is available])
fi
+ AC_CACHE_CHECK([for KV5M_KEYTAB],
+ samba_cv_HAVE_KV5M_KEYTAB,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keytab_entry entry; entry.magic = KV5M_KEYTAB;],
+ samba_cv_HAVE_KV5M_KEYTAB=yes,
+ samba_cv_HAVE_KV5M_KEYTAB=no)])
+
+ if test x"$samba_cv_HAVE_KV5M_KEYTAB" = x"yes"; then
+ AC_DEFINE(HAVE_KV5M_KEYTAB,1,
+ [Whether the KV5M_KEYTAB option is available])
+ fi
+
AC_CACHE_CHECK([for the krb5_princ_component macro],
samba_cv_HAVE_KRB5_PRINC_COMPONENT,[
AC_TRY_LINK([#include <krb5.h>],
@@ -2862,7 +2885,45 @@ if test x"$with_ads_support" != x"no"; then
KRB5_LIBS=""
with_ads_support=no
fi
- LIBS="$ac_save_LIBS"
+
+ AC_CACHE_CHECK([for WRFILE: keytab support],
+ samba_cv_HAVE_WRFILE_KEYTAB,[
+ AC_TRY_RUN([
+#include<krb5.h>
+ main()
+ {
+ krb5_context context;
+ krb5_keytab keytab;
+
+ krb5_init_context(&context);
+ if (krb5_kt_resolve(context, "WRFILE:api", &keytab))
+ exit(0);
+ exit(1);
+ }],
+ samba_cv_HAVE_WRFILE_KEYTAB=no,
+ samba_cv_HAVE_WRFILE_KEYTAB=yes)])
+
+ if test x"$samba_cv_HAVE_WRFILE_KEYTAB" = x"yes"; then
+ AC_DEFINE(HAVE_WRFILE_KEYTAB,1,
+ [Whether the WRFILE:-keytab is supported])
+ fi
+
+ AC_CACHE_CHECK([for krb5_princ_realm returns krb5_realm or krb5_data],
+ samba_cv_KRB5_PRINC_REALM_RETURNS_REALM,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [
+ krb5_context context;
+ krb5_principal principal;
+ krb5_realm realm; realm = *krb5_princ_realm(context, principal);],
+ samba_cv_KRB5_PRINC_REALM_RETURNS_REALM=yes,
+ samba_cv_KRB5_PRINC_REALM_RETURNS_REALM=no)])
+
+ if test x"$samba_cv_KRB5_PRINC_REALM_RETURNS_REALM" = x"yes"; then
+ AC_DEFINE(KRB5_PRINC_REALM_RETURNS_REALM,1,
+ [Whether krb5_princ_realm returns krb5_realm or krb5_data])
+ fi
+
+LIBS="$ac_save_LIBS"
fi
########################################################
@@ -2950,6 +3011,7 @@ AC_ARG_WITH(smbmount,
)
+
#################################################
# check for a PAM clear-text auth, accounts, password and session support
with_pam_for_crypt=no
diff --git a/source/include/client.h b/source/include/client.h
index 968b73f0b41..52a6c76299d 100644
--- a/source/include/client.h
+++ b/source/include/client.h
@@ -153,6 +153,7 @@ struct cli_state {
BOOL (*oplock_handler)(struct cli_state *cli, int fnum, unsigned char level);
BOOL force_dos_errors;
+ BOOL case_sensitive; /* False by default. */
/* was this structure allocated by cli_initialise? If so, then
free in cli_shutdown() */
diff --git a/source/include/debug.h b/source/include/debug.h
index 52e06b9360b..05a9a3f0c52 100644
--- a/source/include/debug.h
+++ b/source/include/debug.h
@@ -33,7 +33,7 @@
* diffferent prototype declarations), so we must do these by hand.
*/
/* I know the __attribute__ stuff is ugly, but it does ensure we get the
- arguemnts to DEBUG() right. We have got them wrong too often in the
+ arguments to DEBUG() right. We have got them wrong too often in the
past.
The PRINTFLIKE comment does the equivalent for SGI MIPSPro.
*/
diff --git a/source/include/includes.h b/source/include/includes.h
index ea8eb1a3043..7657984bfb1 100644
--- a/source/include/includes.h
+++ b/source/include/includes.h
@@ -1239,6 +1239,7 @@ int asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3);
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
#define snprintf smb_snprintf
+#define vsnprintf smb_vsnprintf
#endif
void sys_adminlog(int priority, const char *format_str, ...) PRINTF_ATTRIBUTE(2,3);
@@ -1293,6 +1294,10 @@ krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype
krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock);
#endif
+#ifndef HAVE_KRB5_FREE_UNPARSED_NAME
+void krb5_free_unparsed_name(krb5_context ctx, char *val);
+#endif
+
/* Samba wrapper function for krb5 functionality. */
void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr);
int create_kerberos_key_from_string(krb5_context context, krb5_principal host_princ, krb5_data *password, krb5_keyblock *key, krb5_enctype enctype);
diff --git a/source/include/local.h b/source/include/local.h
index 540365047a2..7ac2e256120 100644
--- a/source/include/local.h
+++ b/source/include/local.h
@@ -230,4 +230,9 @@
/* size of listen() backlog in smbd */
#define SMBD_LISTEN_BACKLOG 50
+/* Number of microseconds to wait before a sharing violation. */
+#define SHARING_VIOLATION_USEC_WAIT 950000
+
+#define MAX_LDAP_REPLICATION_SLEEP_TIME 5000 /* In milliseconds. */
+
#endif
diff --git a/source/include/rpc_dce.h b/source/include/rpc_dce.h
index 0df903109db..57b1184bd96 100644
--- a/source/include/rpc_dce.h
+++ b/source/include/rpc_dce.h
@@ -71,7 +71,8 @@ enum RPC_PKT_TYPE
to NT4. Actually, anything other than 1ff would seem to do... */
#define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff
-#define NETLOGON_NEG_SCHANNEL 0x40000000
+#define NETLOGON_NEG_SCHANNEL 0x40000000
+#define NETLOGON_NEG_DOMAIN_TRUST_ACCOUNT 0x2010b000
enum netsec_direction
{
diff --git a/source/include/rpc_netlogon.h b/source/include/rpc_netlogon.h
index a5b93b0238a..44beb2b8c82 100644
--- a/source/include/rpc_netlogon.h
+++ b/source/include/rpc_netlogon.h
@@ -68,6 +68,11 @@
#define SAM_DATABASE_BUILTIN 0x01 /* BUILTIN users and groups */
#define SAM_DATABASE_PRIVS 0x02 /* Privileges */
+#define NETLOGON_CONTROL_REDISCOVER 0x5
+#define NETLOGON_CONTROL_TC_QUERY 0x6
+#define NETLOGON_CONTROL_TRANSPORT_NOTIFY 0x7
+#define NETLOGON_CONTROL_SET_DBFLAG 0xfffe
+
#if 0
/* I think this is correct - it's what gets parsed on the wire. JRA. */
/* NET_USER_INFO_2 */
@@ -204,7 +209,7 @@ typedef struct netlogon_2_info
uint32 flags; /* 0x0 - undocumented */
uint32 pdc_status; /* 0x0 - undocumented */
uint32 ptr_trusted_dc_name; /* pointer to trusted domain controller name */
- uint32 tc_status; /* 0x051f - ERROR_NO_LOGON_SERVERS */
+ uint32 tc_status;
UNISTR2 uni_trusted_dc_name; /* unicode string - trusted dc name */
} NETLOGON_INFO_2;
@@ -255,6 +260,26 @@ typedef struct net_r_logon_ctrl_info
NTSTATUS status;
} NET_R_LOGON_CTRL;
+
+typedef struct ctrl_data_info_5
+{
+ uint32 function_code;
+
+ uint32 ptr_domain;
+ UNISTR2 domain;
+
+} CTRL_DATA_INFO_5;
+
+typedef struct ctrl_data_info_6
+{
+ uint32 function_code;
+
+ uint32 ptr_domain;
+ UNISTR2 domain;
+
+} CTRL_DATA_INFO_6;
+
+
/********************************************************
Logon Control2 Query
@@ -266,13 +291,16 @@ typedef struct net_r_logon_ctrl_info
/* NET_Q_LOGON_CTRL2 - LSA Netr Logon Control 2 */
typedef struct net_q_logon_ctrl2_info
{
- uint32 ptr; /* undocumented buffer pointer */
- UNISTR2 uni_server_name; /* server name, starting with two '\'s */
+ uint32 ptr; /* undocumented buffer pointer */
+ UNISTR2 uni_server_name; /* server name, starting with two '\'s */
+
+ uint32 function_code;
+ uint32 query_level;
+ union {
+ CTRL_DATA_INFO_5 info5;
+ CTRL_DATA_INFO_6 info6;
+ } info;
- uint32 function_code; /* 0x1 */
- uint32 query_level; /* 0x1, 0x3 */
- uint32 switch_value; /* 0x1 */
-
} NET_Q_LOGON_CTRL2;
/*******************************************************
diff --git a/source/include/rpc_samr.h b/source/include/rpc_samr.h
index 089941de3aa..ae603c9cd93 100644
--- a/source/include/rpc_samr.h
+++ b/source/include/rpc_samr.h
@@ -1068,6 +1068,14 @@ typedef struct samr_group_info1
} GROUP_INFO1;
+typedef struct samr_group_info2
+{
+ uint16 level;
+ UNIHDR hdr_acct_name;
+ UNISTR2 uni_acct_name;
+
+} GROUP_INFO2;
+
typedef struct samr_group_info3
{
uint32 unknown_1; /* 0x0000 0003 - number of group members? */
@@ -1090,6 +1098,7 @@ typedef struct group_info_ctr
union
{
GROUP_INFO1 info1;
+ GROUP_INFO2 info2;
GROUP_INFO3 info3;
GROUP_INFO4 info4;
@@ -1734,11 +1743,7 @@ typedef struct q_samr_get_dom_pwinfo
typedef struct r_samr_get_dom_pwinfo
{
/*
- * Previously this was 3 uint16's. However, after some tests
- * it appears that the data len for the signing needs to be 16.
- * Not sure how 3 unit16's ever worked since the length always
- * turned out to 12. 3 uint32's + NT_STATUS == 16 bytes. Tested
- * using NT and 2k. --jerry
+ * See Samba4 IDL
*/
uint16 unk_0;
uint32 unk_1;
diff --git a/source/include/safe_string.h b/source/include/safe_string.h
index b22c5efcc99..d278e29aca5 100644
--- a/source/include/safe_string.h
+++ b/source/include/safe_string.h
@@ -59,7 +59,7 @@
#ifdef strncasecmp
#undef strncasecmp
#endif
-#define strncasecmp __ERROR__XX__NEVER_USE_STRCASECMP__;
+#define strncasecmp __ERROR__XX__NEVER_USE_STRNCASECMP__;
#endif /* !_SPLINT_ */
diff --git a/source/include/smb.h b/source/include/smb.h
index 54a69d1433a..a802e962266 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -584,6 +584,24 @@ struct interface
struct in_addr nmask;
};
+/* struct used by share mode violation error processing */
+typedef struct {
+ pid_t pid;
+ uint16 mid;
+ struct timeval time;
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ uint16 port;
+} deferred_open_entry;
+
+/* Internal message queue for deferred opens. */
+struct pending_message_list {
+ struct pending_message_list *next, *prev;
+ struct timeval msg_time; /* The timeout time */
+ DATA_BLOB buf;
+ DATA_BLOB private_data;
+};
+
/* struct returned by get_share_modes */
typedef struct {
pid_t pid;
@@ -663,28 +681,14 @@ struct locking_key {
SMB_INO_T inode;
};
-struct locking_data {
- union {
- int num_share_mode_entries;
- share_mode_entry dummy; /* Needed for alignment. */
- } u;
- /* the following two entries are implicit
- share_mode_entry modes[num_share_mode_entries];
- char file_name[];
- */
-};
-
-
/* the following are used by loadparm for option lists */
-typedef enum
-{
- P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_LIST,
- P_STRING,P_USTRING,P_GSTRING,P_UGSTRING,P_ENUM,P_SEP
+typedef enum {
+ P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_LIST,
+ P_STRING,P_USTRING,P_GSTRING,P_UGSTRING,P_ENUM,P_SEP
} parm_type;
-typedef enum
-{
- P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
+typedef enum {
+ P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
} parm_class;
/* passed to br lock code */
@@ -1345,7 +1349,8 @@ enum ldap_ssl_types {LDAP_SSL_ON, LDAP_SSL_OFF, LDAP_SSL_START_TLS};
enum ldap_passwd_sync_types {LDAP_PASSWD_SYNC_ON, LDAP_PASSWD_SYNC_OFF, LDAP_PASSWD_SYNC_ONLY};
/* Remote architectures we know about. */
-enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT, RA_WIN2K, RA_WINXP, RA_WIN2K3, RA_SAMBA};
+enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT,
+ RA_WIN2K, RA_WINXP, RA_WIN2K3, RA_SAMBA, RA_CIFSFS};
/* case handling */
enum case_handling {CASE_LOWER,CASE_UPPER};
@@ -1410,6 +1415,7 @@ extern int chain_size;
#define EXCLUSIVE_OPLOCK 1
#define BATCH_OPLOCK 2
#define LEVEL_II_OPLOCK 4
+#define INTERNAL_OPEN_ONLY 8
#define EXCLUSIVE_OPLOCK_TYPE(lck) ((lck) & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
#define BATCH_OPLOCK_TYPE(lck) ((lck) & BATCH_OPLOCK)
@@ -1461,6 +1467,25 @@ extern int chain_size;
#define LEVEL_II_OPLOCK_BREAK_CMD 0x3
#define ASYNC_LEVEL_II_OPLOCK_BREAK_CMD 0x4
+/* Add the "deferred open" message. */
+#define RETRY_DEFERRED_OPEN_CMD 0x5
+
+/*
+ * And the message format for it. Keep the same message length.
+ *
+ * 0 2 2+pid 2+pid+dev 2+pid+dev+ino
+ * +----+--------+-------+--------+---------+
+ * | cmd| pid | dev | inode | mid |
+ * +----+--------+-------+--------+---------+
+ */
+
+#define DEFERRED_OPEN_CMD_OFFSET 0
+#define DEFERRED_OPEN_PID_OFFSET 2 /* pid we're *sending* from. */
+#define DEFERRED_OPEN_DEV_OFFSET (DEFERRED_OPEN_PID_OFFSET + sizeof(pid_t))
+#define DEFERRED_OPEN_INODE_OFFSET (DEFERRED_OPEN_DEV_OFFSET + sizeof(SMB_DEV_T))
+#define DEFERRED_OPEN_MID_OFFSET (DEFERRED_OPEN_INODE_OFFSET + sizeof(SMB_INO_T))
+#define DEFERRED_OPEN_MSG_LEN OPLOCK_BREAK_MSG_LEN
+
/*
* Capabilities abstracted for different systems.
*/
diff --git a/source/include/smbldap.h b/source/include/smbldap.h
index 61b8df0f0ef..c7de7d84b37 100644
--- a/source/include/smbldap.h
+++ b/source/include/smbldap.h
@@ -153,5 +153,6 @@ struct smbldap_state {
struct smbldap_state;
-#endif /* _SMBLDAP_H */
+#define LDAP_CONNECT_DEFAULT_TIMEOUT 5
+#endif /* _SMBLDAP_H */
diff --git a/source/lib/afs_settoken.c b/source/lib/afs_settoken.c
index eb10c4c66d4..5c646c72e48 100644
--- a/source/lib/afs_settoken.c
+++ b/source/lib/afs_settoken.c
@@ -28,12 +28,16 @@
#include <afs/venus.h>
#include <asm/unistd.h>
#include <openssl/des.h>
+#include <sys/syscall.h>
-_syscall5(int, afs_syscall, int, subcall,
- char *, path,
- int, cmd,
- char *, cmarg,
- int, follow);
+int afs_syscall( int subcall,
+ char * path,
+ int cmd,
+ char * cmarg,
+ int follow)
+{
+ return( syscall( SYS_afs_syscall, subcall, path, cmd, cmarg, follow));
+}
struct ClearToken {
uint32 AuthHandle;
diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c
index b9791931a35..3d7678c34cb 100644
--- a/source/lib/charcnv.c
+++ b/source/lib/charcnv.c
@@ -932,7 +932,7 @@ size_t pull_ascii_fstring(char *dest, const void *src)
size_t pull_ascii_nstring(char *dest, size_t dest_len, const void *src)
{
- return pull_ascii(dest, src, dest_len, sizeof(nstring), STR_TERMINATE);
+ return pull_ascii(dest, src, dest_len, sizeof(nstring)-1, STR_TERMINATE);
}
/**
diff --git a/source/lib/iconv.c b/source/lib/iconv.c
index 7df73192f24..4c9ecf992e6 100644
--- a/source/lib/iconv.c
+++ b/source/lib/iconv.c
@@ -129,7 +129,11 @@ static size_t sys_iconv(void *cd,
size_t ret = iconv((iconv_t)cd,
inbuf, inbytesleft,
outbuf, outbytesleft);
- if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
+ if (ret == (size_t)-1) {
+ int saved_errno = errno;
+ iconv(cd, NULL, NULL, NULL, NULL);
+ errno = saved_errno;
+ }
return ret;
#else
errno = EINVAL;
diff --git a/source/lib/interface.c b/source/lib/interface.c
index 4d8010e31bc..adf9ca34381 100644
--- a/source/lib/interface.c
+++ b/source/lib/interface.c
@@ -94,7 +94,7 @@ This handles the following different forms:
4) ip/mask
5) bcast/mask
****************************************************************************/
-static void interpret_interface(const char *token)
+static void interpret_interface(char *token)
{
struct in_addr ip, nmask;
char *p;
@@ -130,9 +130,9 @@ static void interpret_interface(const char *token)
}
/* parse it into an IP address/netmasklength pair */
- *p++ = 0;
-
+ *p = 0;
ip = *interpret_addr2(token);
+ *p++ = '/';
if (strlen(p) > 2) {
nmask = *interpret_addr2(p);
@@ -207,7 +207,11 @@ void load_interfaces(void)
if (ptr) {
while (*ptr) {
- interpret_interface(*ptr);
+ char *ptr_cpy = strdup(*ptr);
+ if (ptr_cpy) {
+ interpret_interface(ptr_cpy);
+ free(ptr_cpy);
+ }
ptr++;
}
}
diff --git a/source/lib/smbldap.c b/source/lib/smbldap.c
index 21e2a7c1018..d058613f004 100644
--- a/source/lib/smbldap.c
+++ b/source/lib/smbldap.c
@@ -676,7 +676,7 @@ static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
*methodp = LDAP_AUTH_SIMPLE;
}
- gettimeofday(&(ldap_state->last_rebind),NULL);
+ GetTimeOfDay(&ldap_state->last_rebind);
return 0;
}
@@ -704,7 +704,7 @@ static int rebindproc_connect_with_state (LDAP *ldap_struct,
rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
- gettimeofday(&(ldap_state->last_rebind),NULL);
+ GetTimeOfDay(&ldap_state->last_rebind);
return rc;
}
@@ -755,8 +755,7 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_
char *ldap_secret;
/* get the password */
- if (!fetch_ldap_pw(&ldap_dn, &ldap_secret))
- {
+ if (!fetch_ldap_pw(&ldap_dn, &ldap_secret)) {
DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
return LDAP_INVALID_CREDENTIALS;
}
@@ -808,7 +807,7 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_
}
/**********************************************************************
-Connect to LDAP server (called before every ldap operation)
+ Connect to LDAP server (called before every ldap operation)
*********************************************************************/
static int smbldap_open(struct smbldap_state *ldap_state)
{
@@ -854,7 +853,7 @@ static int smbldap_open(struct smbldap_state *ldap_state)
ldap_state->last_ping = time(NULL);
- DEBUG(4,("The LDAP server is succesful connected\n"));
+ DEBUG(4,("The LDAP server is succesfully connected\n"));
return LDAP_SUCCESS;
}
@@ -933,25 +932,25 @@ int smbldap_search(struct smbldap_state *ldap_state,
if (ldap_state->last_rebind.tv_sec > 0) {
struct timeval tval;
- int tdiff = 0;
+ SMB_BIG_INT tdiff = 0;
int sleep_time = 0;
ZERO_STRUCT(tval);
+ GetTimeOfDay(&tval);
- gettimeofday(&tval,NULL);
-
- tdiff = 1000000 *(tval.tv_sec - ldap_state->last_rebind.tv_sec) +
- (tval.tv_usec - ldap_state->last_rebind.tv_usec);
+ tdiff = usec_time_diff(&tval, &ldap_state->last_rebind.tv_sec);
+ tdiff /= 1000; /* Convert to milliseconds. */
- sleep_time = ((1000*lp_ldap_replication_sleep())-tdiff)/1000;
+ sleep_time = lp_ldap_replication_sleep()-(int)tdiff;
+ sleep_time = MIN(sleep_time, MAX_LDAP_REPLICATION_SLEEP_TIME);
if (sleep_time > 0) {
/* we wait for the LDAP replication */
DEBUG(5,("smbldap_search: waiting %d milliseconds for LDAP replication.\n",sleep_time));
smb_msleep(sleep_time);
DEBUG(5,("smbldap_search: go on!\n"));
- ZERO_STRUCT(ldap_state->last_rebind);
}
+ ZERO_STRUCT(ldap_state->last_rebind);
}
if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) {
diff --git a/source/lib/snprintf.c b/source/lib/snprintf.c
index 5b0cfa1ab33..79de3c0ca5d 100644
--- a/source/lib/snprintf.c
+++ b/source/lib/snprintf.c
@@ -817,7 +817,7 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
(*currlen)++;
}
- int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
+ int smb_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{
return dopr(str, count, fmt, args);
}
diff --git a/source/lib/time.c b/source/lib/time.c
index faca2cba879..e63e0b29659 100644
--- a/source/lib/time.c
+++ b/source/lib/time.c
@@ -754,3 +754,9 @@ BOOL nt_time_is_zero(NTTIME *nt)
return True;
return False;
}
+
+SMB_BIG_INT usec_time_diff(struct timeval *larget, struct timeval *smallt)
+{
+ SMB_BIG_INT sec_diff = larget->tv_sec - smallt->tv_sec;
+ return (sec_diff * 1000000) + (SMB_BIG_INT)(larget->tv_usec - smallt->tv_usec);
+}
diff --git a/source/lib/username.c b/source/lib/username.c
index ac5530b5c71..317935d396f 100644
--- a/source/lib/username.c
+++ b/source/lib/username.c
@@ -306,7 +306,7 @@ static BOOL user_in_netgroup_list(const char *user, const char *ngname)
{
#ifdef HAVE_NETGROUP
static char *mydomain = NULL;
- fstring lowercase_user, lowercase_ngname;
+ fstring lowercase_user;
if (mydomain == NULL)
yp_get_default_domain(&mydomain);
@@ -318,25 +318,28 @@ static BOOL user_in_netgroup_list(const char *user, const char *ngname)
DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
user, mydomain, ngname));
- DEBUG(5,("innetgr is %s\n", innetgr(ngname, NULL, user, mydomain)
- ? "TRUE" : "FALSE"));
- if (innetgr(ngname, NULL, user, mydomain))
+ if (innetgr(ngname, NULL, user, mydomain)) {
+ DEBUG(5,("user_in_netgroup_list: Found\n"));
return (True);
+ } else {
- /*
- * Ok, innetgr is case sensitive. Try once more with lowercase
- * just in case. Attempt to fix #703. JRA.
- */
+ /*
+ * Ok, innetgr is case sensitive. Try once more with lowercase
+ * just in case. Attempt to fix #703. JRA.
+ */
- fstrcpy(lowercase_user, user);
- strlower_m(lowercase_user);
- fstrcpy(lowercase_ngname, ngname);
- strlower_m(lowercase_ngname);
+ fstrcpy(lowercase_user, user);
+ strlower_m(lowercase_user);
- if (innetgr(lowercase_ngname, NULL, lowercase_user, mydomain))
- return (True);
+ DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
+ lowercase_user, mydomain, ngname));
+ if (innetgr(ngname, NULL, lowercase_user, mydomain)) {
+ DEBUG(5,("user_in_netgroup_list: Found\n"));
+ return (True);
+ }
+ }
#endif /* HAVE_NETGROUP */
return False;
}
diff --git a/source/lib/util.c b/source/lib/util.c
index 9d7a2648c5b..554f5ee79da 100644
--- a/source/lib/util.c
+++ b/source/lib/util.c
@@ -1802,6 +1802,9 @@ void set_remote_arch(enum remote_arch_types type)
case RA_SAMBA:
fstrcpy(remote_arch,"Samba");
break;
+ case RA_CIFSFS:
+ fstrcpy(remote_arch,"CIFSFS");
+ break;
default:
ra_type = RA_UNKNOWN;
fstrcpy(remote_arch, "UNKNOWN");
@@ -2432,6 +2435,21 @@ BOOL unix_wild_match(const char *pattern, const char *string)
return unix_do_match(p2, s2) == 0;
}
+/**********************************************************************
+ Converts a name to a fully qalified domain name.
+***********************************************************************/
+
+void name_to_fqdn(fstring fqdn, const char *name)
+{
+ struct hostent *hp = sys_gethostbyname(name);
+ if ( hp && hp->h_name && *hp->h_name ) {
+ DEBUG(10,("name_to_fqdn: lookup for %s -> %s.\n", name, hp->h_name));
+ fstrcpy(fqdn,hp->h_name);
+ } else {
+ DEBUG(10,("name_to_fqdn: lookup for %s failed.\n", name));
+ fstrcpy(fqdn, name);
+ }
+}
#ifdef __INSURE__
diff --git a/source/lib/util_sock.c b/source/lib/util_sock.c
index b6bfdca5cf9..4b9881a4499 100644
--- a/source/lib/util_sock.c
+++ b/source/lib/util_sock.c
@@ -52,6 +52,23 @@ static char *get_socket_addr(int fd)
return addr_buf;
}
+static int get_socket_port(int fd)
+{
+ struct sockaddr sa;
+ struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+ socklen_t length = sizeof(sa);
+
+ if (fd == -1)
+ return -1;
+
+ if (getsockname(fd, &sa, &length) < 0) {
+ DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) ));
+ return -1;
+ }
+
+ return ntohs(sockin->sin_port);
+}
+
/****************************************************************************
Determine if a file descriptor is in fact a socket.
****************************************************************************/
@@ -837,6 +854,11 @@ char *client_socket_addr(void)
return get_socket_addr(client_fd);
}
+int client_socket_port(void)
+{
+ return get_socket_port(client_fd);
+}
+
struct in_addr *client_inaddr(struct sockaddr *sa)
{
struct sockaddr_in *sockin = (struct sockaddr_in *) (sa);
diff --git a/source/lib/util_str.c b/source/lib/util_str.c
index 65ef306ed17..7c5fa11c92d 100644
--- a/source/lib/util_str.c
+++ b/source/lib/util_str.c
@@ -62,7 +62,7 @@ BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
/* copy over the token */
pbuf = buff;
for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
- if (*s == '\"' || *s == '\'') {
+ if ( *s == '\"' ) {
quoted = !quoted;
} else {
len++;
diff --git a/source/libads/kerberos.c b/source/libads/kerberos.c
index e8bf4b08462..97b895a2418 100644
--- a/source/libads/kerberos.c
+++ b/source/libads/kerberos.c
@@ -79,9 +79,9 @@ int kerberos_kinit_password(const char *principal, const char *password, int tim
return code;
}
- if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, NULL,
+ if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, password,
kerb_prompter,
- password, 0, NULL, NULL))) {
+ NULL, 0, NULL, NULL))) {
krb5_free_principal(ctx, me);
krb5_free_context(ctx);
return code;
diff --git a/source/libads/kerberos_keytab.c b/source/libads/kerberos_keytab.c
new file mode 100644
index 00000000000..eec5f104fd9
--- /dev/null
+++ b/source/libads/kerberos_keytab.c
@@ -0,0 +1,554 @@
+/*
+ Unix SMB/CIFS implementation.
+ kerberos keytab utility library
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Remus Koos 2001
+ Copyright (C) Luke Howard 2003
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003
+ Copyright (C) Guenther Deschner 2003
+ Copyright (C) Rakesh Patel 2004
+ Copyright (C) Dan Perry 2004
+ Copyright (C) Jeremy Allison 2004
+
+ 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+/**********************************************************************
+ Adds a single service principal, i.e. 'host' to the system keytab
+***********************************************************************/
+
+int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
+{
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+ krb5_principal princ = NULL;
+ krb5_data password;
+ krb5_enctype *enctypes = NULL;
+ krb5_kvno kvno;
+
+ char *principal = NULL;
+ char *princ_s = NULL;
+ char *password_s = NULL;
+#ifndef MAX_KEYTAB_NAME_LEN
+#define MAX_KEYTAB_NAME_LEN 1100
+#endif
+ char keytab_name[MAX_KEYTAB_NAME_LEN]; /* This MAX_NAME_LEN is a constant defined in krb5.h */
+ fstring my_fqdn;
+ int i;
+ char *ktprinc = NULL;
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: could not krb5_init_context: %s\n",error_message(ret)));
+ return -1;
+ }
+#ifdef HAVE_WRFILE_KEYTAB /* MIT */
+ keytab_name[0] = 'W';
+ keytab_name[1] = 'R';
+ ret = krb5_kt_default_name(context, (char *) &keytab_name[2], MAX_KEYTAB_NAME_LEN - 4);
+#else /* Heimdal */
+ ret = krb5_kt_default_name(context, (char *) &keytab_name[0], MAX_KEYTAB_NAME_LEN - 2);
+#endif
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_default_name failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ DEBUG(2,("ads_keytab_add_entry: Using default system keytab: %s\n", (char *) &keytab_name));
+ ret = krb5_kt_resolve(context, (char *) &keytab_name, &keytab);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_resolve failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ /* retrieve the password */
+ if (!secrets_init()) {
+ DEBUG(1,("ads_keytab_add_entry: secrets_init failed\n"));
+ ret = -1;
+ goto out;
+ }
+ password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ if (!password_s) {
+ DEBUG(1,("ads_keytab_add_entry: failed to fetch machine password\n"));
+ ret = -1;
+ goto out;
+ }
+ password.data = password_s;
+ password.length = strlen(password_s);
+
+ /* Construct our principal */
+ name_to_fqdn(my_fqdn, global_myname());
+ strlower_m(my_fqdn);
+ asprintf(&princ_s, "%s/%s@%s", srvPrinc, my_fqdn, lp_realm());
+
+ ret = krb5_parse_name(context, princ_s, &princ);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret)));
+ goto out;
+ }
+
+ kvno = (krb5_kvno) ads_get_kvno(ads, global_myname());
+ if (kvno == -1) { /* -1 indicates failure, everything else is OK */
+ DEBUG(1,("ads_keytab_add_entry: ads_get_kvno failed to determine the system's kvno.\n"));
+ ret = -1;
+ goto out;
+ }
+
+ /* Seek and delete old keytab entries */
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret != KRB5_KT_END && ret != ENOENT ) {
+ DEBUG(3,("ads_keytab_add_entry: Will try to delete old keytab entries\n"));
+ while(!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
+ BOOL compare_ok = False;
+
+ ret = krb5_unparse_name(context, kt_entry.principal, &ktprinc);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_unparse_name failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ /*---------------------------------------------------------------------------
+ * Save the entries with kvno - 1. This is what microsoft does
+ * to allow people with existing sessions that have kvno - 1 to still
+ * work. Otherwise, when the password for the machine changes, all
+ * kerberizied sessions will 'break' until either the client reboots or
+ * the client's session key expires and they get a new session ticket
+ * with the new kvno.
+ */
+
+#ifdef HAVE_KRB5_KT_COMPARE
+ compare_ok = ((krb5_kt_compare(context, &kt_entry, princ, 0, 0) == True) && (kt_entry.vno != kvno - 1));
+#else
+ compare_ok = ((strcmp(ktprinc, princ_s) == 0) && (kt_entry.vno != kvno - 1));
+#endif
+ krb5_free_unparsed_name(context, ktprinc);
+ ktprinc = NULL;
+
+ if (compare_ok) {
+ DEBUG(3,("ads_keytab_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it.\n",
+ princ_s, kt_entry.vno));
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get() failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_start_seq failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+ ret = smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+ continue;
+ }
+
+ /* Not a match, just free this entry and continue. */
+ ret = smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: smb_krb5_kt_free_entry failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ }
+
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+ }
+
+ /* Ensure we don't double free. */
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ /* If we get here, we have deleted all the old entries with kvno's not equal to the current kvno-1. */
+
+ ret = get_kerberos_allowed_etypes(context,&enctypes);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: get_kerberos_allowed_etypes failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+
+ /* Now add keytab entries for all encryption types */
+ for (i = 0; enctypes[i]; i++) {
+ krb5_keyblock *keyp;
+
+#if !defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) && !defined(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK)
+#error krb5_keytab_entry has no key or keyblock member
+#endif
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY /* MIT */
+ keyp = &kt_entry.key;
+#endif
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
+ keyp = &kt_entry.keyblock;
+#endif
+ if (create_kerberos_key_from_string(context, princ, &password, keyp, enctypes[i])) {
+ continue;
+ }
+
+ kt_entry.principal = princ;
+ kt_entry.vno = kvno;
+
+ DEBUG(3,("ads_keytab_add_entry: adding keytab entry for (%s) with encryption type (%d) and version (%d)\n",
+ princ_s, enctypes[i], kt_entry.vno));
+ ret = krb5_kt_add_entry(context, keytab, &kt_entry);
+ krb5_free_keyblock_contents(context, keyp);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: adding entry to keytab failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ }
+
+ krb5_kt_close(context, keytab);
+ keytab = NULL; /* Done with keytab now. No double free. */
+
+ /* Update the LDAP with the SPN */
+ DEBUG(3,("ads_keytab_add_entry: Attempting to add/update '%s'\n", princ_s));
+ if (!ADS_ERR_OK(ads_add_service_principal_name(ads, global_myname(), srvPrinc))) {
+ DEBUG(1,("ads_keytab_add_entry: ads_add_service_principcal_name failed.\n"));
+ goto out;
+ }
+
+out:
+
+ SAFE_FREE(principal);
+ SAFE_FREE(password_s);
+ SAFE_FREE(princ_s);
+
+ {
+ krb5_keytab_entry zero_kt_entry;
+ ZERO_STRUCT(zero_kt_entry);
+ if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ }
+ }
+ if (princ) {
+ krb5_free_principal(context, princ);
+ }
+ if (enctypes) {
+ free_kerberos_etypes(context, enctypes);
+ }
+
+ {
+ krb5_kt_cursor zero_csr;
+ ZERO_STRUCT(zero_csr);
+ if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ }
+ if (keytab) {
+ krb5_kt_close(context, keytab);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+ return (int)ret;
+}
+
+/**********************************************************************
+ Flushes all entries from the system keytab.
+***********************************************************************/
+
+int ads_keytab_flush(ADS_STRUCT *ads)
+{
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+ krb5_kvno kvno;
+ char keytab_name[MAX_KEYTAB_NAME_LEN];
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: could not krb5_init_context: %s\n",error_message(ret)));
+ return ret;
+ }
+#ifdef HAVE_WRFILE_KEYTAB
+ keytab_name[0] = 'W';
+ keytab_name[1] = 'R';
+ ret = krb5_kt_default_name(context, (char *) &keytab_name[2], MAX_KEYTAB_NAME_LEN - 4);
+#else
+ ret = krb5_kt_default_name(context, (char *) &keytab_name[0], MAX_KEYTAB_NAME_LEN - 2);
+#endif
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_default failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ DEBUG(3,("ads_keytab_flush: Using default keytab: %s\n", (char *) &keytab_name));
+ ret = krb5_kt_resolve(context, (char *) &keytab_name, &keytab);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_default failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_resolve(context, (char *) &keytab_name, &keytab);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_default failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ kvno = (krb5_kvno) ads_get_kvno(ads, global_myname());
+ if (kvno == -1) { /* -1 indicates a failure */
+ DEBUG(1,("ads_keytab_flush: Error determining the system's kvno.\n"));
+ goto out;
+ }
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret != KRB5_KT_END && ret != ENOENT) {
+ while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_end_seq_get() failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_start_seq failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+ ret = smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+ }
+ }
+
+ /* Ensure we don't double free. */
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ if (!ADS_ERR_OK(ads_clear_service_principal_names(ads, global_myname()))) {
+ DEBUG(1,("ads_keytab_flush: Error while clearing service principal listings in LDAP.\n"));
+ goto out;
+ }
+
+out:
+
+ {
+ krb5_keytab_entry zero_kt_entry;
+ ZERO_STRUCT(zero_kt_entry);
+ if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ }
+ }
+ {
+ krb5_kt_cursor zero_csr;
+ ZERO_STRUCT(zero_csr);
+ if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ }
+ if (keytab) {
+ krb5_kt_close(context, keytab);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+ return ret;
+}
+
+/**********************************************************************
+ Adds all the required service principals to the system keytab.
+***********************************************************************/
+
+int ads_keytab_create_default(ADS_STRUCT *ads)
+{
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+ krb5_kvno kvno;
+ int i, found = 0;
+ char **oldEntries = NULL;
+
+ ret = ads_keytab_add_entry(ads, "host");
+ if (ret) {
+ DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'host'.\n"));
+ return ret;
+ }
+ ret = ads_keytab_add_entry(ads, "cifs");
+ if (ret) {
+ DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'cifs'.\n"));
+ return ret;
+ }
+
+ kvno = (krb5_kvno) ads_get_kvno(ads, global_myname());
+ if (kvno == -1) {
+ DEBUG(1,("ads_keytab_create_default: ads_get_kvno failed to determine the system's kvno.\n"));
+ return -1;
+ }
+
+ DEBUG(3,("ads_keytab_create_default: Searching for keytab entries to preserve and update.\n"));
+ /* Now loop through the keytab and update any other existing entries... */
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ initialize_krb5_error_table();
+ ret = krb5_init_context(&context);
+ if (ret) {
+ DEBUG(1,("ads_keytab_create_default: could not krb5_init_context: %s\n",error_message(ret)));
+ return ret;
+ }
+ ret = krb5_kt_default(context, &keytab);
+ if (ret) {
+ DEBUG(1,("ads_keytab_create_default: krb5_kt_default failed (%s)\n",error_message(ret)));
+ goto done;
+ }
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret != KRB5_KT_END && ret != ENOENT ) {
+ while ((ret = krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) == 0) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ found++;
+ }
+ }
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+
+ /*
+ * Hmmm. There is no "rewind" function for the keytab. This means we have a race condition
+ * where someone else could add entries after we've counted them. Re-open asap to minimise
+ * the race. JRA.
+ */
+
+ DEBUG(3, ("ads_keytab_create_default: Found %d entries in the keytab.\n", found));
+ if (!found) {
+ goto done;
+ }
+ oldEntries = (char **) malloc(found * sizeof(char *));
+ if (!oldEntries) {
+ DEBUG(1,("ads_keytab_create_default: Failed to allocate space to store the old keytab entries (malloc failed?).\n"));
+ ret = -1;
+ goto done;
+ }
+ memset(oldEntries, '\0', found * sizeof(char *));
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret != KRB5_KT_END && ret != ENOENT ) {
+ while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
+ if (kt_entry.vno != kvno) {
+ char *ktprinc = NULL;
+ char *p;
+
+ /* This returns a malloc'ed string in ktprinc. */
+ ret = krb5_unparse_name(context, kt_entry.principal, &ktprinc);
+ if (ret) {
+ DEBUG(1,("krb5_unparse_name failed (%s)\n", error_message(ret)));
+ goto done;
+ }
+ /*
+ * From looking at the krb5 source they don't seem to take locale
+ * or mb strings into account. Maybe this is because they assume utf8 ?
+ * In this case we may need to convert from utf8 to mb charset here ? JRA.
+ */
+ p = strchr_m(ktprinc, '/');
+ if (p) {
+ *p = '\0';
+ }
+ for (i = 0; i < found; i++) {
+ if (!oldEntries[i]) {
+ oldEntries[i] = ktprinc;
+ break;
+ }
+ if (!strcmp(oldEntries[i], ktprinc)) {
+ krb5_free_unparsed_name(context, ktprinc);
+ break;
+ }
+ }
+ if (i == found) {
+ krb5_free_unparsed_name(context, ktprinc);
+ }
+ }
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ }
+ ret = 0;
+ for (i = 0; oldEntries[i]; i++) {
+ ret |= ads_keytab_add_entry(ads, oldEntries[i]);
+ krb5_free_unparsed_name(context, oldEntries[i]);
+ }
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ ZERO_STRUCT(cursor);
+
+done:
+
+ SAFE_FREE(oldEntries);
+
+ {
+ krb5_keytab_entry zero_kt_entry;
+ ZERO_STRUCT(zero_kt_entry);
+ if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ }
+ }
+ {
+ krb5_kt_cursor zero_csr;
+ ZERO_STRUCT(zero_csr);
+ if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ }
+ if (keytab) {
+ krb5_kt_close(context, keytab);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+ return ret;
+}
+#endif /* HAVE_KRB5 */
diff --git a/source/libads/kerberos_verify.c b/source/libads/kerberos_verify.c
index 47559c1abb7..bdac22a9022 100644
--- a/source/libads/kerberos_verify.c
+++ b/source/libads/kerberos_verify.c
@@ -26,10 +26,182 @@
#ifdef HAVE_KRB5
-/*
- verify an incoming ticket and parse out the principal name and
- authorization_data if available
-*/
+/**********************************************************************************
+ Try to verify a ticket using the system keytab... the system keytab has kvno -1 entries, so
+ it's more like what microsoft does... see comment in utils/net_ads.c in the
+ ads_keytab_add_entry function for details.
+***********************************************************************************/
+
+static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context auth_context,
+ const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt)
+{
+ krb5_error_code ret = 0;
+ BOOL auth_ok = False;
+
+ krb5_keytab keytab = NULL;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+ char *princ_name = NULL;
+
+ ZERO_STRUCT(kt_entry);
+ ZERO_STRUCT(cursor);
+
+ ret = krb5_kt_default(context, &keytab);
+ if (ret) {
+ DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_default failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
+ ret = krb5_unparse_name(context, kt_entry.principal, &princ_name);
+ if (ret) {
+ DEBUG(1, ("ads_keytab_verify_ticket: krb5_unparse_name failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ /* Look for a CIFS ticket */
+ if (!StrnCaseCmp(princ_name, "cifs/", 5)) {
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK
+ krb5_auth_con_setuseruserkey(context, auth_context, &kt_entry.keyblock);
+#else
+ krb5_auth_con_setuseruserkey(context, auth_context, &kt_entry.key);
+#endif
+
+ p_packet->length = ticket->length;
+ p_packet->data = (krb5_pointer)ticket->data;
+
+ if (!(ret = krb5_rd_req(context, &auth_context, p_packet, NULL, NULL, NULL, pp_tkt))) {
+ unsigned int keytype;
+ krb5_free_unparsed_name(context, princ_name);
+ princ_name = NULL;
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK
+ keytype = (unsigned int) kt_entry.keyblock.keytype;
+#else
+ keytype = (unsigned int) kt_entry.key.enctype;
+#endif
+ DEBUG(10,("ads_keytab_verify_ticket: enc type [%u] decrypted message !\n",
+ keytype));
+ auth_ok = True;
+ break;
+ }
+ }
+ krb5_free_unparsed_name(context, princ_name);
+ princ_name = NULL;
+ }
+ if (ret && ret != KRB5_KT_END) {
+ /* This failed because something went wrong, not because the keytab file was empty. */
+ DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_next_entry failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ out:
+
+ if (princ_name) {
+ krb5_free_unparsed_name(context, princ_name);
+ }
+ {
+ krb5_kt_cursor zero_csr;
+ ZERO_STRUCT(zero_csr);
+ if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ }
+ if (keytab) {
+ krb5_kt_close(context, keytab);
+ }
+
+ return auth_ok;
+}
+
+/**********************************************************************************
+ Try to verify a ticket using the secrets.tdb.
+***********************************************************************************/
+
+static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context auth_context,
+ krb5_principal host_princ,
+ const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt)
+{
+ krb5_error_code ret = 0;
+ BOOL auth_ok = False;
+ char *password_s = NULL;
+ krb5_data password;
+ krb5_enctype *enctypes = NULL;
+ int i;
+
+ if (!secrets_init()) {
+ DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n"));
+ return False;
+ }
+
+ password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ if (!password_s) {
+ DEBUG(1,("ads_secrets_verify_ticket: failed to fetch machine password\n"));
+ return False;
+ }
+
+ password.data = password_s;
+ password.length = strlen(password_s);
+
+ /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */
+
+ if ((ret = get_kerberos_allowed_etypes(context, &enctypes))) {
+ DEBUG(1,("ads_secrets_verify_ticket: krb5_get_permitted_enctypes failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+
+ p_packet->length = ticket->length;
+ p_packet->data = (krb5_pointer)ticket->data;
+
+ /* We need to setup a auth context with each possible encoding type in turn. */
+ for (i=0;enctypes[i];i++) {
+ krb5_keyblock *key = NULL;
+
+ if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) {
+ goto out;
+ }
+
+ if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i])) {
+ SAFE_FREE(key);
+ continue;
+ }
+
+ krb5_auth_con_setuseruserkey(context, auth_context, key);
+
+ krb5_free_keyblock(context, key);
+
+ if (!(ret = krb5_rd_req(context, &auth_context, p_packet,
+ NULL,
+ NULL, NULL, pp_tkt))) {
+ DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n",
+ (unsigned int)enctypes[i] ));
+ auth_ok = True;
+ break;
+ }
+
+ DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10,
+ ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n",
+ (unsigned int)enctypes[i], error_message(ret)));
+ }
+
+ out:
+
+ free_kerberos_etypes(context, enctypes);
+ SAFE_FREE(password_s);
+
+ return auth_ok;
+}
+
+/**********************************************************************************
+ Verify an incoming ticket and parse out the principal name and
+ authorization_data if available.
+***********************************************************************************/
+
NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
char **principal, DATA_BLOB *auth_data,
DATA_BLOB *ap_rep,
@@ -41,43 +213,21 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
krb5_data packet;
krb5_ticket *tkt = NULL;
krb5_rcache rcache = NULL;
- int ret, i;
- krb5_keyblock *key = NULL;
+ int ret;
- krb5_principal host_princ;
+ krb5_principal host_princ = NULL;
char *host_princ_s = NULL;
- BOOL free_host_princ = False;
BOOL got_replay_mutex = False;
fstring myname;
- char *password_s = NULL;
- krb5_data password;
- krb5_enctype *enctypes = NULL;
-#if 0
- krb5_address local_addr;
- krb5_address remote_addr;
-#endif
BOOL auth_ok = False;
ZERO_STRUCT(packet);
- ZERO_STRUCT(password);
ZERO_STRUCTP(auth_data);
ZERO_STRUCTP(ap_rep);
+ ZERO_STRUCTP(session_key);
- if (!secrets_init()) {
- DEBUG(1,("ads_verify_ticket: secrets_init failed\n"));
- return NT_STATUS_LOGON_FAILURE;
- }
-
- password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
- if (!password_s) {
- DEBUG(1,("ads_verify_ticket: failed to fetch machine password\n"));
- return NT_STATUS_LOGON_FAILURE;
- }
-
- password.data = password_s;
- password.length = strlen(password_s);
-
+ initialize_krb5_error_table();
ret = krb5_init_context(&context);
if (ret) {
DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret)));
@@ -87,7 +237,6 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
ret = krb5_set_default_realm(context, realm);
if (ret) {
DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret)));
- sret = NT_STATUS_LOGON_FAILURE;
goto out;
}
@@ -98,22 +247,29 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
ret = krb5_auth_con_init(context, &auth_context);
if (ret) {
DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret)));
- sret = NT_STATUS_LOGON_FAILURE;
goto out;
}
- fstrcpy(myname, global_myname());
+ name_to_fqdn(myname, global_myname());
strlower_m(myname);
- asprintf(&host_princ_s, "HOST/%s@%s", myname, lp_realm());
+ asprintf(&host_princ_s, "host/%s@%s", myname, lp_realm());
ret = krb5_parse_name(context, host_princ_s, &host_princ);
if (ret) {
DEBUG(1,("ads_verify_ticket: krb5_parse_name(%s) failed (%s)\n",
host_princ_s, error_message(ret)));
- sret = NT_STATUS_LOGON_FAILURE;
goto out;
}
- free_host_princ = True;
+
+ /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5
+ * code surrounding the replay cache... */
+
+ if (!grab_server_mutex("replay cache mutex")) {
+ DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n"));
+ goto out;
+ }
+
+ got_replay_mutex = True;
/*
* JRA. We must set the rcache here. This will prevent replay attacks.
@@ -122,67 +278,21 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
ret = krb5_get_server_rcache(context, krb5_princ_component(context, host_princ, 0), &rcache);
if (ret) {
DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache failed (%s)\n", error_message(ret)));
- sret = NT_STATUS_LOGON_FAILURE;
goto out;
}
ret = krb5_auth_con_setrcache(context, auth_context, rcache);
if (ret) {
DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache failed (%s)\n", error_message(ret)));
- sret = NT_STATUS_LOGON_FAILURE;
goto out;
}
- /* CIFS doesn't use addresses in tickets. This would breat NAT. JRA */
-
- if ((ret = get_kerberos_allowed_etypes(context, &enctypes))) {
- DEBUG(1,("ads_verify_ticket: krb5_get_permitted_enctypes failed (%s)\n",
- error_message(ret)));
- sret = NT_STATUS_LOGON_FAILURE;
- goto out;
+ if (lp_use_kerberos_keytab()) {
+ auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &packet, &tkt);
}
-
- /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5
- * code surrounding the replay cache... */
-
- if (!grab_server_mutex("replay cache mutex")) {
- DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n"));
- sret = NT_STATUS_LOGON_FAILURE;
- goto out;
- }
-
- got_replay_mutex = True;
-
- /* We need to setup a auth context with each possible encoding type in turn. */
- for (i=0;enctypes[i];i++) {
- if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) {
- sret = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i])) {
- continue;
- }
-
- krb5_auth_con_setuseruserkey(context, auth_context, key);
-
- krb5_free_keyblock(context, key);
-
- packet.length = ticket->length;
- packet.data = (krb5_pointer)ticket->data;
-
- if (!(ret = krb5_rd_req(context, &auth_context, &packet,
- NULL,
- NULL, NULL, &tkt))) {
- DEBUG(10,("ads_verify_ticket: enc type [%u] decrypted message !\n",
- (unsigned int)enctypes[i] ));
- auth_ok = True;
- break;
- }
-
- DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10,
- ("ads_verify_ticket: enc type [%u] failed to decrypt with error %s\n",
- (unsigned int)enctypes[i], error_message(ret)));
+ if (!auth_ok) {
+ auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
+ ticket, &packet, &tkt);
}
release_server_mutex();
@@ -191,7 +301,6 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
if (!auth_ok) {
DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n",
error_message(ret)));
- sret = NT_STATUS_LOGON_FAILURE;
goto out;
}
@@ -199,12 +308,12 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
if (ret) {
DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
error_message(ret)));
- sret = NT_STATUS_LOGON_FAILURE;
goto out;
}
*ap_rep = data_blob(packet.data, packet.length);
- free(packet.data);
+ SAFE_FREE(packet.data);
+ packet.length = 0;
get_krb5_smb_session_key(context, auth_context, session_key, True);
dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length);
@@ -241,29 +350,35 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
out:
- if (got_replay_mutex)
+ if (got_replay_mutex) {
release_server_mutex();
+ }
- if (!NT_STATUS_IS_OK(sret))
+ if (!NT_STATUS_IS_OK(sret)) {
data_blob_free(auth_data);
+ }
- if (!NT_STATUS_IS_OK(sret))
+ if (!NT_STATUS_IS_OK(sret)) {
data_blob_free(ap_rep);
+ }
- if (free_host_princ)
+ if (host_princ) {
krb5_free_principal(context, host_princ);
+ }
- if (tkt != NULL)
+ if (tkt != NULL) {
krb5_free_ticket(context, tkt);
- free_kerberos_etypes(context, enctypes);
- SAFE_FREE(password_s);
+ }
+
SAFE_FREE(host_princ_s);
- if (auth_context)
+ if (auth_context) {
krb5_auth_con_free(context, auth_context);
+ }
- if (context)
+ if (context) {
krb5_free_context(context);
+ }
return sret;
}
diff --git a/source/libads/krb5_setpw.c b/source/libads/krb5_setpw.c
index 5c859f0e995..84595212e6c 100644
--- a/source/libads/krb5_setpw.c
+++ b/source/libads/krb5_setpw.c
@@ -56,7 +56,7 @@ static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password)
princ = strdup(principal);
- if ((c = strchr(princ, '/')) == NULL) {
+ if ((c = strchr_m(princ, '/')) == NULL) {
c = princ;
} else {
*c = '\0';
@@ -66,7 +66,7 @@ static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password)
princ_part2 = c;
- if ((c = strchr(c, '@')) != NULL) {
+ if ((c = strchr_m(c, '@')) != NULL) {
*c = '\0';
c++;
realm = c;
@@ -462,14 +462,21 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ,
{
ADS_STATUS aret;
- krb5_error_code ret;
+ krb5_error_code ret = 0;
krb5_context context = NULL;
- krb5_principal principal;
- char *princ_name;
- char *realm;
- krb5_creds creds, *credsp;
+ krb5_principal principal = NULL;
+ char *princ_name = NULL;
+ char *realm = NULL;
+ krb5_creds creds, *credsp = NULL;
+#if KRB5_PRINC_REALM_RETURNS_REALM
+ krb5_realm orig_realm;
+#else
+ krb5_data orig_realm;
+#endif
krb5_ccache ccache = NULL;
+ ZERO_STRUCT(creds);
+
ret = krb5_init_context(&context);
if (ret) {
DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
@@ -487,14 +494,19 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ,
return ADS_ERROR_KRB5(ret);
}
- ZERO_STRUCT(creds);
-
- realm = strchr(princ, '@');
+ realm = strchr_m(princ, '@');
+ if (!realm) {
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+ DEBUG(1,("Failed to get realm\n"));
+ return ADS_ERROR_KRB5(-1);
+ }
realm++;
asprintf(&princ_name, "kadmin/changepw@%s", realm);
ret = krb5_parse_name(context, princ_name, &creds.server);
if (ret) {
+ krb5_cc_close(context, ccache);
krb5_free_context(context);
DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret)));
return ADS_ERROR_KRB5(ret);
@@ -504,16 +516,23 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ,
/* parse the principal we got as a function argument */
ret = krb5_parse_name(context, princ, &principal);
if (ret) {
+ krb5_cc_close(context, ccache);
+ krb5_free_principal(context, creds.server);
krb5_free_context(context);
DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret)));
return ADS_ERROR_KRB5(ret);
}
- krb5_princ_set_realm(context, creds.server,
- krb5_princ_realm(context, principal));
+ /* The creds.server principal takes ownership of this memory.
+ Remember to set back to original value before freeing. */
+ orig_realm = *krb5_princ_realm(context, creds.server);
+ krb5_princ_set_realm(context, creds.server, krb5_princ_realm(context, principal));
ret = krb5_cc_get_principal(context, ccache, &creds.client);
if (ret) {
+ krb5_cc_close(context, ccache);
+ krb5_princ_set_realm(context, creds.server, &orig_realm);
+ krb5_free_principal(context, creds.server);
krb5_free_principal(context, principal);
krb5_free_context(context);
DEBUG(1,("Failed to get principal from ccache (%s)\n",
@@ -523,7 +542,10 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ,
ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
if (ret) {
+ krb5_cc_close(context, ccache);
krb5_free_principal(context, creds.client);
+ krb5_princ_set_realm(context, creds.server, &orig_realm);
+ krb5_free_principal(context, creds.server);
krb5_free_principal(context, principal);
krb5_free_context(context);
DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
@@ -538,7 +560,10 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ,
krb5_free_creds(context, credsp);
krb5_free_principal(context, creds.client);
+ krb5_princ_set_realm(context, creds.server, &orig_realm);
+ krb5_free_principal(context, creds.server);
krb5_free_principal(context, principal);
+ krb5_cc_close(context, ccache);
krb5_free_context(context);
return aret;
diff --git a/source/libads/ldap.c b/source/libads/ldap.c
index e018eeb2da9..78ea9f1497d 100644
--- a/source/libads/ldap.c
+++ b/source/libads/ldap.c
@@ -37,6 +37,35 @@
* codepoints in UTF-8). This may have to change at some point
**/
+static SIG_ATOMIC_T gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+ LDAP *ldap_open_with_timeout(const char *server, int port, unsigned int to)
+{
+ LDAP *ldp = NULL;
+
+ /* Setup timeout */
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(to);
+ /* End setup timeout. */
+
+ ldp = ldap_open(server, port);
+
+ /* Teardown timeout. */
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
+ alarm(0);
+
+ return ldp;
+}
/*
try a connection to a given ldap server, returning True and setting the servers IP
@@ -58,7 +87,7 @@ static BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
/* this copes with inet_ntoa brokenness */
srv = strdup(server);
- ads->ld = ldap_open(srv, port);
+ ads->ld = ldap_open_with_timeout(srv, port, lp_ldap_timeout());
if (!ads->ld) {
free(srv);
return False;
@@ -226,11 +255,10 @@ got_connection:
ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
if (!ads->auth.user_name) {
- /* by default use the machine account */
- fstring myname;
- fstrcpy(myname, global_myname());
- strlower_m(myname);
- asprintf(&ads->auth.user_name, "HOST/%s", myname);
+ /* have to use the userPrincipalName value here and
+ not servicePrincipalName; found by Guenther Deschner @ Sernet */
+
+ asprintf(&ads->auth.user_name, "host/%s", global_myname() );
}
if (!ads->auth.realm) {
@@ -730,7 +758,7 @@ char *ads_get_dn(ADS_STRUCT *ads, void *msg)
* @param host Hostname to search for
* @return status of search
**/
-ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host)
+ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *machine)
{
ADS_STATUS status;
char *expr;
@@ -738,13 +766,13 @@ ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host)
/* the easiest way to find a machine account anywhere in the tree
is to look for hostname$ */
- if (asprintf(&expr, "(samAccountName=%s$)", host) == -1) {
+ if (asprintf(&expr, "(samAccountName=%s$)", machine) == -1) {
DEBUG(1, ("asprintf failed!\n"));
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
status = ads_search(ads, res, expr, attrs);
- free(expr);
+ SAFE_FREE(expr);
return status;
}
@@ -979,18 +1007,251 @@ char *ads_ou_string(const char *org_unit)
return ads_build_path(org_unit, "\\/", "ou=", 1);
}
+/**
+ * Adds (appends) an item to an attribute array, rather then
+ * replacing the whole list
+ * @param ctx An initialized TALLOC_CTX
+ * @param mods An initialized ADS_MODLIST
+ * @param name name of the ldap attribute to append to
+ * @param vals an array of values to add
+ * @return status of addition
+ **/
+ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
+ const char *name, const char **vals)
+{
+ return ads_modlist_add(ctx, mods, LDAP_MOD_ADD, name, (const void **) vals);
+}
-/*
- add a machine account to the ADS server
-*/
-static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
+/**
+ * Determines the computer account's current KVNO via an LDAP lookup
+ * @param ads An initialized ADS_STRUCT
+ * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
+ * @return the kvno for the computer account, or -1 in case of a failure.
+ **/
+
+uint32 ads_get_kvno(ADS_STRUCT *ads, const char *machine_name)
+{
+ LDAPMessage *res = NULL;
+ uint32 kvno = (uint32)-1; /* -1 indicates a failure */
+ char *filter;
+ const char *attrs[] = {"msDS-KeyVersionNumber", NULL};
+ char *dn_string = NULL;
+ ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS);
+
+ DEBUG(5,("ads_get_kvno: Searching for host %s\n", machine_name));
+ if (asprintf(&filter, "(samAccountName=%s$)", machine_name) == -1) {
+ return kvno;
+ }
+ ret = ads_search(ads, (void**) &res, filter, attrs);
+ SAFE_FREE(filter);
+ if (!ADS_ERR_OK(ret) && ads_count_replies(ads, res)) {
+ DEBUG(1,("ads_get_kvno: Computer Account For %s not found.\n", machine_name));
+ ads_msgfree(ads, res);
+ return kvno;
+ }
+
+ dn_string = ads_get_dn(ads, res);
+ if (!dn_string) {
+ DEBUG(0,("ads_get_kvno: out of memory.\n"));
+ ads_msgfree(ads, res);
+ return kvno;
+ }
+ DEBUG(5,("ads_get_kvno: Using: %s\n", dn_string));
+ ads_memfree(ads, dn_string);
+
+ /* ---------------------------------------------------------
+ * 0 is returned as a default KVNO from this point on...
+ * This is done because Windows 2000 does not support key
+ * version numbers. Chances are that a failure in the next
+ * step is simply due to Windows 2000 being used for a
+ * domain controller. */
+ kvno = 0;
+
+ if (!ads_pull_uint32(ads, res, "msDS-KeyVersionNumber", &kvno)) {
+ DEBUG(3,("ads_get_kvno: Error Determining KVNO!\n"));
+ DEBUG(3,("ads_get_kvno: Windows 2000 does not support KVNO's, so this may be normal.\n"));
+ ads_msgfree(ads, res);
+ return kvno;
+ }
+
+ /* Success */
+ DEBUG(5,("ads_get_kvno: Looked Up KVNO of: %d\n", kvno));
+ ads_msgfree(ads, res);
+ return kvno;
+}
+
+/**
+ * This clears out all registered spn's for a given hostname
+ * @param ads An initilaized ADS_STRUCT
+ * @param machine_name the NetBIOS name of the computer.
+ * @return 0 upon success, non-zero otherwise.
+ **/
+
+ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machine_name)
+{
+ TALLOC_CTX *ctx;
+ LDAPMessage *res = NULL;
+ ADS_MODLIST mods;
+ const char *servicePrincipalName[1] = {NULL};
+ ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS);
+ char *dn_string = NULL;
+
+ ret = ads_find_machine_acct(ads, (void **)&res, machine_name);
+ if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) {
+ DEBUG(5,("ads_clear_service_principal_names: WARNING: Host Account for %s not found... skipping operation.\n", machine_name));
+ DEBUG(5,("ads_clear_service_principal_names: WARNING: Service Principals for %s have NOT been cleared.\n", machine_name));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ DEBUG(5,("ads_clear_service_principal_names: Host account for %s found\n", machine_name));
+ ctx = talloc_init("ads_clear_service_principal_names");
+ if (!ctx) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ if (!(mods = ads_init_mods(ctx))) {
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ ret = ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
+ if (!ADS_ERR_OK(ret)) {
+ DEBUG(1,("ads_clear_service_principal_names: Error creating strlist.\n"));
+ ads_msgfree(ads, res);
+ talloc_destroy(ctx);
+ return ret;
+ }
+ dn_string = ads_get_dn(ads, res);
+ if (!dn_string) {
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ ret = ads_gen_mod(ads, dn_string, mods);
+ ads_memfree(ads,dn_string);
+ if (!ADS_ERR_OK(ret)) {
+ DEBUG(1,("ads_clear_service_principal_names: Error: Updating Service Principals for machine %s in LDAP\n",
+ machine_name));
+ ads_msgfree(ads, res);
+ talloc_destroy(ctx);
+ return ret;
+ }
+
+ ads_msgfree(ads, res);
+ talloc_destroy(ctx);
+ return ret;
+}
+
+/**
+ * This adds a service principal name to an existing computer account
+ * (found by hostname) in AD.
+ * @param ads An initialized ADS_STRUCT
+ * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
+ * @param spn A string of the service principal to add, i.e. 'host'
+ * @return 0 upon sucess, or non-zero if a failure occurs
+ **/
+
+ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_name, const char *spn)
+{
+ ADS_STATUS ret;
+ TALLOC_CTX *ctx;
+ LDAPMessage *res = NULL;
+ char *host_spn, *host_upn, *psp1, *psp2;
+ ADS_MODLIST mods;
+ fstring my_fqdn;
+ char *dn_string = NULL;
+ const char *servicePrincipalName[3] = {NULL, NULL, NULL};
+
+ ret = ads_find_machine_acct(ads, (void **)&res, machine_name);
+ if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) {
+ DEBUG(1,("ads_add_service_principal_name: WARNING: Host Account for %s not found... skipping operation.\n",
+ machine_name));
+ DEBUG(1,("ads_add_service_principal_name: WARNING: Service Principal '%s/%s@%s' has NOT been added.\n",
+ spn, machine_name, ads->config.realm));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ DEBUG(1,("ads_add_service_principal_name: Host account for %s found\n", machine_name));
+ if (!(ctx = talloc_init("ads_add_service_principal_name"))) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ name_to_fqdn(my_fqdn, machine_name);
+ if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", my_fqdn))) {
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+ if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->config.realm))) {
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ /* Add the extra principal */
+ psp1 = talloc_asprintf(ctx, "%s/%s", spn, machine_name);
+ strupper_m(psp1);
+ strlower_m(&psp1[strlen(spn)]);
+ DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", psp1, machine_name));
+ servicePrincipalName[0] = psp1;
+ psp2 = talloc_asprintf(ctx, "%s/%s.%s", spn, machine_name, ads->config.realm);
+ strupper_m(psp2);
+ strlower_m(&psp2[strlen(spn)]);
+ DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", psp2, machine_name));
+ servicePrincipalName[1] = psp2;
+
+ if (!(mods = ads_init_mods(ctx))) {
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ ret = ads_add_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
+ if (!ADS_ERR_OK(ret)) {
+ DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n"));
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ret;
+ }
+ dn_string = ads_get_dn(ads, res);
+ if (!dn_string) {
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+ ret = ads_gen_mod(ads, dn_string, mods);
+ ads_memfree(ads,dn_string);
+ if (!ADS_ERR_OK(ret)) {
+ DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n"));
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ret;
+ }
+
+ talloc_destroy(ctx);
+ ads_msgfree(ads, res);
+ return ret;
+}
+
+/**
+ * adds a machine account to the ADS server
+ * @param ads An intialized ADS_STRUCT
+ * @param machine_name - the NetBIOS machine name of this account.
+ * @param account_type A number indicating the type of account to create
+ * @param org_unit The LDAP path in which to place this account
+ * @return 0 upon success, or non-zero otherwise
+**/
+
+static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *machine_name,
uint32 account_type,
const char *org_unit)
{
ADS_STATUS ret, status;
char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr;
- char *ou_str;
TALLOC_CTX *ctx;
ADS_MODLIST mods;
const char *objectClass[] = {"top", "person", "organizationalPerson",
@@ -999,87 +1260,106 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
char *psp, *psp2;
unsigned acct_control;
unsigned exists=0;
- LDAPMessage *res;
+ fstring my_fqdn;
+ LDAPMessage *res = NULL;
- status = ads_find_machine_acct(ads, (void **)&res, hostname);
+ if (!(ctx = talloc_init("ads_add_machine_acct")))
+ return ADS_ERROR(LDAP_NO_MEMORY);
+
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+
+ name_to_fqdn(my_fqdn, machine_name);
+
+ status = ads_find_machine_acct(ads, (void **)&res, machine_name);
if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
- DEBUG(0, ("Host account for %s already exists - modifying old account\n", hostname));
+ char *dn_string = ads_get_dn(ads, res);
+ if (!dn_string) {
+ DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
+ goto done;
+ }
+ new_dn = talloc_strdup(ctx, dn_string);
+ ads_memfree(ads,dn_string);
+ DEBUG(0, ("ads_add_machine_acct: Host account for %s already exists - modifying old account\n",
+ machine_name));
exists=1;
- }
+ } else {
+ char *ou_str = ads_ou_string(org_unit);
+ if (!ou_str) {
+ DEBUG(1, ("ads_add_machine_acct: ads_ou_string returned NULL (malloc failure?)\n"));
+ goto done;
+ }
+ new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", machine_name, ou_str,
+ ads->config.bind_path);
- if (!(ctx = talloc_init("machine_account")))
- return ADS_ERROR(LDAP_NO_MEMORY);
+ SAFE_FREE(ou_str);
+ }
- ret = ADS_ERROR(LDAP_NO_MEMORY);
+ if (!new_dn) {
+ goto done;
+ }
- if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", hostname)))
+ if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", machine_name)))
goto done;
if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->config.realm)))
goto done;
- ou_str = ads_ou_string(org_unit);
- if (!ou_str) {
- DEBUG(1, ("ads_ou_string returned NULL (malloc failure?)\n"));
- goto done;
- }
- new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", hostname, ou_str,
- ads->config.bind_path);
- servicePrincipalName[0] = talloc_asprintf(ctx, "HOST/%s", hostname);
+ servicePrincipalName[0] = talloc_asprintf(ctx, "HOST/%s", machine_name);
psp = talloc_asprintf(ctx, "HOST/%s.%s",
- hostname,
- ads->config.realm);
+ machine_name,
+ ads->config.realm);
strlower_m(&psp[5]);
servicePrincipalName[1] = psp;
- servicePrincipalName[2] = talloc_asprintf(ctx, "CIFS/%s", hostname);
+ servicePrincipalName[2] = talloc_asprintf(ctx, "CIFS/%s", machine_name);
psp2 = talloc_asprintf(ctx, "CIFS/%s.%s",
- hostname,
+ machine_name,
ads->config.realm);
strlower_m(&psp2[5]);
servicePrincipalName[3] = psp2;
- free(ou_str);
- if (!new_dn)
- goto done;
-
- if (!(samAccountName = talloc_asprintf(ctx, "%s$", hostname)))
+ if (!(samAccountName = talloc_asprintf(ctx, "%s$", machine_name))) {
goto done;
+ }
acct_control = account_type | UF_DONT_EXPIRE_PASSWD;
#ifndef ENCTYPE_ARCFOUR_HMAC
acct_control |= UF_USE_DES_KEY_ONLY;
#endif
- if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control)))
+ if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control))) {
goto done;
+ }
- if (!(mods = ads_init_mods(ctx)))
+ if (!(mods = ads_init_mods(ctx))) {
goto done;
+ }
if (!exists) {
- ads_mod_str(ctx, &mods, "cn", hostname);
+ ads_mod_str(ctx, &mods, "cn", machine_name);
ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
}
- ads_mod_str(ctx, &mods, "dNSHostName", hostname);
+ ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
ads_mod_str(ctx, &mods, "userPrincipalName", host_upn);
ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
ads_mod_str(ctx, &mods, "operatingSystem", "Samba");
ads_mod_str(ctx, &mods, "operatingSystemVersion", SAMBA_VERSION_STRING);
- if (!exists)
+ if (!exists) {
ret = ads_gen_add(ads, new_dn, mods);
- else
+ } else {
ret = ads_gen_mod(ads, new_dn, mods);
+ }
- if (!ADS_ERR_OK(ret))
+ if (!ADS_ERR_OK(ret)) {
goto done;
+ }
/* Do not fail if we can't set security descriptor
* it shouldn't be mandatory and probably we just
* don't have enough rights to do it.
*/
if (!exists) {
- status = ads_set_machine_sd(ads, hostname, new_dn);
+ status = ads_set_machine_sd(ads, machine_name, new_dn);
if (!ADS_ERR_OK(status)) {
DEBUG(0, ("Warning: ads_set_machine_sd: %s\n",
@@ -1087,6 +1367,7 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
}
}
done:
+ ads_msgfree(ads, res);
talloc_destroy(ctx);
return ret;
}
@@ -1303,47 +1584,50 @@ int ads_count_replies(ADS_STRUCT *ads, void *res)
* Join a machine to a realm
* Creates the machine account and sets the machine password
* @param ads connection to ads server
- * @param hostname name of host to add
+ * @param machine name of host to add
* @param org_unit Organizational unit to place machine in
* @return status of join
**/
-ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname,
+ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name,
uint32 account_type, const char *org_unit)
{
ADS_STATUS status;
- LDAPMessage *res;
- char *host;
+ LDAPMessage *res = NULL;
+ char *machine;
- /* hostname must be lowercase */
- host = strdup(hostname);
- strlower_m(host);
+ /* machine name must be lowercase */
+ machine = strdup(machine_name);
+ strlower_m(machine);
/*
- status = ads_find_machine_acct(ads, (void **)&res, host);
+ status = ads_find_machine_acct(ads, (void **)&res, machine);
if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
- DEBUG(0, ("Host account for %s already exists - deleting old account\n", host));
- status = ads_leave_realm(ads, host);
+ DEBUG(0, ("Host account for %s already exists - deleting old account\n", machine));
+ status = ads_leave_realm(ads, machine);
if (!ADS_ERR_OK(status)) {
DEBUG(0, ("Failed to delete host '%s' from the '%s' realm.\n",
- host, ads->config.realm));
+ machine, ads->config.realm));
return status;
}
}
*/
- status = ads_add_machine_acct(ads, host, account_type, org_unit);
+ status = ads_add_machine_acct(ads, machine, account_type, org_unit);
if (!ADS_ERR_OK(status)) {
- DEBUG(0, ("ads_add_machine_acct: %s\n", ads_errstr(status)));
+ DEBUG(0, ("ads_add_machine_acct (%s): %s\n", machine, ads_errstr(status)));
+ SAFE_FREE(machine);
return status;
}
- status = ads_find_machine_acct(ads, (void **)&res, host);
+ status = ads_find_machine_acct(ads, (void **)&res, machine);
if (!ADS_ERR_OK(status)) {
- DEBUG(0, ("Host account test failed\n"));
+ DEBUG(0, ("Host account test failed for machine %s\n", machine));
+ SAFE_FREE(machine);
return status;
}
- free(host);
+ SAFE_FREE(machine);
+ ads_msgfree(ads, res);
return status;
}
diff --git a/source/libads/sasl.c b/source/libads/sasl.c
index 18cbb465887..8eb2c86bed5 100644
--- a/source/libads/sasl.c
+++ b/source/libads/sasl.c
@@ -201,14 +201,14 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
/* make sure the server understands kerberos */
for (i=0;OIDs[i];i++) {
- DEBUG(3,("got OID=%s\n", OIDs[i]));
+ DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
strcmp(OIDs[i], OID_KERBEROS5) == 0) {
got_kerberos_mechanism = True;
}
free(OIDs[i]);
}
- DEBUG(3,("got principal=%s\n", principal));
+ DEBUG(3,("ads_sasl_spnego_bind: got server principal name =%s\n", principal));
#ifdef HAVE_KRB5
if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
diff --git a/source/libsmb/asn1.c b/source/libsmb/asn1.c
index ecc5e3dee64..ca14f3fbb71 100644
--- a/source/libsmb/asn1.c
+++ b/source/libsmb/asn1.c
@@ -320,17 +320,17 @@ int asn1_tag_remaining(ASN1_DATA *data)
BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
{
uint8 b;
- pstring oid;
+ pstring oid_str;
fstring el;
if (!asn1_start_tag(data, ASN1_OID)) return False;
asn1_read_uint8(data, &b);
- oid[0] = 0;
+ oid_str[0] = 0;
fstr_sprintf(el, "%u", b/40);
- pstrcat(oid, el);
+ pstrcat(oid_str, el);
fstr_sprintf(el, " %u", b%40);
- pstrcat(oid, el);
+ pstrcat(oid_str, el);
while (asn1_tag_remaining(data) > 0) {
unsigned v = 0;
@@ -339,12 +339,12 @@ BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
v = (v<<7) | (b&0x7f);
} while (!data->has_error && b & 0x80);
fstr_sprintf(el, " %u", v);
- pstrcat(oid, el);
+ pstrcat(oid_str, el);
}
asn1_end_tag(data);
- *OID = strdup(oid);
+ *OID = strdup(oid_str);
return !data->has_error;
}
diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c
index b75d6be0a60..281ee3af845 100644
--- a/source/libsmb/clientgen.c
+++ b/source/libsmb/clientgen.c
@@ -176,7 +176,12 @@ void cli_setup_packet(struct cli_state *cli)
SSVAL(cli->outbuf,smb_mid,cli->mid);
if (cli->protocol > PROTOCOL_CORE) {
uint16 flags2;
- SCVAL(cli->outbuf,smb_flg,0x8);
+ if (cli->case_sensitive) {
+ SCVAL(cli->outbuf,smb_flg,0x0);
+ } else {
+ /* Default setting, case insensitive. */
+ SCVAL(cli->outbuf,smb_flg,0x8);
+ }
flags2 = FLAGS2_LONG_PATH_COMPONENTS;
if (cli->capabilities & CAP_UNICODE)
flags2 |= FLAGS2_UNICODE_STRINGS;
@@ -273,6 +278,7 @@ struct cli_state *cli_initialise(struct cli_state *cli)
cli->outbuf = (char *)malloc(cli->bufsize+SAFETY_MARGIN);
cli->inbuf = (char *)malloc(cli->bufsize+SAFETY_MARGIN);
cli->oplock_handler = cli_oplock_ack;
+ cli->case_sensitive = False;
cli->use_spnego = lp_client_use_spnego();
@@ -441,6 +447,17 @@ uint16 cli_setpid(struct cli_state *cli, uint16 pid)
}
/****************************************************************************
+ Set the case sensitivity flag on the packets. Returns old state.
+****************************************************************************/
+
+BOOL cli_set_case_sensitive(struct cli_state *cli, BOOL case_sensitive)
+{
+ BOOL ret = cli->case_sensitive;
+ cli->case_sensitive = case_sensitive;
+ return ret;
+}
+
+/****************************************************************************
Send a keepalive packet to the server
****************************************************************************/
BOOL cli_send_keepalive(struct cli_state *cli)
diff --git a/source/libsmb/clikrb5.c b/source/libsmb/clikrb5.c
index 9027f192ef7..4929bd63ef2 100644
--- a/source/libsmb/clikrb5.c
+++ b/source/libsmb/clikrb5.c
@@ -124,13 +124,13 @@
#endif
#if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
-krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
+ krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
krb5_enctype **enctypes)
{
return krb5_get_permitted_enctypes(context, enctypes);
}
#elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES)
-krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
+ krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
krb5_enctype **enctypes)
{
return krb5_get_default_in_tkt_etypes(context, enctypes);
@@ -234,6 +234,13 @@ krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
}
#endif
+#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME)
+ void krb5_free_unparsed_name(krb5_context context, char *val)
+{
+ SAFE_FREE(val);
+}
+#endif
+
static BOOL ads_cleanup_expired_creds(krb5_context context,
krb5_ccache ccache,
krb5_creds *credsp)
@@ -413,11 +420,12 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset,
failed:
if ( context ) {
-#if 0 /* JERRY -- disabled since it causes heimdal 0.6.1rc3 to die
- SuSE 9.1 Pro */
+/* Removed by jra. They really need to fix their kerberos so we don't leak memory.
+ JERRY -- disabled since it causes heimdal 0.6.1rc3 to die
+ SuSE 9.1 Pro
+*/
if (ccdef)
krb5_cc_close(context, ccdef);
-#endif
if (auth_context)
krb5_auth_con_free(context, auth_context);
krb5_free_context(context);
@@ -465,6 +473,17 @@ failed:
}
#endif
+ krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry)
+{
+#if defined(HAVE_KRB5_KT_FREE_ENTRY)
+ return krb5_kt_free_entry(context, kt_entry);
+#elif defined(HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS)
+ return krb5_free_keytab_entry_contents(context, kt_entry);
+#else
+#error UNKNOWN_KT_FREE_FUNCTION
+#endif
+}
+
#else /* HAVE_KRB5 */
/* this saves a few linking headaches */
int cli_krb5_get_ticket(const char *principal, time_t time_offset,
diff --git a/source/libsmb/clispnego.c b/source/libsmb/clispnego.c
index e6cadc466c1..85b7bd9e1ee 100644
--- a/source/libsmb/clispnego.c
+++ b/source/libsmb/clispnego.c
@@ -141,9 +141,9 @@ BOOL spnego_parse_negTokenInit(DATA_BLOB blob,
asn1_start_tag(&data,ASN1_CONTEXT(0));
asn1_start_tag(&data,ASN1_SEQUENCE(0));
for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) {
- char *oid = NULL;
- asn1_read_OID(&data,&oid);
- OIDs[i] = oid;
+ char *oid_str = NULL;
+ asn1_read_OID(&data,&oid_str);
+ OIDs[i] = oid_str;
}
OIDs[i] = NULL;
asn1_end_tag(&data);
@@ -230,9 +230,9 @@ BOOL parse_negTokenTarg(DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], DATA_BLOB *se
asn1_start_tag(&data, ASN1_CONTEXT(0));
asn1_start_tag(&data, ASN1_SEQUENCE(0));
for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) {
- char *oid = NULL;
- asn1_read_OID(&data,&oid);
- OIDs[i] = oid;
+ char *oid_str = NULL;
+ asn1_read_OID(&data,&oid_str);
+ OIDs[i] = oid_str;
}
OIDs[i] = NULL;
asn1_end_tag(&data);
diff --git a/source/libsmb/conncache.c b/source/libsmb/conncache.c
index e6604617d68..15cc75b129e 100644
--- a/source/libsmb/conncache.c
+++ b/source/libsmb/conncache.c
@@ -154,5 +154,3 @@ void flush_negative_conn_cache( void )
}
}
-
-
diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c
index 2bb7359e742..cee0015e257 100644
--- a/source/libsmb/namequery.c
+++ b/source/libsmb/namequery.c
@@ -56,7 +56,8 @@ static struct node_status *parse_node_status(char *p, int *num_names, struct nod
return NULL;
ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names));
- if (!ret) return NULL;
+ if (!ret)
+ return NULL;
p++;
for (i=0;i< *num_names;i++) {
@@ -556,84 +557,80 @@ XFILE *startlmhosts(char *fname)
BOOL getlmhostsent( XFILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
{
- pstring line;
-
- while(!x_feof(fp) && !x_ferror(fp)) {
- pstring ip,flags,extra;
- const char *ptr;
- char *ptr1;
- int count = 0;
+ pstring line;
- *name_type = -1;
+ while(!x_feof(fp) && !x_ferror(fp)) {
+ pstring ip,flags,extra;
+ const char *ptr;
+ char *ptr1;
+ int count = 0;
- if (!fgets_slash(line,sizeof(pstring),fp))
- continue;
+ *name_type = -1;
- if (*line == '#')
- continue;
+ if (!fgets_slash(line,sizeof(pstring),fp)) {
+ continue;
+ }
- pstrcpy(ip,"");
- pstrcpy(name,"");
- pstrcpy(flags,"");
+ if (*line == '#') {
+ continue;
+ }
- ptr = line;
+ pstrcpy(ip,"");
+ pstrcpy(name,"");
+ pstrcpy(flags,"");
- if (next_token(&ptr,ip ,NULL,sizeof(ip)))
- ++count;
- if (next_token(&ptr,name ,NULL, sizeof(pstring)))
- ++count;
- if (next_token(&ptr,flags,NULL, sizeof(flags)))
- ++count;
- if (next_token(&ptr,extra,NULL, sizeof(extra)))
- ++count;
+ ptr = line;
- if (count <= 0)
- continue;
+ if (next_token(&ptr,ip ,NULL,sizeof(ip)))
+ ++count;
+ if (next_token(&ptr,name ,NULL, sizeof(pstring)))
+ ++count;
+ if (next_token(&ptr,flags,NULL, sizeof(flags)))
+ ++count;
+ if (next_token(&ptr,extra,NULL, sizeof(extra)))
+ ++count;
- if (count > 0 && count < 2)
- {
- DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
- continue;
- }
+ if (count <= 0)
+ continue;
- if (count >= 4)
- {
- DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
- continue;
- }
+ if (count > 0 && count < 2) {
+ DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
+ continue;
+ }
- DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
+ if (count >= 4) {
+ DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
+ continue;
+ }
- if (strchr_m(flags,'G') || strchr_m(flags,'S'))
- {
- DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
- continue;
- }
+ DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
- *ipaddr = *interpret_addr2(ip);
+ if (strchr_m(flags,'G') || strchr_m(flags,'S')) {
+ DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
+ continue;
+ }
- /* Extra feature. If the name ends in '#XX', where XX is a hex number,
- then only add that name type. */
- if((ptr1 = strchr_m(name, '#')) != NULL)
- {
- char *endptr;
+ *ipaddr = *interpret_addr2(ip);
- ptr1++;
- *name_type = (int)strtol(ptr1, &endptr, 16);
+ /* Extra feature. If the name ends in '#XX', where XX is a hex number,
+ then only add that name type. */
+ if((ptr1 = strchr_m(name, '#')) != NULL) {
+ char *endptr;
+ ptr1++;
- if(!*ptr1 || (endptr == ptr1))
- {
- DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
- continue;
- }
+ *name_type = (int)strtol(ptr1, &endptr, 16);
+ if(!*ptr1 || (endptr == ptr1)) {
+ DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
+ continue;
+ }
- *(--ptr1) = '\0'; /* Truncate at the '#' */
- }
+ *(--ptr1) = '\0'; /* Truncate at the '#' */
+ }
- return True;
- }
+ return True;
+ }
- return False;
+ return False;
}
/********************************************************
@@ -998,145 +995,145 @@ static BOOL internal_resolve_name(const char *name, int name_type,
struct ip_service **return_iplist,
int *return_count, const char *resolve_order)
{
- pstring name_resolve_list;
- fstring tok;
- const char *ptr;
- BOOL allones = (strcmp(name,"255.255.255.255") == 0);
- BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
- BOOL is_address = is_ipaddress(name);
- BOOL result = False;
- int i;
+ pstring name_resolve_list;
+ fstring tok;
+ const char *ptr;
+ BOOL allones = (strcmp(name,"255.255.255.255") == 0);
+ BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
+ BOOL is_address = is_ipaddress(name);
+ BOOL result = False;
+ int i;
- *return_iplist = NULL;
- *return_count = 0;
+ *return_iplist = NULL;
+ *return_count = 0;
- DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type));
+ DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type));
- if (allzeros || allones || is_address) {
+ if (allzeros || allones || is_address) {
- if ( (*return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service))) == NULL ) {
- DEBUG(0,("internal_resolve_name: malloc fail !\n"));
- return False;
- }
+ if ( (*return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service))) == NULL ) {
+ DEBUG(0,("internal_resolve_name: malloc fail !\n"));
+ return False;
+ }
- if(is_address) {
- /* ignore the port here */
- (*return_iplist)->port = PORT_NONE;
+ if(is_address) {
+ /* ignore the port here */
+ (*return_iplist)->port = PORT_NONE;
- /* if it's in the form of an IP address then get the lib to interpret it */
- if (((*return_iplist)->ip.s_addr = inet_addr(name)) == 0xFFFFFFFF ){
- DEBUG(1,("internal_resolve_name: inet_addr failed on %s\n", name));
- return False;
+ /* if it's in the form of an IP address then get the lib to interpret it */
+ if (((*return_iplist)->ip.s_addr = inet_addr(name)) == 0xFFFFFFFF ){
+ DEBUG(1,("internal_resolve_name: inet_addr failed on %s\n", name));
+ return False;
+ }
+ } else {
+ (*return_iplist)->ip.s_addr = allones ? 0xFFFFFFFF : 0;
}
- } else {
- (*return_iplist)->ip.s_addr = allones ? 0xFFFFFFFF : 0;
+ *return_count = 1;
+ return True;
}
- *return_count = 1;
- return True;
- }
- /* Check name cache */
+ /* Check name cache */
- if (namecache_fetch(name, name_type, return_iplist, return_count)) {
- /* This could be a negative response */
- return (*return_count > 0);
- }
+ if (namecache_fetch(name, name_type, return_iplist, return_count)) {
+ /* This could be a negative response */
+ return (*return_count > 0);
+ }
- /* set the name resolution order */
+ /* set the name resolution order */
- if ( strcmp( resolve_order, "NULL") == 0 ) {
- DEBUG(8,("internal_resolve_name: all lookups disabled\n"));
- return False;
- }
-
- if ( !resolve_order )
- pstrcpy(name_resolve_list, lp_name_resolve_order());
- else
- pstrcpy(name_resolve_list, resolve_order);
+ if ( strcmp( resolve_order, "NULL") == 0 ) {
+ DEBUG(8,("internal_resolve_name: all lookups disabled\n"));
+ return False;
+ }
- if ( !name_resolve_list[0] )
- ptr = "host";
- else
- ptr = name_resolve_list;
+ if ( !resolve_order ) {
+ pstrcpy(name_resolve_list, lp_name_resolve_order());
+ } else {
+ pstrcpy(name_resolve_list, resolve_order);
+
+ if ( !name_resolve_list[0] ) {
+ ptr = "host";
+ } else {
+ ptr = name_resolve_list;
+ }
- /* iterate through the name resolution backends */
+ /* iterate through the name resolution backends */
- while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
- if((strequal(tok, "host") || strequal(tok, "hosts"))) {
- if (resolve_hosts(name, name_type, return_iplist, return_count)) {
- result = True;
- goto done;
- }
- } else if(strequal( tok, "ads")) {
- /* deal with 0x1c names here. This will result in a
- SRV record lookup for _ldap._tcp.<domain> if we
- are using 'security = ads' */
- if (resolve_ads(name, name_type, return_iplist, return_count)) {
- result = True;
- goto done;
- }
- } else if(strequal( tok, "lmhosts")) {
- if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
- result = True;
- goto done;
- }
- } else if(strequal( tok, "wins")) {
- /* don't resolve 1D via WINS */
- if (name_type != 0x1D &&
- resolve_wins(name, name_type, return_iplist, return_count)) {
- result = True;
- goto done;
- }
- } else if(strequal( tok, "bcast")) {
- if (name_resolve_bcast(name, name_type, return_iplist, return_count)) {
- result = True;
- goto done;
- }
- } else {
- DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
- }
- }
-
- /* All of the resolve_* functions above have returned false. */
-
- SAFE_FREE(*return_iplist);
- *return_count = 0;
-
- return False;
+ while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
+ if((strequal(tok, "host") || strequal(tok, "hosts"))) {
+ if (resolve_hosts(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "ads")) {
+ /* deal with 0x1c names here. This will result in a
+ SRV record lookup for _ldap._tcp.<domain> if we
+ are using 'security = ads' */
+ if (resolve_ads(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "lmhosts")) {
+ if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "wins")) {
+ /* don't resolve 1D via WINS */
+ if (name_type != 0x1D && resolve_wins(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "bcast")) {
+ if (name_resolve_bcast(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else {
+ DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
+ }
+ }
- done:
+ /* All of the resolve_* functions above have returned false. */
+
+ SAFE_FREE(*return_iplist);
+ *return_count = 0;
+
+ return False;
- /* Remove duplicate entries. Some queries, notably #1c (domain
- controllers) return the PDC in iplist[0] and then all domain
- controllers including the PDC in iplist[1..n]. Iterating over
- the iplist when the PDC is down will cause two sets of timeouts. */
+ done:
- if ( *return_count ) {
- *return_count = remove_duplicate_addrs2( *return_iplist, *return_count );
- }
+ /* Remove duplicate entries. Some queries, notably #1c (domain
+ controllers) return the PDC in iplist[0] and then all domain
+ controllers including the PDC in iplist[1..n]. Iterating over
+ the iplist when the PDC is down will cause two sets of timeouts. */
+
+ if ( *return_count ) {
+ *return_count = remove_duplicate_addrs2( *return_iplist, *return_count );
+ }
- /* Save in name cache */
- if ( DEBUGLEVEL >= 100 ) {
- for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++)
- DEBUG(100, ("Storing name %s of type %d (%s:%d)\n", name,
- name_type, inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port));
- }
+ /* Save in name cache */
+ if ( DEBUGLEVEL >= 100 ) {
+ for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++)
+ DEBUG(100, ("Storing name %s of type %d (%s:%d)\n", name,
+ name_type, inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port));
+ }
- namecache_store(name, name_type, *return_count, *return_iplist);
-
- /* Display some debugging info */
+ namecache_store(name, name_type, *return_count, *return_iplist);
- if ( DEBUGLEVEL >= 10 ) {
- DEBUG(10, ("internal_resolve_name: returning %d addresses: ",
- *return_count));
+ /* Display some debugging info */
- for (i = 0; i < *return_count; i++)
- DEBUGADD(10, ("%s:%d ", inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port));
+ if ( DEBUGLEVEL >= 10 ) {
+ DEBUG(10, ("internal_resolve_name: returning %d addresses: ", *return_count));
- DEBUG(10, ("\n"));
- }
+ for (i = 0; i < *return_count; i++) {
+ DEBUGADD(10, ("%s:%d ", inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port));
+ }
+ DEBUG(10, ("\n"));
+ }
+ }
- return result;
+ return result;
}
/********************************************************
@@ -1218,8 +1215,9 @@ BOOL get_pdc_ip(const char *domain, struct in_addr *ip)
/* Look up #1B name */
- if (!internal_resolve_name(domain, 0x1b, &ip_list, &count, lp_name_resolve_order()))
+ if (!internal_resolve_name(domain, 0x1b, &ip_list, &count, lp_name_resolve_order())) {
return False;
+ }
/* if we get more than 1 IP back we have to assume it is a
multi-homed PDC and not a mess up */
@@ -1298,16 +1296,17 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list,
num_addresses += auto_count;
done_auto_lookup = True;
DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count));
- }
- else
+ } else {
num_addresses++;
+ }
}
/* if we have no addresses and haven't done the auto lookup, then
just return the list of DC's */
- if ( (num_addresses == 0) && !done_auto_lookup )
+ if ( (num_addresses == 0) && !done_auto_lookup ) {
return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order);
+ }
/* maybe we just failed? */
@@ -1317,8 +1316,7 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list,
}
if ( (return_iplist = (struct ip_service *)
- malloc(num_addresses * sizeof(struct ip_service))) == NULL )
- {
+ malloc(num_addresses * sizeof(struct ip_service))) == NULL ) {
DEBUG(3,("get_dc_list: malloc fail !\n"));
return False;
}
@@ -1335,6 +1333,13 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list,
if ( strequal(name, "*") ) {
for ( j=0; j<auto_count; j++ ) {
+ /* Check for and don't copy any known bad DC IP's. */
+ if(!NT_STATUS_IS_OK(check_negative_conn_cache(domain,
+ inet_ntoa(auto_ip_list[j].ip)))) {
+ DEBUG(5,("get_dc_list: negative entry %s removed from DC list\n",
+ inet_ntoa(auto_ip_list[j].ip) ));
+ continue;
+ }
return_iplist[local_count].ip = auto_ip_list[j].ip;
return_iplist[local_count].port = auto_ip_list[j].port;
local_count++;
@@ -1356,6 +1361,13 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list,
/* explicit lookup; resolve_name() will handle names & IP addresses */
if ( resolve_name( name, &name_ip, 0x20 ) ) {
+
+ /* Check for and don't copy any known bad DC IP's. */
+ if( !NT_STATUS_IS_OK(check_negative_conn_cache(domain, inet_ntoa(name_ip))) ) {
+ DEBUG(5,("get_dc_list: negative entry %s removed from DC list\n",name ));
+ continue;
+ }
+
return_iplist[local_count].ip = name_ip;
return_iplist[local_count].port = port;
local_count++;
@@ -1368,8 +1380,9 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list,
/* need to remove duplicates in the list if we have any
explicit password servers */
- if ( local_count )
+ if ( local_count ) {
local_count = remove_duplicate_addrs2( return_iplist, local_count );
+ }
if ( DEBUGLEVEL >= 4 ) {
DEBUG(4,("get_dc_list: returning %d ip addresses in an %sordered list\n", local_count,
@@ -1392,8 +1405,9 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list,
}
/*********************************************************************
- small wrapper function to get the DC list and sort it if neccessary
+ Small wrapper function to get the DC list and sort it if neccessary.
*********************************************************************/
+
BOOL get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *count, BOOL ads_only )
{
BOOL ordered;
@@ -1401,13 +1415,14 @@ BOOL get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *c
DEBUG(8,("get_sorted_dc_list: attempting lookup using [%s]\n",
(ads_only ? "ads" : lp_name_resolve_order())));
- if ( !get_dc_list(domain, ip_list, count, ads_only, &ordered) )
- return False;
+ if ( !get_dc_list(domain, ip_list, count, ads_only, &ordered) ) {
+ return False;
+ }
/* only sort if we don't already have an ordered list */
- if ( !ordered )
+ if ( !ordered ) {
sort_ip_list2( *ip_list, *count );
+ }
return True;
}
-
diff --git a/source/libsmb/ntlmssp.c b/source/libsmb/ntlmssp.c
index 52e5cd004ff..66d48afc463 100644
--- a/source/libsmb/ntlmssp.c
+++ b/source/libsmb/ntlmssp.c
@@ -1102,8 +1102,6 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state)
NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_NEGOTIATE_NTLM2 |
NTLMSSP_NEGOTIATE_KEY_EXCH |
- NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED |
- NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED |
/*
* We need to set this to allow a later SetPassword
* via the SAMR pipe to succeed. Strange.... We could
diff --git a/source/libsmb/smb_signing.c b/source/libsmb/smb_signing.c
index 7130453c0c9..8c59e49ebb9 100644
--- a/source/libsmb/smb_signing.c
+++ b/source/libsmb/smb_signing.c
@@ -42,11 +42,18 @@ struct smb_basic_signing_context {
struct outstanding_packet_lookup *outstanding_packet_list;
};
-static void store_sequence_for_reply(struct outstanding_packet_lookup **list,
+static BOOL store_sequence_for_reply(struct outstanding_packet_lookup **list,
uint16 mid, uint32 reply_seq_num)
{
struct outstanding_packet_lookup *t;
+ /* Ensure we only add a mid once. */
+ for (t = *list; t; t = t->next) {
+ if (t->mid == mid) {
+ return False;
+ }
+ }
+
t = smb_xmalloc(sizeof(*t));
ZERO_STRUCTP(t);
@@ -65,6 +72,7 @@ static void store_sequence_for_reply(struct outstanding_packet_lookup **list,
DLIST_ADD(*list, t);
DEBUG(10,("store_sequence_for_reply: stored seq = %u mid = %u\n",
(unsigned int)reply_seq_num, (unsigned int)mid ));
+ return True;
}
static BOOL get_sequence_for_reply(struct outstanding_packet_lookup **list,
@@ -489,6 +497,7 @@ BOOL cli_simple_set_signing(struct cli_state *cli,
void cli_signing_trans_start(struct cli_state *cli, uint16 mid)
{
struct smb_basic_signing_context *data = cli->sign_info.signing_context;
+ uint32 reply_seq_num;
if (!cli->sign_info.doing_signing || !data)
return;
@@ -496,9 +505,16 @@ void cli_signing_trans_start(struct cli_state *cli, uint16 mid)
data->trans_info = smb_xmalloc(sizeof(struct trans_info_context));
ZERO_STRUCTP(data->trans_info);
- data->trans_info->send_seq_num = data->send_seq_num-2;
+ /* This ensures the sequence is pulled off the outstanding packet list */
+ if (!get_sequence_for_reply(&data->outstanding_packet_list,
+ mid, &reply_seq_num)) {
+ DEBUG(1, ("get_sequence_for_reply failed - did we enter the trans signing state without sending a packet?\n"));
+ return;
+ }
+
+ data->trans_info->send_seq_num = reply_seq_num - 1;
data->trans_info->mid = mid;
- data->trans_info->reply_seq_num = data->send_seq_num-1;
+ data->trans_info->reply_seq_num = reply_seq_num;
DEBUG(10,("cli_signing_trans_start: storing mid = %u, reply_seq_num = %u, send_seq_num = %u \
data->send_seq_num = %u\n",
@@ -748,14 +764,16 @@ static BOOL srv_check_incoming_message(char *inbuf, struct smb_sign_info *si, BO
if (!good) {
- DEBUG(5, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n",
- (unsigned int)saved_seq));
- dump_data(5, (const char *)calc_md5_mac, 8);
-
- DEBUG(5, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n",
+ if (saved_seq) {
+ DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n",
(unsigned int)saved_seq));
- dump_data(5, (const char *)server_sent_mac, 8);
+ dump_data(5, (const char *)calc_md5_mac, 8);
+ DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n",
+ (unsigned int)reply_seq_number));
+ dump_data(5, (const char *)server_sent_mac, 8);
+ }
+
#if 1 /* JRATEST */
{
int i;
@@ -848,9 +866,13 @@ void srv_defer_sign_response(uint16 mid)
if (!data)
return;
- store_sequence_for_reply(&data->outstanding_packet_list,
- mid, data->send_seq_num);
- data->send_seq_num++;
+ /*
+ * Ensure we only store this mid reply once...
+ */
+
+ if (store_sequence_for_reply(&data->outstanding_packet_list, mid, data->send_seq_num)) {
+ data->send_seq_num++;
+ }
}
/***********************************************************
diff --git a/source/locking/brlock.c b/source/locking/brlock.c
index 47001c8b89c..990a6a25d2f 100644
--- a/source/locking/brlock.c
+++ b/source/locking/brlock.c
@@ -246,8 +246,8 @@ void brl_init(int read_only)
{
if (tdb)
return;
- tdb = tdb_open_ex(lock_path("brlock.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
- read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644, smbd_tdb_log);
+ tdb = tdb_open_log(lock_path("brlock.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
+ read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 );
if (!tdb) {
DEBUG(0,("Failed to open byte range locking database\n"));
return;
diff --git a/source/locking/locking.c b/source/locking/locking.c
index 42036cc70cf..8f53b55fc54 100644
--- a/source/locking/locking.c
+++ b/source/locking/locking.c
@@ -40,6 +40,17 @@ uint16 global_smbpid;
/* the locking database handle */
static TDB_CONTEXT *tdb;
+struct locking_data {
+ union {
+ int num_share_mode_entries;
+ share_mode_entry dummy; /* Needed for alignment. */
+ } u;
+ /* the following two entries are implicit
+ share_mode_entry modes[num_share_mode_entries];
+ char file_name[];
+ */
+};
+
/****************************************************************************
Debugging aid :-).
****************************************************************************/
@@ -283,10 +294,10 @@ BOOL locking_init(int read_only)
if (tdb)
return True;
- tdb = tdb_open_ex(lock_path("locking.tdb"),
+ tdb = tdb_open_log(lock_path("locking.tdb"),
0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
read_only?O_RDONLY:O_RDWR|O_CREAT,
- 0644, smbd_tdb_log);
+ 0644);
if (!tdb) {
DEBUG(0,("ERROR: Failed to initialise locking database\n"));
@@ -432,6 +443,7 @@ int get_share_modes(connection_struct *conn,
data = (struct locking_data *)dbuf.dptr;
num_share_modes = data->u.num_share_mode_entries;
if(num_share_modes) {
+ pstring fname;
int i;
int del_count = 0;
@@ -443,6 +455,9 @@ int get_share_modes(connection_struct *conn,
return 0;
}
+ /* Save off the associated filename. */
+ pstrcpy(fname, dbuf.dptr + sizeof(*data) + num_share_modes * sizeof(share_mode_entry));
+
/*
* Ensure that each entry has a real process attached.
*/
@@ -454,8 +469,10 @@ int get_share_modes(connection_struct *conn,
i++;
} else {
DEBUG(10,("get_share_modes: deleted %s\n", share_mode_str(i, entry_p) ));
- memcpy( &shares[i], &shares[i+1],
- sizeof(share_mode_entry) * (num_share_modes - i - 1));
+ if (num_share_modes - i - 1 > 0) {
+ memcpy( &shares[i], &shares[i+1],
+ sizeof(share_mode_entry) * (num_share_modes - i - 1));
+ }
num_share_modes--;
del_count++;
}
@@ -465,17 +482,28 @@ int get_share_modes(connection_struct *conn,
if (del_count) {
data->u.num_share_mode_entries = num_share_modes;
- if (num_share_modes)
+ if (num_share_modes) {
memcpy(dbuf.dptr + sizeof(*data), shares,
num_share_modes * sizeof(share_mode_entry));
+ /* Append the filename. */
+ pstrcpy(dbuf.dptr + sizeof(*data) + num_share_modes * sizeof(share_mode_entry), fname);
+ }
/* The record has shrunk a bit */
dbuf.dsize -= del_count * sizeof(share_mode_entry);
- if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
- SAFE_FREE(shares);
- SAFE_FREE(dbuf.dptr);
- return 0;
+ if (data->u.num_share_mode_entries == 0) {
+ if (tdb_delete(tdb, key) == -1) {
+ SAFE_FREE(shares);
+ SAFE_FREE(dbuf.dptr);
+ return 0;
+ }
+ } else {
+ if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
+ SAFE_FREE(shares);
+ SAFE_FREE(dbuf.dptr);
+ return 0;
+ }
}
}
}
@@ -575,8 +603,10 @@ ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode,
if (ppse)
*ppse = memdup(&shares[i], sizeof(*shares));
data->u.num_share_mode_entries--;
- memmove(&shares[i], &shares[i+1],
- dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
+ if ((dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))) > 0) {
+ memmove(&shares[i], &shares[i+1],
+ dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
+ }
del_count++;
DEBUG(10,("del_share_entry: deleting entry %d\n", i ));
@@ -843,6 +873,358 @@ BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close)
return True;
}
+/*******************************************************************
+ Print out a deferred open entry.
+********************************************************************/
+
+char *deferred_open_str(int num, deferred_open_entry *e)
+{
+ static pstring de_str;
+
+ slprintf(de_str, sizeof(de_str)-1, "deferred_open_entry[%d]: \
+pid = %lu, mid = %u, dev = 0x%x, inode = %.0f, port = %u, time = [%u.%06u]",
+ num, (unsigned long)e->pid, (unsigned int)e->mid, (unsigned int)e->dev, (double)e->inode,
+ (unsigned int)e->port,
+ (unsigned int)e->time.tv_sec, (unsigned int)e->time.tv_usec );
+
+ return de_str;
+}
+
+/* Internal data structures for deferred opens... */
+
+struct de_locking_key {
+ char name[4];
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+};
+
+struct deferred_open_data {
+ union {
+ int num_deferred_open_entries;
+ deferred_open_entry dummy; /* Needed for alignment. */
+ } u;
+ /* the following two entries are implicit
+ deferred_open_entry de_entries[num_deferred_open_entries];
+ char file_name[];
+ */
+};
+
+/*******************************************************************
+ Print out a deferred open table.
+********************************************************************/
+
+static void print_deferred_open_table(struct deferred_open_data *data)
+{
+ int num_de_entries = data->u.num_deferred_open_entries;
+ deferred_open_entry *de_entries = (deferred_open_entry *)(data + 1);
+ int i;
+
+ for (i = 0; i < num_de_entries; i++) {
+ deferred_open_entry *entry_p = &de_entries[i];
+ DEBUG(10,("print_deferred_open_table: %s\n", deferred_open_str(i, entry_p) ));
+ }
+}
+
+
+/*******************************************************************
+ Form a static deferred open locking key for a dev/inode pair.
+******************************************************************/
+
+static TDB_DATA deferred_open_locking_key(SMB_DEV_T dev, SMB_INO_T inode)
+{
+ static struct de_locking_key key;
+ TDB_DATA kbuf;
+
+ memset(&key, '\0', sizeof(key));
+ memcpy(&key.name[0], "DOE", 4);
+ key.dev = dev;
+ key.inode = inode;
+ kbuf.dptr = (char *)&key;
+ kbuf.dsize = sizeof(key);
+ return kbuf;
+}
+
+/*******************************************************************
+ Get all deferred open entries for a dev/inode pair.
+********************************************************************/
+
+int get_deferred_opens(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode,
+ deferred_open_entry **pp_de_entries)
+{
+ TDB_DATA dbuf;
+ struct deferred_open_data *data;
+ int num_de_entries;
+ deferred_open_entry *de_entries = NULL;
+ TDB_DATA key = deferred_open_locking_key(dev, inode);
+
+ *pp_de_entries = NULL;
+
+ dbuf = tdb_fetch(tdb, key);
+ if (!dbuf.dptr)
+ return 0;
+
+ data = (struct deferred_open_data *)dbuf.dptr;
+ num_de_entries = data->u.num_deferred_open_entries;
+ if(num_de_entries) {
+ pstring fname;
+ int i;
+ int del_count = 0;
+
+ de_entries = (deferred_open_entry *)memdup(dbuf.dptr + sizeof(*data),
+ num_de_entries * sizeof(deferred_open_entry));
+
+ if (!de_entries) {
+ SAFE_FREE(dbuf.dptr);
+ return 0;
+ }
+
+ /* Save off the associated filename. */
+ pstrcpy(fname, dbuf.dptr + sizeof(*data) + num_de_entries * sizeof(deferred_open_entry));
+
+ /*
+ * Ensure that each entry has a real process attached.
+ */
+
+ for (i = 0; i < num_de_entries; ) {
+ deferred_open_entry *entry_p = &de_entries[i];
+ if (process_exists(entry_p->pid)) {
+ DEBUG(10,("get_deferred_opens: %s\n", deferred_open_str(i, entry_p) ));
+ i++;
+ } else {
+ DEBUG(10,("get_deferred_opens: deleted %s\n", deferred_open_str(i, entry_p) ));
+ if (num_de_entries - i - 1 > 0) {
+ memcpy( &de_entries[i], &de_entries[i+1],
+ sizeof(deferred_open_entry) * (num_de_entries - i - 1));
+ }
+ num_de_entries--;
+ del_count++;
+ }
+ }
+
+ /* Did we delete any ? If so, re-store in tdb. */
+ if (del_count) {
+ data->u.num_deferred_open_entries = num_de_entries;
+
+ if (num_de_entries) {
+ memcpy(dbuf.dptr + sizeof(*data), de_entries,
+ num_de_entries * sizeof(deferred_open_entry));
+ /* Append the filename. */
+ pstrcpy(dbuf.dptr + sizeof(*data) + num_de_entries * sizeof(deferred_open_entry), fname);
+ }
+
+ /* The record has shrunk a bit */
+ dbuf.dsize -= del_count * sizeof(deferred_open_entry);
+
+ if (data->u.num_deferred_open_entries == 0) {
+ if (tdb_delete(tdb, key) == -1) {
+ SAFE_FREE(de_entries);
+ SAFE_FREE(dbuf.dptr);
+ return 0;
+ }
+ } else {
+ if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
+ SAFE_FREE(de_entries);
+ SAFE_FREE(dbuf.dptr);
+ return 0;
+ }
+ }
+ }
+ }
+
+ SAFE_FREE(dbuf.dptr);
+ *pp_de_entries = de_entries;
+ return num_de_entries;
+}
+
+/*******************************************************************
+ Check if two deferred open entries are identical.
+********************************************************************/
+
+static BOOL deferred_open_entries_identical( deferred_open_entry *e1, deferred_open_entry *e2)
+{
+#if 1 /* JRA PARANOIA TEST - REMOVE LATER */
+ if (e1->pid == e2->pid &&
+ e1->port == e2->port &&
+ e1->dev == e2->dev &&
+ e1->inode == e2->inode &&
+ ((e1->time.tv_sec != e2->time.tv_sec) ||
+ (e1->time.tv_usec != e2->time.tv_usec) ||
+ (e1->mid != e2->mid))) {
+ smb_panic("PANIC: deferred_open_entries_identical: logic error.\n");
+ }
+#endif
+
+ return (e1->pid == e2->pid &&
+ e1->mid == e2->mid &&
+ e1->port == e2->port &&
+ e1->dev == e2->dev &&
+ e1->inode == e2->inode &&
+ e1->time.tv_sec == e2->time.tv_sec &&
+ e1->time.tv_usec == e2->time.tv_usec);
+}
+
+
+/*******************************************************************
+ Delete a specific deferred open entry.
+ Ignore if no entry deleted.
+********************************************************************/
+
+BOOL delete_deferred_open_entry(deferred_open_entry *entry)
+{
+ TDB_DATA dbuf;
+ struct deferred_open_data *data;
+ int i, del_count=0;
+ deferred_open_entry *de_entries;
+ BOOL ret = True;
+ TDB_DATA key = deferred_open_locking_key(entry->dev, entry->inode);
+
+ /* read in the existing share modes */
+ dbuf = tdb_fetch(tdb, key);
+ if (!dbuf.dptr)
+ return -1;
+
+ data = (struct deferred_open_data *)dbuf.dptr;
+ de_entries = (deferred_open_entry *)(dbuf.dptr + sizeof(*data));
+
+ /*
+ * Find any with this pid and delete it
+ * by overwriting with the rest of the data
+ * from the record.
+ */
+
+ DEBUG(10,("delete_deferred_open_entry: num_deferred_open_entries = %d\n",
+ data->u.num_deferred_open_entries ));
+
+ for (i=0;i<data->u.num_deferred_open_entries;) {
+ if (deferred_open_entries_identical(&de_entries[i], entry)) {
+ DEBUG(10,("delete_deferred_open_entry: deleted %s\n",
+ deferred_open_str(i, &de_entries[i]) ));
+
+ data->u.num_deferred_open_entries--;
+ if ((dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*de_entries))) > 0) {
+ memmove(&de_entries[i], &de_entries[i+1],
+ dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*de_entries)));
+ }
+ del_count++;
+
+ DEBUG(10,("delete_deferred_open_entry: deleting entry %d\n", i ));
+
+ } else {
+ i++;
+ }
+ }
+
+ SMB_ASSERT(del_count == 0 || del_count == 1);
+
+ if (del_count) {
+ /* the record may have shrunk a bit */
+ dbuf.dsize -= del_count * sizeof(*de_entries);
+
+ /* store it back in the database */
+ if (data->u.num_deferred_open_entries == 0) {
+ if (tdb_delete(tdb, key) == -1)
+ ret = False;
+ } else {
+ if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1)
+ ret = False;
+ }
+ }
+ DEBUG(10,("delete_deferred_open_entry: Remaining table.\n"));
+ print_deferred_open_table((struct deferred_open_data*)dbuf.dptr);
+ SAFE_FREE(dbuf.dptr);
+ return ret;
+}
+
+/*******************************************************************
+ Fill a deferred open entry.
+********************************************************************/
+
+static void fill_deferred_open(char *p, uint16 mid, struct timeval *ptv, SMB_DEV_T dev, SMB_INO_T inode, uint16 port)
+{
+ deferred_open_entry *e = (deferred_open_entry *)p;
+ void *x = &e->time; /* Needed to force alignment. p may not be aligned.... */
+
+ memset(e, '\0', sizeof(deferred_open_entry));
+ e->mid = mid;
+ e->pid = sys_getpid();
+ memcpy(x, ptv, sizeof(struct timeval));
+ e->dev = dev;
+ e->inode = inode;
+ e->port = port;
+}
+
+/*******************************************************************
+ Add a deferred open record. Return False on fail, True on success.
+********************************************************************/
+
+BOOL add_deferred_open(uint16 mid, struct timeval *ptv, SMB_DEV_T dev, SMB_INO_T inode, uint16 port, const char *fname)
+{
+ TDB_DATA dbuf;
+ struct deferred_open_data *data;
+ char *p=NULL;
+ int size;
+ TDB_DATA key = deferred_open_locking_key(dev, inode);
+ BOOL ret = True;
+
+ /* read in the existing deferred open records if any */
+ dbuf = tdb_fetch(tdb, key);
+ if (!dbuf.dptr) {
+ size_t offset;
+ /* we'll need to create a new record */
+
+ size = sizeof(*data) + sizeof(deferred_open_entry) + strlen(fname) + 1;
+ p = (char *)malloc(size);
+ if (!p)
+ return False;
+ data = (struct deferred_open_data *)p;
+ data->u.num_deferred_open_entries = 1;
+
+ DEBUG(10,("add_deferred_open: creating entry for file %s. num_deferred_open_entries = 1\n",
+ fname ));
+
+ offset = sizeof(*data) + sizeof(deferred_open_entry);
+ safe_strcpy(p + offset, fname, size - offset - 1);
+ fill_deferred_open(p + sizeof(*data), mid, ptv, dev, inode, port);
+ dbuf.dptr = p;
+ dbuf.dsize = size;
+ if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1)
+ ret = False;
+
+ print_deferred_open_table((struct deferred_open_data *)p);
+
+ SAFE_FREE(p);
+ return ret;
+ }
+
+ /* we're adding to an existing entry - this is a bit fiddly */
+ data = (struct deferred_open_data *)dbuf.dptr;
+
+ data->u.num_deferred_open_entries++;
+
+ DEBUG(10,("add_deferred_open: adding entry for file %s. new num_deferred_open_entries = %d\n",
+ fname, data->u.num_deferred_open_entries ));
+
+ size = dbuf.dsize + sizeof(deferred_open_entry);
+ p = malloc(size);
+ if (!p) {
+ SAFE_FREE(dbuf.dptr);
+ return False;
+ }
+ memcpy(p, dbuf.dptr, sizeof(*data));
+ fill_deferred_open(p + sizeof(*data), mid, ptv, dev, inode, port);
+ memcpy(p + sizeof(*data) + sizeof(deferred_open_entry), dbuf.dptr + sizeof(*data),
+ dbuf.dsize - sizeof(*data));
+ SAFE_FREE(dbuf.dptr);
+ dbuf.dptr = p;
+ dbuf.dsize = size;
+ if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1)
+ ret = False;
+ print_deferred_open_table((struct deferred_open_data *)p);
+ SAFE_FREE(p);
+ return ret;
+}
+
/****************************************************************************
Traverse the whole database with this function, calling traverse_callback
on each share mode
@@ -858,6 +1240,10 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
SHAREMODE_FN(traverse_callback) = (SHAREMODE_FN_CAST())state;
+ /* Ensure this is a locking_key record. */
+ if (kbuf.dsize != sizeof(struct locking_key))
+ return 0;
+
data = (struct locking_data *)dbuf.dptr;
shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
name = dbuf.dptr + sizeof(*data) + data->u.num_share_mode_entries*sizeof(*shares);
diff --git a/source/nmbd/nmbd_browsesync.c b/source/nmbd/nmbd_browsesync.c
index 15827e21bae..56ffdc2670f 100644
--- a/source/nmbd/nmbd_browsesync.c
+++ b/source/nmbd/nmbd_browsesync.c
@@ -103,6 +103,7 @@ static void announce_local_master_browser_to_domain_master_browser( struct work_
{
pstring outbuf;
unstring myname;
+ unstring dmb_name;
char *p;
if(ismyip(work->dmb_addr)) {
@@ -135,8 +136,10 @@ static void announce_local_master_browser_to_domain_master_browser( struct work_
work->work_group );
}
+ /* Target name for send_mailslot must be in UNIX charset. */
+ pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
- global_myname(), 0x0, work->dmb_name.name, 0x0,
+ global_myname(), 0x0, dmb_name, 0x0,
work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
}
diff --git a/source/nmbd/nmbd_winsserver.c b/source/nmbd/nmbd_winsserver.c
index 582338d710a..0e0289d9a33 100644
--- a/source/nmbd/nmbd_winsserver.c
+++ b/source/nmbd/nmbd_winsserver.c
@@ -1727,11 +1727,16 @@ void initiate_wins_processing(time_t t)
&& (namerec->data.death_time < t) ) {
if( namerec->data.source == SELF_NAME ) {
- DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF name %s\n",
+ DEBUG( 3, ( "initiate_wins_processing: Subnet %s not expiring SELF name %s\n",
wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
namerec->data.death_time += 300;
namerec->subnet->namelist_changed = True;
continue;
+ } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
+ DEBUG(3,("initiate_wins_processing: deleting timed out DNS name %s\n",
+ nmb_namestr(&namerec->name)));
+ remove_name_from_namelist( wins_server_subnet, namerec );
+ continue;
}
/* handle records, samba is the wins owner */
diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c
index a98bd294064..50b6f0a87fb 100644
--- a/source/nsswitch/winbindd.c
+++ b/source/nsswitch/winbindd.c
@@ -869,16 +869,13 @@ int main(int argc, char **argv)
ZERO_STRUCT(server_state);
- if (!winbindd_param_init())
- return 1;
-
/* Winbind daemon initialisation */
- if (!winbindd_upgrade_idmap())
- return 1;
-
- if (!idmap_init(lp_idmap_backend()))
- return 1;
+ if ( (!winbindd_param_init()) || (!winbindd_upgrade_idmap()) ||
+ (!idmap_init(lp_idmap_backend())) ) {
+ DEBUG(1, ("Could not init idmap -- netlogon proxy only\n"));
+ idmap_proxyonly();
+ }
generate_wellknown_sids();
diff --git a/source/nsswitch/winbindd_cache.c b/source/nsswitch/winbindd_cache.c
index 877fa2d995c..bbd98a620f6 100644
--- a/source/nsswitch/winbindd_cache.c
+++ b/source/nsswitch/winbindd_cache.c
@@ -363,6 +363,12 @@ static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
if ( NT_STATUS_IS_OK(status) )
goto done;
+ /* important! make sure that we know if this is a native
+ mode domain or not */
+
+ if ( !domain->initialized )
+ set_dc_type_and_flags( domain );
+
status = domain->backend->sequence_number(domain, &domain->sequence_number);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source/nsswitch/winbindd_cm.c b/source/nsswitch/winbindd_cm.c
index eda962088d4..04f87fc1a2f 100644
--- a/source/nsswitch/winbindd_cm.c
+++ b/source/nsswitch/winbindd_cm.c
@@ -117,21 +117,40 @@ static void cm_get_ipc_userpass(char **username, char **domain, char **password)
/*
setup for schannel on any pipes opened on this connection
*/
-static NTSTATUS setup_schannel(struct cli_state *cli)
+static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain )
{
NTSTATUS ret;
uchar trust_password[16];
uint32 sec_channel_type;
+ DOM_SID sid;
+ time_t lct;
- if (!secrets_fetch_trust_account_password(lp_workgroup(),
- trust_password,
- NULL, &sec_channel_type)) {
- return NT_STATUS_UNSUCCESSFUL;
+ /* use the domain trust password if we're on a DC
+ and this is not our domain */
+
+ if ( IS_DC && !strequal(domain, lp_workgroup()) ) {
+ char *pass = NULL;
+
+ if ( !secrets_fetch_trusted_domain_password( domain,
+ &pass, &sid, &lct) )
+ {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ sec_channel_type = SEC_CHAN_DOMAIN;
+ E_md4hash(pass, trust_password);
+ SAFE_FREE( pass );
+
+ } else {
+ if (!secrets_fetch_trust_account_password(lp_workgroup(),
+ trust_password, NULL, &sec_channel_type))
+ {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
}
ret = cli_nt_setup_netsec(cli, sec_channel_type,
- AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN,
- trust_password);
+ AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password);
return ret;
}
@@ -216,7 +235,8 @@ static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const i
/* Initialise SMB connection */
fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index));
-/* grab stored passwords */
+ /* grab stored passwords */
+
machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) {
@@ -335,9 +355,13 @@ static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const i
/* try and use schannel if possible, but continue anyway if it
failed. This allows existing setups to continue working,
while solving the win2003 '100 user' limit for systems that
- are joined properly */
- if (NT_STATUS_IS_OK(result) && (domain->primary)) {
- NTSTATUS status = setup_schannel(new_conn->cli);
+ are joined properly.
+
+ Only do this for our own domain or perhaps a trusted domain
+ if we are on a Samba DC */
+
+ if (NT_STATUS_IS_OK(result) && (domain->primary || IS_DC) ) {
+ NTSTATUS status = setup_schannel( new_conn->cli, domain->name );
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3,("schannel refused - continuing without schannel (%s)\n",
nt_errstr(status)));
diff --git a/source/nsswitch/winbindd_group.c b/source/nsswitch/winbindd_group.c
index 7b4529144e2..346a2711b6c 100644
--- a/source/nsswitch/winbindd_group.c
+++ b/source/nsswitch/winbindd_group.c
@@ -942,16 +942,14 @@ static void add_gid_to_array_unique(gid_t gid, gid_t **gids, int *num)
*num += 1;
}
-static void add_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num)
+static void add_local_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num)
{
gid_t gid;
DOM_SID *aliases;
int j, num_aliases;
- DEBUG(10, ("Adding gids from SID: %s\n", sid_string_static(sid)));
-
- if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &gid, 0)))
- add_gid_to_array_unique(gid, gids, num);
+ DEBUG(10, ("Adding local gids from SID: %s\n",
+ sid_string_static(sid)));
/* Don't expand aliases if not explicitly activated -- for now
-- jerry */
@@ -965,15 +963,44 @@ static void add_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num)
return;
for (j=0; j<num_aliases; j++) {
+ enum SID_NAME_USE type;
+
+ if (!local_sid_to_gid(&gid, &aliases[j], &type)) {
+ DEBUG(1, ("Got an alias membership with no alias\n"));
+ continue;
+ }
- if (!NT_STATUS_IS_OK(sid_to_gid(&aliases[j], &gid)))
+ if ((type != SID_NAME_ALIAS) && (type != SID_NAME_WKN_GRP)) {
+ DEBUG(1, ("Got an alias membership in a non-alias\n"));
continue;
+ }
add_gid_to_array_unique(gid, gids, num);
}
SAFE_FREE(aliases);
}
+static void add_gids_from_user_sid(DOM_SID *sid, gid_t **gids, int *num)
+{
+ DEBUG(10, ("Adding gids from user SID: %s\n",
+ sid_string_static(sid)));
+
+ add_local_gids_from_sid(sid, gids, num);
+}
+
+static void add_gids_from_group_sid(DOM_SID *sid, gid_t **gids, int *num)
+{
+ gid_t gid;
+
+ DEBUG(10, ("Adding gids from group SID: %s\n",
+ sid_string_static(sid)));
+
+ if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &gid, 0)))
+ add_gid_to_array_unique(gid, gids, num);
+
+ add_local_gids_from_sid(sid, gids, num);
+}
+
/* Get user supplementary groups. This is much quicker than trying to
invert the groups database. We merge the groups from the gids and
other_sids info3 fields as trusted domain, universal group
@@ -1039,7 +1066,7 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
goto done;
}
- add_gids_from_sid(&user_sid, &gid_list, &num_gids);
+ add_gids_from_user_sid(&user_sid, &gid_list, &num_gids);
/* Treat the info3 cache as authoritative as the
lookup_usergroups() function may return cached data. */
@@ -1083,8 +1110,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
continue;
}
- add_gids_from_sid(&info3->other_sids[i].sid,
- &gid_list, &num_gids);
+ add_gids_from_group_sid(&info3->other_sids[i].sid,
+ &gid_list, &num_gids);
if (gid_list == NULL)
goto done;
@@ -1097,7 +1124,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
sid_copy( &group_sid, &domain->sid );
sid_append_rid( &group_sid, info3->gids[i].g_rid );
- add_gids_from_sid(&group_sid, &gid_list, &num_gids);
+ add_gids_from_group_sid(&group_sid, &gid_list,
+ &num_gids);
if (gid_list == NULL)
goto done;
@@ -1116,8 +1144,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
goto done;
for (i = 0; i < num_groups; i++) {
- add_gids_from_sid(user_grpsids[i],
- &gid_list, &num_gids);
+ add_gids_from_group_sid(user_grpsids[i],
+ &gid_list, &num_gids);
if (gid_list == NULL)
goto done;
diff --git a/source/nsswitch/winbindd_passdb.c b/source/nsswitch/winbindd_passdb.c
index 12f5e0bae2e..3adb81caa35 100644
--- a/source/nsswitch/winbindd_passdb.c
+++ b/source/nsswitch/winbindd_passdb.c
@@ -240,7 +240,11 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
if (!pdb_find_alias(name, sid))
return NT_STATUS_NONE_MAPPED;
- *type = SID_NAME_ALIAS;
+ if (sid_check_is_in_builtin(sid))
+ *type = SID_NAME_WKN_GRP;
+ else
+ *type = SID_NAME_ALIAS;
+
return NT_STATUS_OK;
}
@@ -263,7 +267,10 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain,
*domain_name = talloc_strdup(mem_ctx, domain->name);
*name = talloc_strdup(mem_ctx, info.acct_name);
- *type = SID_NAME_ALIAS;
+ if (sid_check_is_in_builtin(sid))
+ *type = SID_NAME_WKN_GRP;
+ else
+ *type = SID_NAME_ALIAS;
return NT_STATUS_OK;
}
diff --git a/source/nsswitch/winbindd_rpc.c b/source/nsswitch/winbindd_rpc.c
index 76688449209..ba24749fbef 100644
--- a/source/nsswitch/winbindd_rpc.c
+++ b/source/nsswitch/winbindd_rpc.c
@@ -707,36 +707,6 @@ done:
#include <ldap.h>
-static SIG_ATOMIC_T gotalarm;
-
-/***************************************************************
- Signal function to tell us we timed out.
-****************************************************************/
-
-static void gotalarm_sig(void)
-{
- gotalarm = 1;
-}
-
-static LDAP *ldap_open_with_timeout(const char *server, int port, unsigned int to)
-{
- LDAP *ldp = NULL;
-
- /* Setup timeout */
- gotalarm = 0;
- CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
- alarm(to);
- /* End setup timeout. */
-
- ldp = ldap_open(server, port);
-
- /* Teardown timeout. */
- CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
- alarm(0);
-
- return ldp;
-}
-
static int get_ldap_seq(const char *server, int port, uint32 *seq)
{
int ret = -1;
@@ -749,11 +719,11 @@ static int get_ldap_seq(const char *server, int port, uint32 *seq)
*seq = DOM_SEQUENCE_NONE;
/*
- * 10 second timeout on open. This is needed as the search timeout
+ * Parameterised (5) second timeout on open. This is needed as the search timeout
* doesn't seem to apply to doing an open as well. JRA.
*/
- if ((ldp = ldap_open_with_timeout(server, port, 10)) == NULL)
+ if ((ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout())) == NULL)
return -1;
/* Timeout if no response within 20 seconds. */
diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c
index 96b8ed8c938..faa6e8d8da4 100644
--- a/source/nsswitch/winbindd_util.c
+++ b/source/nsswitch/winbindd_util.c
@@ -175,7 +175,7 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
/* Link to domain list */
DLIST_ADD(_domain_list, domain);
- DEBUG(1,("Added domain %s %s %s\n",
+ DEBUG(2,("Added domain %s %s %s\n",
domain->name, domain->alt_name,
&domain->sid?sid_string_static(&domain->sid):""));
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index 6376e4aa917..0710c36514b 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -231,8 +231,10 @@ typedef struct
char *szLdapFilter;
char *szLdapAdminDn;
char *szAclCompat;
+ char *szCupsServer;
int ldap_passwd_sync;
int ldap_replication_sleep;
+ int ldap_timeout; /* This is initialised in init_globals */
BOOL ldap_delete_dn;
BOOL bMsAddPrinterWizard;
BOOL bDNSproxy;
@@ -286,6 +288,8 @@ typedef struct
BOOL bUnixExtensions;
BOOL bDisableNetbios;
BOOL bKernelChangeNotify;
+ BOOL bUseKerberosKeytab;
+ BOOL bDeferSharingViolations;
int restrict_anonymous;
int name_cache_timeout;
int client_signing;
@@ -363,7 +367,7 @@ typedef struct
int iBlock_size;
BOOL bPreexecClose;
BOOL bRootpreexecClose;
- BOOL bCaseSensitive;
+ int iCaseSensitive;
BOOL bCasePreserve;
BOOL bShortCasePreserve;
BOOL bHideDotFiles;
@@ -410,6 +414,7 @@ typedef struct
BOOL bUseClientDriver;
BOOL bDefaultDevmode;
BOOL bNTAclSupport;
+ BOOL bForceUnknownAclUser;
BOOL bUseSendfile;
BOOL bProfileAcls;
BOOL bMap_acl_inherit;
@@ -486,7 +491,7 @@ static service sDefault = {
1024, /* iBlock_size */
False, /* bPreexecClose */
False, /* bRootpreexecClose */
- False, /* case sensitive */
+ Auto, /* case sensitive */
True, /* case preserve */
True, /* short case preserve */
True, /* bHideDotFiles */
@@ -533,7 +538,8 @@ static service sDefault = {
False, /* bUseClientDriver */
False, /* bDefaultDevmode */
True, /* bNTAclSupport */
- False, /* bUseSendfile */
+ False, /* bForceUnknownAclUser */
+ True, /* bUseSendfile */
False, /* bProfileAcls */
False, /* bMap_acl_inherit */
False, /* bAfs_Share */
@@ -846,6 +852,7 @@ static struct parm_struct parm_table[] = {
{"force directory mode", P_OCTAL, P_LOCAL, &sDefault.iDir_force_mode, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
{"directory security mask", P_OCTAL, P_LOCAL, &sDefault.iDir_Security_mask, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
{"force directory security mode", P_OCTAL, P_LOCAL, &sDefault.iDir_Security_force_mode, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
+ {"force unknown acl user", P_BOOL, P_LOCAL, &sDefault.bForceUnknownAclUser, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
{"inherit permissions", P_BOOL, P_LOCAL, &sDefault.bInheritPerms, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE},
{"inherit acls", P_BOOL, P_LOCAL, &sDefault.bInheritACLS, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE},
{"guest only", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE},
@@ -860,6 +867,7 @@ static struct parm_struct parm_table[] = {
{"hosts deny", P_LIST, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, FLAG_GLOBAL | FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT},
{"deny hosts", P_LIST, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, FLAG_HIDE},
{"preload modules", P_LIST, P_GLOBAL, &Globals.szPreloadModules, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL},
+ {"use kerberos keytab", P_BOOL, P_GLOBAL, &Globals.bUseKerberosKeytab, NULL, NULL, FLAG_ADVANCED},
{N_("Logging Options"), P_SEP, P_SEPARATOR},
@@ -889,6 +897,7 @@ static struct parm_struct parm_table[] = {
{"disable netbios", P_BOOL, P_GLOBAL, &Globals.bDisableNetbios, NULL, NULL, FLAG_ADVANCED},
{"acl compatibility", P_STRING, P_GLOBAL, &Globals.szAclCompat, handle_acl_compatibility, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
+ { "defer sharing violations", P_BOOL, P_GLOBAL, &Globals.bDeferSharingViolations, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL},
{"ea support", P_BOOL, P_LOCAL, &sDefault.bEASupport, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
{"nt acl support", P_BOOL, P_LOCAL, &sDefault.bNTAclSupport, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
{"nt pipe support", P_BOOL, P_GLOBAL, &Globals.bNTPipeSupport, NULL, NULL, FLAG_ADVANCED},
@@ -953,6 +962,7 @@ static struct parm_struct parm_table[] = {
{"print ok", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL, FLAG_HIDE},
{"printing", P_ENUM, P_LOCAL, &sDefault.iPrinting, handle_printing, enum_printing, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL},
{"cups options", P_STRING, P_LOCAL, &sDefault.szCupsOptions, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL},
+ {"cups server", P_STRING, P_GLOBAL, &Globals.szCupsServer, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL},
{"print command", P_STRING, P_LOCAL, &sDefault.szPrintcommand, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL},
{"disable spoolss", P_BOOL, P_GLOBAL, &Globals.bDisableSpoolss, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL},
{"lpq command", P_STRING, P_LOCAL, &sDefault.szLpqcommand, NULL, NULL, FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL},
@@ -978,8 +988,8 @@ static struct parm_struct parm_table[] = {
{"mangle prefix", P_INTEGER, P_GLOBAL, &Globals.mangle_prefix, NULL, NULL, FLAG_ADVANCED},
{"default case", P_ENUM, P_LOCAL, &sDefault.iDefaultCase, NULL, enum_case, FLAG_ADVANCED | FLAG_SHARE},
- {"case sensitive", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
- {"casesignames", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL, NULL, FLAG_HIDE},
+ {"case sensitive", P_ENUM, P_LOCAL, &sDefault.iCaseSensitive, NULL, enum_bool_auto, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
+ {"casesignames", P_ENUM, P_LOCAL, &sDefault.iCaseSensitive, NULL, enum_bool_auto, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL | FLAG_HIDE},
{"preserve case", P_BOOL, P_LOCAL, &sDefault.bCasePreserve, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
{"short preserve case", P_BOOL, P_LOCAL, &sDefault.bShortCasePreserve, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
{"mangling char", P_CHAR, P_LOCAL, &sDefault.magic_char, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
@@ -1070,17 +1080,18 @@ static struct parm_struct parm_table[] = {
{"ldap server", P_STRING, P_GLOBAL, &Globals.szLdapServer, NULL, NULL, FLAG_ADVANCED},
{"ldap port", P_INTEGER, P_GLOBAL, &Globals.ldap_port, NULL, NULL, FLAG_ADVANCED},
#endif
- {"ldap suffix", P_STRING, P_GLOBAL, &Globals.szLdapSuffix, NULL, NULL, FLAG_ADVANCED},
- {"ldap machine suffix", P_STRING, P_GLOBAL, &Globals.szLdapMachineSuffix, NULL, NULL, FLAG_ADVANCED},
- {"ldap user suffix", P_STRING, P_GLOBAL, &Globals.szLdapUserSuffix, NULL, NULL, FLAG_ADVANCED},
+ {"ldap admin dn", P_STRING, P_GLOBAL, &Globals.szLdapAdminDn, NULL, NULL, FLAG_ADVANCED},
+ {"ldap delete dn", P_BOOL, P_GLOBAL, &Globals.ldap_delete_dn, NULL, NULL, FLAG_ADVANCED},
+ {"ldap filter", P_STRING, P_GLOBAL, &Globals.szLdapFilter, NULL, NULL, FLAG_ADVANCED},
{"ldap group suffix", P_STRING, P_GLOBAL, &Globals.szLdapGroupSuffix, NULL, NULL, FLAG_ADVANCED},
{"ldap idmap suffix", P_STRING, P_GLOBAL, &Globals.szLdapIdmapSuffix, NULL, NULL, FLAG_ADVANCED},
- {"ldap filter", P_STRING, P_GLOBAL, &Globals.szLdapFilter, NULL, NULL, FLAG_ADVANCED},
- {"ldap admin dn", P_STRING, P_GLOBAL, &Globals.szLdapAdminDn, NULL, NULL, FLAG_ADVANCED},
- {"ldap ssl", P_ENUM, P_GLOBAL, &Globals.ldap_ssl, NULL, enum_ldap_ssl, FLAG_ADVANCED},
+ {"ldap machine suffix", P_STRING, P_GLOBAL, &Globals.szLdapMachineSuffix, NULL, NULL, FLAG_ADVANCED},
{"ldap passwd sync", P_ENUM, P_GLOBAL, &Globals.ldap_passwd_sync, NULL, enum_ldap_passwd_sync, FLAG_ADVANCED},
- {"ldap delete dn", P_BOOL, P_GLOBAL, &Globals.ldap_delete_dn, NULL, NULL, FLAG_ADVANCED},
{"ldap replication sleep", P_INTEGER, P_GLOBAL, &Globals.ldap_replication_sleep, NULL, NULL, FLAG_ADVANCED},
+ {"ldap suffix", P_STRING, P_GLOBAL, &Globals.szLdapSuffix, NULL, NULL, FLAG_ADVANCED},
+ {"ldap ssl", P_ENUM, P_GLOBAL, &Globals.ldap_ssl, NULL, enum_ldap_ssl, FLAG_ADVANCED},
+ {"ldap timeout", P_INTEGER, P_GLOBAL, &Globals.ldap_timeout, NULL, NULL, FLAG_ADVANCED},
+ {"ldap user suffix", P_STRING, P_GLOBAL, &Globals.szLdapUserSuffix, NULL, NULL, FLAG_ADVANCED},
{N_("Miscellaneous Options"), P_SEP, P_SEPARATOR},
{"add share command", P_STRING, P_GLOBAL, &Globals.szAddShareCommand, NULL, NULL, FLAG_ADVANCED},
@@ -1289,6 +1300,13 @@ static void init_globals(void)
if (!done_init) {
int i;
+
+ /* The logfile can be set before this is invoked. Free it if so. */
+ if (Globals.szLogFile != NULL) {
+ string_free(&Globals.szLogFile);
+ Globals.szLogFile = NULL;
+ }
+
memset((void *)&Globals, '\0', sizeof(Globals));
for (i = 0; parm_table[i].label; i++)
@@ -1471,6 +1489,7 @@ static void init_globals(void)
Globals.ldap_passwd_sync = LDAP_PASSWD_SYNC_OFF;
Globals.ldap_delete_dn = False;
Globals.ldap_replication_sleep = 1000; /* wait 1 sec for replication */
+ Globals.ldap_timeout = LDAP_CONNECT_DEFAULT_TIMEOUT;
/* these parameters are set to defaults that are more appropriate
for the increasing samba install base:
@@ -1506,6 +1525,7 @@ static void init_globals(void)
string_set(&Globals.szTemplatePrimaryGroup, "nobody");
string_set(&Globals.szWinbindSeparator, "\\");
string_set(&Globals.szAclCompat, "");
+ string_set(&Globals.szCupsServer, "");
Globals.winbind_cache_time = 300; /* 5 minutes */
Globals.bWinbindEnableLocalAccounts = True;
@@ -1525,6 +1545,7 @@ static void init_globals(void)
Globals.client_signing = Auto;
Globals.server_signing = False;
+ Globals.bDeferSharingViolations = True;
string_set(&Globals.smb_ports, SMB_PORTS);
}
@@ -1703,6 +1724,7 @@ FN_GLOBAL_INTEGER(lp_ldap_ssl, &Globals.ldap_ssl)
FN_GLOBAL_INTEGER(lp_ldap_passwd_sync, &Globals.ldap_passwd_sync)
FN_GLOBAL_BOOL(lp_ldap_delete_dn, &Globals.ldap_delete_dn)
FN_GLOBAL_INTEGER(lp_ldap_replication_sleep, &Globals.ldap_replication_sleep)
+FN_GLOBAL_INTEGER(lp_ldap_timeout, &Globals.ldap_timeout)
FN_GLOBAL_STRING(lp_add_share_cmd, &Globals.szAddShareCommand)
FN_GLOBAL_STRING(lp_change_share_cmd, &Globals.szChangeShareCommand)
FN_GLOBAL_STRING(lp_delete_share_cmd, &Globals.szDeleteShareCommand)
@@ -1758,6 +1780,8 @@ FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego)
FN_GLOBAL_BOOL(lp_client_use_spnego, &Globals.bClientUseSpnego)
FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups)
FN_GLOBAL_BOOL(lp_kernel_change_notify, &Globals.bKernelChangeNotify)
+FN_GLOBAL_BOOL(lp_use_kerberos_keytab, &Globals.bUseKerberosKeytab)
+FN_GLOBAL_BOOL(lp_defer_sharing_violations, &Globals.bDeferSharingViolations)
FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level)
FN_GLOBAL_INTEGER(lp_max_ttl, &Globals.max_ttl)
FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl)
@@ -1802,6 +1826,7 @@ FN_LOCAL_LIST(lp_invalid_users, szInvalidUsers)
FN_LOCAL_LIST(lp_valid_users, szValidUsers)
FN_LOCAL_LIST(lp_admin_users, szAdminUsers)
FN_LOCAL_STRING(lp_cups_options, szCupsOptions)
+FN_GLOBAL_STRING(lp_cups_server, &Globals.szCupsServer)
FN_LOCAL_STRING(lp_printcommand, szPrintcommand)
FN_LOCAL_STRING(lp_lpqcommand, szLpqcommand)
FN_LOCAL_STRING(lp_lprmcommand, szLprmcommand)
@@ -1832,7 +1857,7 @@ FN_LOCAL_BOOL(lp_msdfs_root, bMSDfsRoot)
FN_LOCAL_BOOL(lp_autoloaded, autoloaded)
FN_LOCAL_BOOL(lp_preexec_close, bPreexecClose)
FN_LOCAL_BOOL(lp_rootpreexec_close, bRootpreexecClose)
-FN_LOCAL_BOOL(lp_casesensitive, bCaseSensitive)
+FN_LOCAL_INTEGER(lp_casesensitive, iCaseSensitive)
FN_LOCAL_BOOL(lp_preservecase, bCasePreserve)
FN_LOCAL_BOOL(lp_shortpreservecase, bShortCasePreserve)
FN_LOCAL_BOOL(lp_hide_dot_files, bHideDotFiles)
@@ -1875,6 +1900,7 @@ FN_LOCAL_BOOL(lp_inherit_acls, bInheritACLS)
FN_LOCAL_BOOL(lp_use_client_driver, bUseClientDriver)
FN_LOCAL_BOOL(lp_default_devmode, bDefaultDevmode)
FN_LOCAL_BOOL(lp_nt_acl_support, bNTAclSupport)
+FN_LOCAL_BOOL(lp_force_unknown_acl_user, bForceUnknownAclUser)
FN_LOCAL_BOOL(lp_ea_support, bEASupport)
FN_LOCAL_BOOL(_lp_use_sendfile, bUseSendfile)
FN_LOCAL_BOOL(lp_profile_acls, bProfileAcls)
@@ -2315,6 +2341,8 @@ BOOL lp_add_home(const char *pszHomename, int iDefaultService,
ServicePtrs[i]->bBrowseable = sDefault.bBrowseable;
+ ServicePtrs[i]->autoloaded = True;
+
DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n", pszHomename,
user, newHomedir));
@@ -2993,10 +3021,8 @@ static void lp_set_enum_parm( struct parm_struct *parm, const char *pszParmValue
{
int i;
- for (i = 0; parm->enum_list[i].name; i++)
- {
- if ( strequal(pszParmValue, parm->enum_list[i].name))
- {
+ for (i = 0; parm->enum_list[i].name; i++) {
+ if ( strequal(pszParmValue, parm->enum_list[i].name)) {
*ptr = parm->enum_list[i].value;
break;
}
@@ -3269,9 +3295,9 @@ static void print_parameter(struct parm_struct *p, void *ptr, FILE * f)
char **list = *(char ***)ptr;
for (; *list; list++) {
- /* surround strings with whitespace in single quotes */
+ /* surround strings with whitespace in double quotes */
if ( strchr_m( *list, ' ' ) )
- fprintf(f, "\'%s\'%s", *list, ((*(list+1))?", ":""));
+ fprintf(f, "\"%s\"%s", *list, ((*(list+1))?", ":""));
else
fprintf(f, "%s%s", *list, ((*(list+1))?", ":""));
}
@@ -3697,6 +3723,10 @@ void lp_killunused(BOOL (*snumused) (int))
if (!VALID(i))
continue;
+ /* don't kill autoloaded services */
+ if ( ServicePtrs[i]->autoloaded )
+ continue;
+
if (!snumused || !snumused(i)) {
ServicePtrs[i]->valid = False;
free_service(ServicePtrs[i]);
@@ -3866,11 +3896,12 @@ BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults,
/* get the username for substituion -- preference to the current_user_info */
- if ( strlen( current_user_info.smb_name ) != 0 )
+ if ( strlen( current_user_info.smb_name ) != 0 ) {
username = current_user_info.smb_name;
- else
+ } else {
username = sub_get_smb_name();
-
+ }
+
standard_sub_basic( username, n2,sizeof(n2) );
add_to_file_list(pszFname, n2);
@@ -3885,8 +3916,7 @@ BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults,
init_globals();
debug_init();
- if (save_defaults)
- {
+ if (save_defaults) {
init_locals();
lp_save_defaults();
}
@@ -4258,7 +4288,10 @@ const char *get_called_name(void)
extern fstring local_machine;
static fstring called_name;
- if (!*local_machine) {
+ if ( (!*local_machine) ||
+ (client_socket_port() == 445) ) {
+ /* Everybody coming in on 445 should be able to live with the
+ * IP address */
fstrcpy(called_name, client_socket_addr());
DEBUG(8,("get_called_name: assuming that client used IP address [%s] as called name.\n",
called_name));
@@ -4289,3 +4322,14 @@ BOOL lp_use_sendfile(int snum)
{
return (_lp_use_sendfile(snum) && !srv_is_signing_active());
}
+
+/*******************************************************************
+ Turn off storing DOS attributes if this share doesn't support it.
+********************************************************************/
+
+void set_store_dos_attributes(int snum, BOOL val)
+{
+ if (!LP_SNUM_OK(snum))
+ return;
+ ServicePtrs[(snum)]->bStoreDosAttributes = val;
+}
diff --git a/source/passdb/login_cache.c b/source/passdb/login_cache.c
index fc05122ccaf..0d782912b17 100644
--- a/source/passdb/login_cache.c
+++ b/source/passdb/login_cache.c
@@ -95,10 +95,13 @@ LOGIN_CACHE * login_cache_read(SAM_ACCOUNT *sampass)
&entry->bad_password_count,
&entry->bad_password_time) == -1) {
DEBUG(7, ("No cache entry found\n"));
+ SAFE_FREE(entry);
SAFE_FREE(databuf.dptr);
return NULL;
}
+ SAFE_FREE(databuf.dptr);
+
DEBUG(5, ("Found login cache entry: timestamp %12u, flags 0x%x, count %d, time %12u\n",
(unsigned int)entry->entry_timestamp, entry->acct_ctrl,
entry->bad_password_count, (unsigned int)entry->bad_password_time));
diff --git a/source/passdb/lookup_sid.c b/source/passdb/lookup_sid.c
index 842db8de5dc..d536383ef3e 100644
--- a/source/passdb/lookup_sid.c
+++ b/source/passdb/lookup_sid.c
@@ -445,14 +445,11 @@ NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
* Group mapping can deal with foreign SIDs
*/
+ if ( local_sid_to_gid(pgid, psid, &name_type) )
+ goto success;
+
if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
- DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
- sid_to_string(sid_str, psid) ));
-
- if ( local_sid_to_gid(pgid, psid, &name_type) )
- goto success;
-
- DEBUG(10,("sid_to_gid: no one knows this SID\n"));
+ DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then winbind)\n", sid_to_string(sid_str, psid)));
return NT_STATUS_UNSUCCESSFUL;
}
diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c
index 75f8171a25d..c3a423c2636 100644
--- a/source/passdb/passdb.c
+++ b/source/passdb/passdb.c
@@ -1287,6 +1287,7 @@ BOOL local_sid_to_gid(gid_t *pgid, const DOM_SID *psid, enum SID_NAME_USE *name_
}
*pgid = group.gid;
+ *name_type = group.sid_name_use;
DEBUG(10,("local_sid_to_gid: SID %s -> gid (%u)\n", sid_string_static(psid),
(unsigned int)*pgid));
diff --git a/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c
index 15635a034cc..d2ee9a2d9dc 100644
--- a/source/passdb/pdb_ldap.c
+++ b/source/passdb/pdb_ldap.c
@@ -1043,9 +1043,13 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
DEBUG(7, ("bad password count is reset, deleting login cache entry for %s\n", pdb_get_nt_username(sampass)));
login_cache_delentry(sampass);
} else {
- LOGIN_CACHE cache_entry ={time(NULL),
- pdb_get_acct_ctrl(sampass),
- badcount, badtime};
+ LOGIN_CACHE cache_entry;
+
+ cache_entry.entry_timestamp = time(NULL);
+ cache_entry.acct_ctrl = pdb_get_acct_ctrl(sampass);
+ cache_entry.bad_password_count = badcount;
+ cache_entry.bad_password_time = badtime;
+
DEBUG(7, ("Updating bad password count and time in login cache\n"));
login_cache_write(sampass, cache_entry);
}
@@ -1130,6 +1134,19 @@ static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT
return NT_STATUS_OK;
}
+static void append_attr(char ***attr_list, const char *new_attr)
+{
+ int i;
+
+ for (i=0; (*attr_list)[i] != NULL; i++)
+ ;
+
+ (*attr_list) = Realloc((*attr_list), sizeof(**attr_list) * (i+2));
+ SMB_ASSERT((*attr_list) != NULL);
+ (*attr_list)[i] = strdup(new_attr);
+ (*attr_list)[i+1] = NULL;
+}
+
/**********************************************************************
Get SAM_ACCOUNT entry from LDAP by username.
*********************************************************************/
@@ -1145,6 +1162,7 @@ static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT
int rc;
attr_list = get_userattr_list( ldap_state->schema_ver );
+ append_attr(&attr_list, MODIFY_TIMESTAMP_STRING);
rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list);
free_attr_list( attr_list );
@@ -1190,6 +1208,7 @@ static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state,
switch ( ldap_state->schema_ver ) {
case SCHEMAVER_SAMBASAMACCOUNT:
attr_list = get_userattr_list(ldap_state->schema_ver);
+ append_attr(&attr_list, MODIFY_TIMESTAMP_STRING);
rc = ldapsam_search_suffix_by_sid(ldap_state, sid, result, attr_list);
free_attr_list( attr_list );
diff --git a/source/printing/notify.c b/source/printing/notify.c
index 26ef191f877..8d5be136071 100644
--- a/source/printing/notify.c
+++ b/source/printing/notify.c
@@ -278,7 +278,7 @@ in notify_queue\n", msg->type, msg->field, msg->printer));
return;
}
copy_notify2_msg(pnqueue->msg, msg);
- gettimeofday(&pnqueue->tv, NULL);
+ GetTimeOfDay(&pnqueue->tv);
pnqueue->buf = NULL;
pnqueue->buflen = 0;
diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c
index 909aed6c866..225ff20ec3e 100644
--- a/source/printing/nt_printing.c
+++ b/source/printing/nt_printing.c
@@ -1003,9 +1003,9 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
fsp = open_file_shared(conn, filepath, &stat_buf,
- SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
+ FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action);
if (!fsp) {
/* Old file not found, so by definition new file is in fact newer */
DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
@@ -1032,9 +1032,9 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
fsp = open_file_shared(conn, filepath, &stat_buf,
- SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
+ FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action);
if (!fsp) {
/* New file not found, this shouldn't occur if the caller did its job */
DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
@@ -1148,9 +1148,9 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_
driver_unix_convert(driverpath,conn,NULL,&bad_path,&st);
fsp = open_file_shared(conn, driverpath, &st,
- SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
+ FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action);
if (!fsp) {
DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
driverpath, errno));
diff --git a/source/printing/print_cups.c b/source/printing/print_cups.c
index 9a48296543d..3097811fac2 100644
--- a/source/printing/print_cups.c
+++ b/source/printing/print_cups.c
@@ -65,6 +65,17 @@ cups_passwd_cb(const char *prompt) /* I - Prompt */
return (NULL);
}
+static const char *cups_server(void)
+{
+ if ((lp_cups_server() != NULL) && (strlen(lp_cups_server()) > 0)) {
+ DEBUG(10, ("cups server explicitly set to %s\n",
+ lp_cups_server()));
+ return lp_cups_server();
+ }
+
+ DEBUG(10, ("cups server left to default %s\n", cupsServer()));
+ return cupsServer();
+}
/*
* 'cups_printer_fn()' - Call a function for every printer known to the
@@ -102,10 +113,10 @@ void cups_printer_fn(void (*fn)(char *, char *))
* Try to connect to the server...
*/
- if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ if ((http = httpConnect(cups_server(), ippPort())) == NULL)
{
DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
- cupsServer(), strerror(errno)));
+ cups_server(), strerror(errno)));
return;
}
@@ -331,10 +342,10 @@ int cups_printername_ok(const char *name)
* Try to connect to the server...
*/
- if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ if ((http = httpConnect(cups_server(), ippPort())) == NULL)
{
DEBUG(3,("Unable to connect to CUPS server %s - %s\n",
- cupsServer(), strerror(errno)));
+ cups_server(), strerror(errno)));
return (0);
}
@@ -425,10 +436,10 @@ cups_job_delete(int snum, struct printjob *pjob)
* Try to connect to the server...
*/
- if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ if ((http = httpConnect(cups_server(), ippPort())) == NULL)
{
DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
- cupsServer(), strerror(errno)));
+ cups_server(), strerror(errno)));
return (1);
}
@@ -515,10 +526,10 @@ cups_job_pause(int snum, struct printjob *pjob)
* Try to connect to the server...
*/
- if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ if ((http = httpConnect(cups_server(), ippPort())) == NULL)
{
DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
- cupsServer(), strerror(errno)));
+ cups_server(), strerror(errno)));
return (1);
}
@@ -605,10 +616,10 @@ cups_job_resume(int snum, struct printjob *pjob)
* Try to connect to the server...
*/
- if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ if ((http = httpConnect(cups_server(), ippPort())) == NULL)
{
DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
- cupsServer(), strerror(errno)));
+ cups_server(), strerror(errno)));
return (1);
}
@@ -698,10 +709,10 @@ cups_job_submit(int snum, struct printjob *pjob)
* Try to connect to the server...
*/
- if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ if ((http = httpConnect(cups_server(), ippPort())) == NULL)
{
DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
- cupsServer(), strerror(errno)));
+ cups_server(), strerror(errno)));
return (1);
}
@@ -848,10 +859,10 @@ cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status)
* Try to connect to the server...
*/
- if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ if ((http = httpConnect(cups_server(), ippPort())) == NULL)
{
DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
- cupsServer(), strerror(errno)));
+ cups_server(), strerror(errno)));
return (0);
}
@@ -1153,10 +1164,10 @@ cups_queue_pause(int snum)
* Try to connect to the server...
*/
- if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ if ((http = httpConnect(cups_server(), ippPort())) == NULL)
{
DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
- cupsServer(), strerror(errno)));
+ cups_server(), strerror(errno)));
return (1);
}
@@ -1245,10 +1256,10 @@ cups_queue_resume(int snum)
* Try to connect to the server...
*/
- if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ if ((http = httpConnect(cups_server(), ippPort())) == NULL)
{
DEBUG(0,("Unable to connect to CUPS server %s - %s\n",
- cupsServer(), strerror(errno)));
+ cups_server(), strerror(errno)));
return (1);
}
diff --git a/source/printing/printing.c b/source/printing/printing.c
index 2274e2d5f45..8beea9d0cec 100644
--- a/source/printing/printing.c
+++ b/source/printing/printing.c
@@ -23,6 +23,9 @@
#include "includes.h"
#include "printing.h"
+extern SIG_ATOMIC_T got_sig_term;
+extern SIG_ATOMIC_T reload_after_sighup;
+
/* Current printer interface */
static BOOL remove_from_jobs_changed(int snum, uint32 jobid);
@@ -597,6 +600,7 @@ void pjob_delete(int snum, uint32 jobid)
tdb_delete(pdb->tdb, print_key(jobid));
release_print_db(pdb);
rap_jobid_delete(snum, jobid);
+ remove_from_jobs_changed( snum, jobid );
}
/****************************************************************************
@@ -1195,6 +1199,22 @@ void start_background_queue(void)
DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
while (1) {
pause();
+
+ /* check for some essential signals first */
+
+ if (got_sig_term) {
+ exit_server("Caught TERM signal");
+ }
+
+ if (reload_after_sighup) {
+ change_to_root_user();
+ DEBUG(1,("Reloading services after SIGHUP\n"));
+ reload_services(False);
+ reload_after_sighup = 0;
+ }
+
+ /* now check for messages */
+
DEBUG(10,("start_background_queue: background LPQ thread got a message\n"));
message_dispatch();
}
@@ -1211,9 +1231,13 @@ static void print_queue_update(int snum)
* Otherwise just do the update ourselves
*/
- if ( background_lpq_updater_pid != -1 )
- message_send_pid(background_lpq_updater_pid, MSG_PRINTER_UPDATE, &snum, sizeof(snum), False);
- else
+ if ( background_lpq_updater_pid != -1 ) {
+ become_root();
+ message_send_pid(background_lpq_updater_pid,
+ MSG_PRINTER_UPDATE, &snum, sizeof(snum),
+ False);
+ unbecome_root();
+ } else
print_queue_update_internal( snum );
}
diff --git a/source/printing/printing_db.c b/source/printing/printing_db.c
index d402aa366f4..9efb3e8eadf 100644
--- a/source/printing/printing_db.c
+++ b/source/printing/printing_db.c
@@ -96,8 +96,8 @@ struct tdb_print_db *get_print_db_byname(const char *printername)
done_become_root = True;
}
- p->tdb = tdb_open_ex(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT,
- 0600, smbd_tdb_log);
+ p->tdb = tdb_open_log(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT,
+ 0600);
if (done_become_root)
unbecome_root();
diff --git a/source/rpc_client/cli_netlogon.c b/source/rpc_client/cli_netlogon.c
index f6d88a19501..02d2611d88c 100644
--- a/source/rpc_client/cli_netlogon.c
+++ b/source/rpc_client/cli_netlogon.c
@@ -91,18 +91,25 @@ NTSTATUS cli_net_auth2(struct cli_state *cli,
NET_Q_AUTH_2 q;
NET_R_AUTH_2 r;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ fstring machine_acct;
prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+ if ( sec_chan == SEC_CHAN_DOMAIN )
+ fstr_sprintf( machine_acct, "%s$", lp_workgroup() );
+ else
+ fstrcpy( machine_acct, cli->mach_acct );
+
/* create and send a MSRPC command with api NET_AUTH2 */
DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
- cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname(),
+ cli->srv_name_slash, machine_acct, sec_chan, global_myname(),
credstr(cli->clnt_cred.challenge.data), *neg_flags));
/* store the parameters */
- init_q_auth_2(&q, cli->srv_name_slash, cli->mach_acct,
+
+ init_q_auth_2(&q, cli->srv_name_slash, machine_acct,
sec_chan, global_myname(), &cli->clnt_cred.challenge,
*neg_flags);
diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c
index b24dbb7d25d..0720f872419 100644
--- a/source/rpc_client/cli_pipe.c
+++ b/source/rpc_client/cli_pipe.c
@@ -1233,10 +1233,12 @@ static BOOL valid_pipe_name(const int pipe_idx, RPC_IFACE *abstract, RPC_IFACE *
static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, const int pipe_idx, RPC_IFACE *transfer)
{
-# if 0 /* JERRY -- apparently ASU forgets to fill in the server pipe name sometimes */
- if ( hdr_ba->addr.len <= 0)
- return False;
+ if ( hdr_ba->addr.len == 0) {
+ DEBUG(4,("Ignoring length check -- ASU bug (server didn't fill in the pipe name correctly)"));
+ }
+
+# if 0 /* JERRY -- apparently ASU forgets to fill in the server pipe name sometimes */
if ( !strequal(hdr_ba->addr.str, pipe_names[pipe_idx].client_pipe) &&
!strequal(hdr_ba->addr.str, pipe_names[pipe_idx].server_pipe) )
{
@@ -1621,9 +1623,6 @@ NTSTATUS cli_nt_setup_netsec(struct cli_state *cli, int sec_chan, int auth_flags
return NT_STATUS_UNSUCCESSFUL;
}
- if (lp_client_schannel() != False)
- neg_flags |= NETLOGON_NEG_SCHANNEL;
-
neg_flags |= NETLOGON_NEG_SCHANNEL;
result = cli_nt_setup_creds(cli, sec_chan, trust_password,
diff --git a/source/rpc_parse/parse_net.c b/source/rpc_parse/parse_net.c
index 36d55c7bf67..b42b9b2a8b4 100644
--- a/source/rpc_parse/parse_net.c
+++ b/source/rpc_parse/parse_net.c
@@ -182,6 +182,50 @@ static BOOL net_io_netinfo_2(const char *desc, NETLOGON_INFO_2 *info, prs_struct
return True;
}
+static BOOL net_io_ctrl_data_info_5(const char *desc, CTRL_DATA_INFO_5 *info, prs_struct *ps, int depth)
+{
+ if (info == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_ctrl_data_info_5");
+ depth++;
+
+ if ( !prs_uint32( "function_code", ps, depth, &info->function_code ) )
+ return False;
+
+ if(!prs_uint32("ptr_domain", ps, depth, &info->ptr_domain))
+ return False;
+
+ if ( info->ptr_domain ) {
+ if(!smb_io_unistr2("domain", &info->domain, info->ptr_domain, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
+static BOOL net_io_ctrl_data_info_6(const char *desc, CTRL_DATA_INFO_6 *info, prs_struct *ps, int depth)
+{
+ if (info == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "net_io_ctrl_data_info_6");
+ depth++;
+
+ if ( !prs_uint32( "function_code", ps, depth, &info->function_code ) )
+ return False;
+
+ if(!prs_uint32("ptr_domain", ps, depth, &info->ptr_domain))
+ return False;
+
+ if ( info->ptr_domain ) {
+ if(!smb_io_unistr2("domain", &info->domain, info->ptr_domain, ps, depth))
+ return False;
+ }
+
+ return True;
+}
+
/*******************************************************************
Reads or writes an NET_Q_LOGON_CTRL2 structure.
********************************************************************/
@@ -210,9 +254,23 @@ BOOL net_io_q_logon_ctrl2(const char *desc, NET_Q_LOGON_CTRL2 *q_l, prs_struct *
return False;
if(!prs_uint32("query_level ", ps, depth, &q_l->query_level))
return False;
- if(!prs_uint32("switch_value ", ps, depth, &q_l->switch_value))
- return False;
+ switch ( q_l->function_code ) {
+ case NETLOGON_CONTROL_REDISCOVER:
+ if ( !net_io_ctrl_data_info_5( "ctrl_data_info5", &q_l->info.info5, ps, depth) )
+ return False;
+ break;
+
+ case NETLOGON_CONTROL_TC_QUERY:
+ if ( !net_io_ctrl_data_info_6( "ctrl_data_info6", &q_l->info.info6, ps, depth) )
+ return False;
+ break;
+ default:
+ DEBUG(0,("net_io_q_logon_ctrl2: unknown function_code [%d]\n",
+ q_l->function_code));
+ return False;
+ }
+
return True;
}
@@ -227,7 +285,6 @@ void init_net_q_logon_ctrl2(NET_Q_LOGON_CTRL2 *q_l, const char *srv_name,
q_l->function_code = 0x01;
q_l->query_level = query_level;
- q_l->switch_value = 0x01;
init_unistr2(&q_l->uni_server_name, srv_name, UNI_STR_TERMINATE);
}
@@ -241,9 +298,7 @@ void init_net_r_logon_ctrl2(NET_R_LOGON_CTRL2 *r_l, uint32 query_level,
uint32 logon_attempts, uint32 tc_status,
const char *trusted_domain_name)
{
- DEBUG(5,("init_r_logon_ctrl2\n"));
-
- r_l->switch_value = query_level; /* should only be 0x1 */
+ r_l->switch_value = query_level;
switch (query_level) {
case 1:
diff --git a/source/rpc_parse/parse_prs.c b/source/rpc_parse/parse_prs.c
index 0e5a25fe8c2..92c5b13632a 100644
--- a/source/rpc_parse/parse_prs.c
+++ b/source/rpc_parse/parse_prs.c
@@ -1101,10 +1101,13 @@ BOOL prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str)
/* the test of the value of *ptr helps to catch the circumstance
where we have an emtpty (non-existent) string in the buffer */
- for ( ptr = (uint16 *)q; *ptr && (alloc_len <= max_len); alloc_len++)
+ for ( ptr = (uint16 *)q; *ptr++ && (alloc_len <= max_len); alloc_len++)
/* do nothing */
;
+ if (alloc_len < max_len)
+ alloc_len += 1;
+
/* should we allocate anything at all? */
str->buffer = (uint16 *)prs_alloc_mem(ps,alloc_len * sizeof(uint16));
if ((str->buffer == NULL) && (alloc_len > 0))
diff --git a/source/rpc_parse/parse_samr.c b/source/rpc_parse/parse_samr.c
index 85eedc7baab..bb4c94404b0 100644
--- a/source/rpc_parse/parse_samr.c
+++ b/source/rpc_parse/parse_samr.c
@@ -2204,12 +2204,17 @@ reads or writes a structure.
BOOL samr_io_group_info1(const char *desc, GROUP_INFO1 * gr1,
prs_struct *ps, int depth)
{
+ uint16 dummy = 1;
+
if (gr1 == NULL)
return False;
prs_debug(ps, depth, desc, "samr_io_group_info1");
depth++;
+ if(!prs_uint16("level", ps, depth, &dummy))
+ return False;
+
if(!prs_align(ps))
return False;
@@ -2236,6 +2241,43 @@ BOOL samr_io_group_info1(const char *desc, GROUP_INFO1 * gr1,
}
/*******************************************************************
+inits a GROUP_INFO2 structure.
+********************************************************************/
+
+void init_samr_group_info2(GROUP_INFO2 * gr2, const char *acct_name)
+{
+ DEBUG(5, ("init_samr_group_info2\n"));
+
+ gr2->level = 2;
+ init_unistr2(&gr2->uni_acct_name, acct_name, UNI_FLAGS_NONE);
+ init_uni_hdr(&gr2->hdr_acct_name, &gr2->uni_acct_name);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
+BOOL samr_io_group_info2(const char *desc, GROUP_INFO2 *gr2, prs_struct *ps, int depth)
+{
+ if (gr2 == NULL)
+ return False;
+
+ prs_debug(ps, depth, desc, "samr_io_group_info2");
+ depth++;
+
+ if(!prs_uint16("hdr_level", ps, depth, &gr2->level))
+ return False;
+
+ if(!smb_io_unihdr("hdr_acct_name", &gr2->hdr_acct_name, ps, depth))
+ return False;
+ if(!smb_io_unistr2("uni_acct_name", &gr2->uni_acct_name,
+ gr2->hdr_acct_name.buffer, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
inits a GROUP_INFO3 structure.
********************************************************************/
@@ -2328,6 +2370,10 @@ static BOOL samr_group_info_ctr(const char *desc, GROUP_INFO_CTR **ctr,
if(!samr_io_group_info1("group_info1", &(*ctr)->group.info1, ps, depth))
return False;
break;
+ case 2:
+ if(!samr_io_group_info2("group_info2", &(*ctr)->group.info2, ps, depth))
+ return False;
+ break;
case 3:
if(!samr_io_group_info3("group_info3", &(*ctr)->group.info3, ps, depth))
return False;
@@ -6924,8 +6970,7 @@ BOOL samr_io_r_get_dom_pwinfo(const char *desc, SAMR_R_GET_DOM_PWINFO * r_u,
return False;
/*
- * We need 16 bytes here according to tests. Don't know
- * what they are, but the length is important for the singing
+ * see the Samba4 IDL for what these actually are.
*/
if(!prs_uint16("unk_0", ps, depth, &r_u->unk_0))
diff --git a/source/rpc_server/srv_lsa_nt.c b/source/rpc_server/srv_lsa_nt.c
index b4e29e67485..6c3157d5c95 100644
--- a/source/rpc_server/srv_lsa_nt.c
+++ b/source/rpc_server/srv_lsa_nt.c
@@ -101,7 +101,7 @@ static int init_dom_ref(DOM_R_REF *ref, char *dom_name, DOM_SID *dom_sid)
if (dom_name != NULL) {
for (num = 0; num < ref->num_ref_doms_1; num++) {
fstring domname;
- rpcstr_pull(domname, &ref->ref_dom[num].uni_dom_name, sizeof(domname), -1, 0);
+ rpcstr_pull(domname, ref->ref_dom[num].uni_dom_name.buffer, sizeof(domname), -1, 0);
if (strequal(domname, dom_name))
return num;
}
@@ -719,12 +719,12 @@ done:
/* set up the LSA Lookup RIDs response */
init_lsa_rid2s(ref, rids, num_entries, names, &mapped_count, p->endian);
- if (mapped_count == 0)
- r_u->status = NT_STATUS_NONE_MAPPED;
- else if (mapped_count != num_entries)
- r_u->status = STATUS_SOME_UNMAPPED;
- else
- r_u->status = NT_STATUS_OK;
+ if (NT_STATUS_IS_OK(r_u->status)) {
+ if (mapped_count == 0)
+ r_u->status = NT_STATUS_NONE_MAPPED;
+ else if (mapped_count != num_entries)
+ r_u->status = STATUS_SOME_UNMAPPED;
+ }
init_reply_lookup_names(r_u, ref, num_entries, rids, mapped_count);
return r_u->status;
diff --git a/source/rpc_server/srv_netlog.c b/source/rpc_server/srv_netlog.c
index f06a2002e3c..705b629732a 100644
--- a/source/rpc_server/srv_netlog.c
+++ b/source/rpc_server/srv_netlog.c
@@ -227,8 +227,6 @@ static BOOL api_net_trust_dom_list(pipes_struct *p)
ZERO_STRUCT(q_u);
ZERO_STRUCT(r_u);
- DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
-
/* grab the lsa trusted domain list query... */
if(!net_io_q_trust_dom("", &q_u, data, 0)) {
DEBUG(0,("api_net_trust_dom_list: Failed to unmarshall NET_Q_TRUST_DOM_LIST.\n"));
@@ -244,8 +242,6 @@ static BOOL api_net_trust_dom_list(pipes_struct *p)
return False;
}
- DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
-
return True;
}
@@ -263,7 +259,6 @@ static BOOL api_net_logon_ctrl2(pipes_struct *p)
ZERO_STRUCT(q_u);
ZERO_STRUCT(r_u);
- DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
/* grab the lsa netlogon ctrl2 query... */
if(!net_io_q_logon_ctrl2("", &q_u, data, 0)) {
@@ -278,8 +273,6 @@ static BOOL api_net_logon_ctrl2(pipes_struct *p)
return False;
}
- DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
-
return True;
}
@@ -297,8 +290,6 @@ static BOOL api_net_logon_ctrl(pipes_struct *p)
ZERO_STRUCT(q_u);
ZERO_STRUCT(r_u);
- DEBUG(6,("api_net_logon_ctrl: %d\n", __LINE__));
-
/* grab the lsa netlogon ctrl query... */
if(!net_io_q_logon_ctrl("", &q_u, data, 0)) {
DEBUG(0,("api_net_logon_ctrl: Failed to unmarshall NET_Q_LOGON_CTRL.\n"));
@@ -312,8 +303,6 @@ static BOOL api_net_logon_ctrl(pipes_struct *p)
return False;
}
- DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
-
return True;
}
diff --git a/source/rpc_server/srv_netlog_nt.c b/source/rpc_server/srv_netlog_nt.c
index be8eda82c90..264b7a74a79 100644
--- a/source/rpc_server/srv_netlog_nt.c
+++ b/source/rpc_server/srv_netlog_nt.c
@@ -47,6 +47,7 @@ static void init_net_r_req_chal(NET_R_REQ_CHAL *r_c,
#define ERROR_NO_SUCH_DOMAIN 0x54b
#define ERROR_NO_LOGON_SERVERS 0x51f
+#define NO_ERROR 0x0
/*************************************************************************
net_reply_logon_ctrl:
@@ -104,25 +105,67 @@ NTSTATUS _net_logon_ctrl2(pipes_struct *p, NET_Q_LOGON_CTRL2 *q_u, NET_R_LOGON_C
uint32 flags = 0x0;
uint32 pdc_connection_status = 0x0;
uint32 logon_attempts = 0x0;
- uint32 tc_status = ERROR_NO_LOGON_SERVERS;
- const char *trusted_domain = "test_domain";
+ uint32 tc_status;
+ fstring servername, domain, dc_name, dc_name2;
+ struct in_addr dc_ip;
- DEBUG(0, ("*** net long ctrl2 %d, %d, %d\n",
- q_u->function_code, q_u->query_level, q_u->switch_value));
+ /* this should be \\global_myname() */
+ unistr2_to_ascii(servername, &q_u->uni_server_name, sizeof(servername));
- DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
-
-
- /* set up the Logon Control2 response */
- init_net_r_logon_ctrl2(r_u, q_u->query_level,
- flags, pdc_connection_status, logon_attempts,
- tc_status, trusted_domain);
+ r_u->status = NT_STATUS_OK;
+
+ tc_status = ERROR_NO_SUCH_DOMAIN;
+ fstrcpy( dc_name, "" );
+
+ switch ( q_u->function_code ) {
+ case NETLOGON_CONTROL_TC_QUERY:
+ unistr2_to_ascii(domain, &q_u->info.info6.domain, sizeof(domain));
+
+ if ( !is_trusted_domain( domain ) )
+ break;
+
+ if ( !get_dc_name( domain, NULL, dc_name2, &dc_ip ) ) {
+ tc_status = ERROR_NO_LOGON_SERVERS;
+ break;
+ }
+
+ fstr_sprintf( dc_name, "\\\\%s", dc_name2 );
+
+ tc_status = NO_ERROR;
+
+ break;
+
+ case NETLOGON_CONTROL_REDISCOVER:
+ unistr2_to_ascii(domain, &q_u->info.info6.domain, sizeof(domain));
+
+ if ( !is_trusted_domain( domain ) )
+ break;
+
+ if ( !get_dc_name( domain, NULL, dc_name2, &dc_ip ) ) {
+ tc_status = ERROR_NO_LOGON_SERVERS;
+ break;
+ }
+
+ fstr_sprintf( dc_name, "\\\\%s", dc_name2 );
+
+ tc_status = NO_ERROR;
+
+ break;
+
+ default:
+ /* no idea what this should be */
+ DEBUG(0,("_net_logon_ctrl2: unimplemented function level [%d]\n",
+ q_u->function_code));
+ }
+
+ /* prepare the response */
+
+ init_net_r_logon_ctrl2( r_u, q_u->query_level, flags,
+ pdc_connection_status, logon_attempts, tc_status, dc_name );
if (lp_server_role() == ROLE_DOMAIN_BDC)
send_sync_message();
- DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
-
return r_u->status;
}
diff --git a/source/rpc_server/srv_pipe.c b/source/rpc_server/srv_pipe.c
index 13d894d2d88..36929150e54 100644
--- a/source/rpc_server/srv_pipe.c
+++ b/source/rpc_server/srv_pipe.c
@@ -1397,7 +1397,7 @@ BOOL api_pipe_netsec_process(pipes_struct *p, prs_struct *rpc_in)
SENDER_IS_INITIATOR,
&netsec_chk,
prs_data_p(rpc_in)+old_offset, data_len)) {
- DEBUG(0,("failed to decode PDU\n"));
+ DEBUG(3,("failed to decode PDU\n"));
return False;
}
diff --git a/source/rpc_server/srv_pipe_hnd.c b/source/rpc_server/srv_pipe_hnd.c
index ccf571a0e2c..7f7a3025a90 100644
--- a/source/rpc_server/srv_pipe_hnd.c
+++ b/source/rpc_server/srv_pipe_hnd.c
@@ -602,7 +602,7 @@ static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p)
}
if (p->netsec_auth_validated && !api_pipe_netsec_process(p, rpc_in_p)) {
- DEBUG(0,("process_request_pdu: failed to do schannel processing.\n"));
+ DEBUG(3,("process_request_pdu: failed to do schannel processing.\n"));
set_incoming_fault(p);
return False;
}
diff --git a/source/rpc_server/srv_samr_util.c b/source/rpc_server/srv_samr_util.c
index 417a712036a..8cc44074abe 100644
--- a/source/rpc_server/srv_samr_util.c
+++ b/source/rpc_server/srv_samr_util.c
@@ -240,6 +240,12 @@ void copy_id21_to_sam_passwd(SAM_ACCOUNT *to, SAM_USER_INFO_21 *from)
if (from->fields_present & ACCT_FLAGS) {
DEBUG(10,("INFO_21 ACCT_CTRL: %08X -> %08X\n",pdb_get_acct_ctrl(to),from->acb_info));
if (from->acb_info != pdb_get_acct_ctrl(to)) {
+ if (!(from->acb_info & ACB_AUTOLOCK) && (pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) {
+ /* We're unlocking a previously locked user. Reset bad password counts.
+ Patch from Jianliang Lu. <Jianliang.Lu@getronics.com> */
+ pdb_set_bad_password_count(to, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(to, 0, PDB_CHANGED);
+ }
pdb_set_acct_ctrl(to, from->acb_info, PDB_CHANGED);
}
}
diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c
index 65d5517da45..06ba5435976 100644
--- a/source/rpc_server/srv_spoolss_nt.c
+++ b/source/rpc_server/srv_spoolss_nt.c
@@ -5,7 +5,7 @@
* Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
* Copyright (C) Jean François Micouleau 1998-2000,
* Copyright (C) Jeremy Allison 2001-2002,
- * Copyright (C) Gerald Carter 2000-2003,
+ * Copyright (C) Gerald Carter 2000-2004,
* Copyright (C) Tim Potter 2001-2002.
*
* This program is free software; you can redistribute it and/or modify
@@ -312,6 +312,7 @@ void invalidate_printer_hnd_cache( char *printername )
for ( p=printers_list; p; p=p->next )
{
if ( p->printer_type==PRINTER_HANDLE_IS_PRINTER
+ && p->printer_info
&& StrCaseCmp(p->dev.handlename, printername)==0)
{
DEBUG(10,("invalidating printer_info cache for handl:\n"));
@@ -507,17 +508,19 @@ static BOOL set_printer_hnd_name(Printer_entry *Printer, char *handlename)
if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
continue;
+ /* ------ sharename ------ */
+
fstrcpy(sname, lp_servicename(snum));
DEBUGADD(10, ("share: %s\n",sname));
- /* sharename */
if ( strequal(sname, aprinter) ) {
found = True;
break;
}
- /* printername */
+ /* ------ printername ------ */
+
printer = NULL;
result = get_a_printer( NULL, &printer, 2, sname );
if ( !W_ERROR_IS_OK(result) ) {
@@ -534,10 +537,8 @@ static BOOL set_printer_hnd_name(Printer_entry *Printer, char *handlename)
continue;
}
- /* FIXME!! not mb safe here */
printername++;
- /* sharename */
if ( strequal(printername, aprinter) ) {
found = True;
}
@@ -1188,6 +1189,12 @@ static void receive_notify2_message_list(int msg_type, pid_t src, void *msg, siz
ZERO_STRUCT( notify );
notify2_unpack_msg( &notify, &msg_tv, msg_ptr, msg_len );
msg_ptr += msg_len;
+
+ /* we don't know if the change was from us or not so kill
+ any cached printer objects */
+
+ if ( notify.type == PRINTER_NOTIFY_TYPE )
+ invalidate_printer_hnd_cache( notify.printer );
/* add to correct list in container */
@@ -4310,11 +4317,10 @@ static BOOL construct_printer_info_5(Printer_entry *print_hnd, PRINTER_INFO_5 *p
static BOOL construct_printer_info_7(Printer_entry *print_hnd, PRINTER_INFO_7 *printer, int snum)
{
char *guid_str = NULL;
- UUID_FLAT guid;
+ struct uuid guid;
if (is_printer_published(print_hnd, snum, &guid)) {
- asprintf(&guid_str, "{%s}",
- smb_uuid_string_static(smb_uuid_unpack_static(guid)));
+ asprintf(&guid_str, "{%s}", smb_uuid_string_static(guid));
strupper_m(guid_str);
init_unistr(&printer->guid, guid_str);
printer->action = SPOOL_DS_PUBLISH;
diff --git a/source/rpc_server/srv_srvsvc_nt.c b/source/rpc_server/srv_srvsvc_nt.c
index 77b9be99660..54cc0d61618 100644
--- a/source/rpc_server/srv_srvsvc_nt.c
+++ b/source/rpc_server/srv_srvsvc_nt.c
@@ -1886,8 +1886,21 @@ WERROR _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC
unistr2_to_ascii(filename, &q_u->uni_file_name, sizeof(filename));
unix_convert(filename, conn, NULL, &bad_path, &st);
- fsp = open_file_shared(conn, filename, &st, SET_OPEN_MODE(DOS_OPEN_RDONLY),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
+ if (bad_path) {
+ DEBUG(3,("_srv_net_file_query_secdesc: bad pathname %s\n", filename));
+ r_u->status = WERR_ACCESS_DENIED;
+ goto error_exit;
+ }
+
+ if (!check_name(filename,conn)) {
+ DEBUG(3,("_srv_net_file_query_secdesc: can't access %s\n", filename));
+ r_u->status = WERR_ACCESS_DENIED;
+ goto error_exit;
+ }
+
+ fsp = open_file_shared(conn, filename, &st, SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
+ &access_mode, &action);
if (!fsp) {
/* Perhaps it is a directory */
@@ -1989,9 +2002,22 @@ WERROR _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_
unistr2_to_ascii(filename, &q_u->uni_file_name, sizeof(filename));
unix_convert(filename, conn, NULL, &bad_path, &st);
+ if (bad_path) {
+ DEBUG(3,("_srv_net_file_set_secdesc: bad pathname %s\n", filename));
+ r_u->status = WERR_ACCESS_DENIED;
+ goto error_exit;
+ }
+
+ if (!check_name(filename,conn)) {
+ DEBUG(3,("_srv_net_file_set_secdesc: can't access %s\n", filename));
+ r_u->status = WERR_ACCESS_DENIED;
+ goto error_exit;
+ }
+
- fsp = open_file_shared(conn, filename, &st, SET_OPEN_MODE(DOS_OPEN_RDWR),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
+ fsp = open_file_shared(conn, filename, &st, SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDWR),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
+ &access_mode, &action);
if (!fsp) {
/* Perhaps it is a directory */
diff --git a/source/rpcclient/cmd_spoolss.c b/source/rpcclient/cmd_spoolss.c
index f5a440c024c..38558ec3d47 100644
--- a/source/rpcclient/cmd_spoolss.c
+++ b/source/rpcclient/cmd_spoolss.c
@@ -314,7 +314,7 @@ static WERROR cmd_spoolss_enum_printers(struct cli_state *cli,
return WERR_OK;
}
- if (argc == 2)
+ if (argc >= 2)
info_level = atoi(argv[1]);
if (argc == 3)
@@ -547,6 +547,76 @@ static WERROR cmd_spoolss_setprinter(struct cli_state *cli,
}
/***********************************************************************
+ * Set printer name - use a level2 set.
+ */
+static WERROR cmd_spoolss_setprintername(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ POLICY_HND pol;
+ WERROR result;
+ uint32 needed;
+ uint32 info_level = 2;
+ BOOL opened_hnd = False;
+ PRINTER_INFO_CTR ctr;
+ fstring printername,
+ servername,
+ user,
+ new_printername;
+
+ if (argc == 1 || argc > 3) {
+ printf("Usage: %s printername new_printername\n", argv[0]);
+
+ return WERR_OK;
+ }
+
+ /* Open a printer handle */
+ if (argc == 3) {
+ fstrcpy(new_printername, argv[2]);
+ }
+
+ slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
+ strupper_m(servername);
+ fstrcpy(printername, argv[1]);
+ fstrcpy(user, cli->user_name);
+
+ /* get a printer handle */
+ result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
+ PRINTER_ALL_ACCESS, servername,
+ user, &pol);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ opened_hnd = True;
+
+ /* Get printer info */
+ result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed, &pol, info_level, &ctr);
+
+ if (W_ERROR_V(result) == ERRinsufficientbuffer)
+ result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, info_level, &ctr);
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+
+ /* Modify the printername. */
+ init_unistr(&ctr.printers_2->printername, new_printername);
+ ctr.printers_2->devmode = NULL;
+ ctr.printers_2->secdesc = NULL;
+
+ result = cli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
+ if (W_ERROR_IS_OK(result))
+ printf("Success in setting printername.\n");
+
+ done:
+ if (opened_hnd)
+ cli_spoolss_close_printer(cli, mem_ctx, &pol);
+
+ return result;
+}
+
+/***********************************************************************
* Get printer information
*/
static WERROR cmd_spoolss_getprinter(struct cli_state *cli,
@@ -1844,6 +1914,7 @@ static WERROR cmd_spoolss_setprinterdata(struct cli_state *cli,
PRINTER_INFO_CTR ctr;
PRINTER_INFO_0 info;
REGISTRY_VALUE value;
+ UNISTR2 data;
/* parse the command arguements */
if (argc != 4) {
@@ -1881,10 +1952,11 @@ static WERROR cmd_spoolss_setprinterdata(struct cli_state *cli,
/* Set the printer data */
+ init_unistr2(&data, argv[3], UNI_STR_TERMINATE);
fstrcpy(value.valuename, argv[2]);
value.type = REG_SZ;
- value.size = strlen(argv[3]) + 1;
- value.data_p = talloc_memdup(mem_ctx, argv[3], value.size);
+ value.size = data.uni_str_len * 2;
+ value.data_p = talloc_memdup(mem_ctx, data.buffer, value.size);
result = cli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value);
@@ -2331,6 +2403,7 @@ struct cmd_set spoolss_commands[] = {
{ "deleteform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform, PI_SPOOLSS, "Delete form", "" },
{ "enumforms", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms, PI_SPOOLSS, "Enumerate forms", "" },
{ "setprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter, PI_SPOOLSS, "Set printer comment", "" },
+ { "setprintername", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername, PI_SPOOLSS, "Set printername", "" },
{ "setprinterdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata, PI_SPOOLSS, "Set REG_SZ printer data", "" },
{ "rffpcnex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex, PI_SPOOLSS, "Rffpcnex test", "" },
diff --git a/source/sam/idmap.c b/source/sam/idmap.c
index 4d8b768c2fa..bbb4980c766 100644
--- a/source/sam/idmap.c
+++ b/source/sam/idmap.c
@@ -36,6 +36,8 @@ static struct idmap_function_entry *backends = NULL;
static struct idmap_methods *cache_map;
static struct idmap_methods *remote_map;
+static BOOL proxyonly = False;
+
/**********************************************************************
Get idmap methods. Don't allow tdb to be a remote method.
**********************************************************************/
@@ -144,6 +146,15 @@ BOOL idmap_init(const char *remote_backend)
}
/**************************************************************************
+ Don't do id mapping. This is used to make winbind a netlogon proxy only.
+**************************************************************************/
+
+void idmap_proxyonly(void)
+{
+ proxyonly = True;
+}
+
+/**************************************************************************
This is a rare operation, designed to allow an explicit mapping to be
set up for a sid to a POSIX id.
**************************************************************************/
@@ -153,6 +164,9 @@ NTSTATUS idmap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
struct idmap_methods *map = remote_map;
DOM_SID tmp_sid;
+ if (proxyonly)
+ return NT_STATUS_UNSUCCESSFUL;
+
DEBUG(10, ("idmap_set_mapping: Set %s to %s %lu\n",
sid_string_static(sid),
((id_type & ID_TYPEMASK) == ID_USERID) ? "UID" : "GID",
@@ -186,6 +200,9 @@ NTSTATUS idmap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
NTSTATUS ret;
int loc_type;
+ if (proxyonly)
+ return NT_STATUS_UNSUCCESSFUL;
+
loc_type = *id_type;
if (remote_map) {
@@ -227,6 +244,9 @@ NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
NTSTATUS ret;
int loc_type;
+ if (proxyonly)
+ return NT_STATUS_UNSUCCESSFUL;
+
loc_type = id_type;
if (remote_map) {
loc_type = id_type | ID_QUERY_ONLY;
@@ -260,6 +280,9 @@ NTSTATUS idmap_allocate_id(unid_t *id, int id_type)
{
/* we have to allocate from the authoritative backend */
+ if (proxyonly)
+ return NT_STATUS_UNSUCCESSFUL;
+
if ( remote_map )
return remote_map->allocate_id( id, id_type );
@@ -274,6 +297,9 @@ NTSTATUS idmap_allocate_rid(uint32 *rid, int type)
{
/* we have to allocate from the authoritative backend */
+ if (proxyonly)
+ return NT_STATUS_UNSUCCESSFUL;
+
if ( remote_map )
return remote_map->allocate_rid( rid, type );
@@ -288,6 +314,9 @@ NTSTATUS idmap_close(void)
{
NTSTATUS ret;
+ if (proxyonly)
+ return NT_STATUS_OK;
+
ret = cache_map->close();
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(3, ("idmap_close: failed to close local tdb cache!\n"));
diff --git a/source/sam/idmap_ldap.c b/source/sam/idmap_ldap.c
index 2124fb68793..d83c0bdc4d8 100644
--- a/source/sam/idmap_ldap.c
+++ b/source/sam/idmap_ldap.c
@@ -711,8 +711,12 @@ static NTSTATUS verify_idpool( void )
get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
smbldap_set_mod( &mods, LDAP_MOD_ADD,
get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
-
- rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
+ if (mods) {
+ rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
+ ldap_mods_free( mods, True );
+ } else {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
}
return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
diff --git a/source/script/mkproto.awk b/source/script/mkproto.awk
index b38f405e0da..4c9507dcf9b 100644
--- a/source/script/mkproto.awk
+++ b/source/script/mkproto.awk
@@ -124,7 +124,7 @@ END {
gotstart = 1;
}
- if( $0 ~ /^smb_iconv_t|^long|^char|^uint|^NTSTATUS|^WERROR|^CLI_POLICY_HND|^struct|^BOOL|^void|^time|^smb_shm_offset_t|^shm_offset_t|^FILE|^XFILE|^SMB_OFF_T|^size_t|^ssize_t|^SMB_BIG_UINT/ ) {
+ if( $0 ~ /^smb_iconv_t|^long|^char|^uint|^NTSTATUS|^WERROR|^CLI_POLICY_HND|^struct|^BOOL|^void|^time|^smb_shm_offset_t|^shm_offset_t|^FILE|^XFILE|^SMB_OFF_T|^size_t|^ssize_t|^SMB_BIG_UINT|^SMB_BIG_INT/ ) {
gotstart = 1;
}
@@ -132,7 +132,7 @@ END {
gotstart = 1;
}
- if( $0 ~ /^WINBINDD_PW|^WINBINDD_GR|^NT_PRINTER_INFO_LEVEL_2|^LOGIN_CACHE/ ) {
+ if( $0 ~ /^WINBINDD_PW|^WINBINDD_GR|^NT_PRINTER_INFO_LEVEL_2|^LOGIN_CACHE|^krb5_error_code|^LDAP/ ) {
gotstart = 1;
}
diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c
index c0512d5539b..3983a4cbdfb 100644
--- a/source/smbd/blocking.c
+++ b/source/smbd/blocking.c
@@ -680,7 +680,7 @@ void process_blocking_lock_queue(time_t t)
continue;
}
- if(!set_current_service(conn,True)) {
+ if(!set_current_service(conn,SVAL(blr->inbuf,smb_flg),True)) {
DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
/*
* Remove the entry and return an error to the client.
diff --git a/source/smbd/close.c b/source/smbd/close.c
index 8b3010c1b2e..6de27746442 100644
--- a/source/smbd/close.c
+++ b/source/smbd/close.c
@@ -2,6 +2,7 @@
Unix SMB/CIFS implementation.
file closing
Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1992-2004.
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
@@ -105,6 +106,36 @@ static int close_filestruct(files_struct *fsp)
}
/****************************************************************************
+ If any deferred opens are waiting on this close, notify them.
+****************************************************************************/
+
+static void notify_deferred_opens(files_struct *fsp)
+{
+ deferred_open_entry *de_array = NULL;
+ int num_de_entries, i;
+ pid_t mypid = sys_getpid();
+
+ if (!lp_defer_sharing_violations()) {
+ return;
+ }
+
+ num_de_entries = get_deferred_opens(fsp->conn, fsp->dev, fsp->inode, &de_array);
+ for (i = 0; i < num_de_entries; i++) {
+ deferred_open_entry *entry = &de_array[i];
+ if (entry->pid == mypid) {
+ /*
+ * We need to notify ourself to retry the open.
+ * Do this by finding the queued SMB record, moving it
+ * to the head of the queue and changing the wait time to zero.
+ */
+ schedule_sharing_violation_open_smb_message(entry->mid);
+ } else {
+ send_deferred_open_retry_message(entry);
+ }
+ }
+}
+
+/****************************************************************************
Close a file.
If normal_close is 1 then this came from a normal SMBclose (or equivalent)
@@ -177,6 +208,9 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
SAFE_FREE(share_entry);
+ /* Notify any deferred opens waiting on this close. */
+ notify_deferred_opens(fsp);
+
/*
* NT can set delete_on_close of the last open
* reference to a file.
diff --git a/source/smbd/conn.c b/source/smbd/conn.c
index e083e144263..34e19a3ca6b 100644
--- a/source/smbd/conn.c
+++ b/source/smbd/conn.c
@@ -161,7 +161,7 @@ void conn_close_all(void)
connection_struct *conn, *next;
for (conn=Connections;conn;conn=next) {
next=conn->next;
- set_current_service(conn, True);
+ set_current_service(conn, 0, True);
close_cnum(conn, conn->vuid);
}
}
diff --git a/source/smbd/connection.c b/source/smbd/connection.c
index a9ab1424615..5bb76eb3bd8 100644
--- a/source/smbd/connection.c
+++ b/source/smbd/connection.c
@@ -29,8 +29,8 @@ static TDB_CONTEXT *tdb;
TDB_CONTEXT *conn_tdb_ctx(void)
{
if (!tdb)
- tdb = tdb_open_ex(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
- O_RDWR | O_CREAT, 0644, smbd_tdb_log);
+ tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
return tdb;
}
@@ -131,8 +131,8 @@ BOOL claim_connection(connection_struct *conn, const char *name,int max_connecti
TDB_DATA kbuf, dbuf;
if (!tdb)
- tdb = tdb_open_ex(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
- O_RDWR | O_CREAT, 0644, smbd_tdb_log);
+ tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
if (!tdb)
return False;
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index 06ef23ab8cd..b88f687766d 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -763,7 +763,8 @@ static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_
return True;
else
fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action);
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
+ &access_mode, &smb_action);
if (!fsp)
return False;
diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c
index d7dc63bb2fd..33c75fffd53 100644
--- a/source/smbd/dosmode.c
+++ b/source/smbd/dosmode.c
@@ -182,6 +182,7 @@ static BOOL get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_S
if ((errno != ENOTSUP) && (errno != ENOATTR) && (errno != EACCES)) {
DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
path, strerror(errno) ));
+ set_store_dos_attributes(SNUM(conn), False);
}
#endif
return False;
@@ -224,9 +225,21 @@ static BOOL set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_
files_struct *fsp = NULL;
BOOL ret = False;
+ if (!lp_store_dos_attributes(SNUM(conn))) {
+ return False;
+ }
+
snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
if((errno != EPERM) && (errno != EACCES)) {
+ if (errno == ENOSYS
+#if defined(ENOTSUP)
+ || errno == ENOTSUP) {
+#else
+ ) {
+#endif
+ set_store_dos_attributes(SNUM(conn), False);
+ }
return False;
}
diff --git a/source/smbd/error.c b/source/smbd/error.c
index 9c81d465e7a..d611e0ef873 100644
--- a/source/smbd/error.c
+++ b/source/smbd/error.c
@@ -29,6 +29,17 @@ NTSTATUS unix_ERR_ntstatus = NT_STATUS_OK;
extern struct unix_error_map unix_dos_nt_errmap[];
/****************************************************************************
+ Ensure we don't have any errors cached.
+****************************************************************************/
+
+void clear_cached_errors(void)
+{
+ unix_ERR_class = SMB_SUCCESS;
+ unix_ERR_code = 0;
+ unix_ERR_ntstatus = NT_STATUS_OK;
+}
+
+/****************************************************************************
Create an error packet from a cached error.
****************************************************************************/
diff --git a/source/smbd/filename.c b/source/smbd/filename.c
index 5e5f5726913..ab75d9c06ae 100644
--- a/source/smbd/filename.c
+++ b/source/smbd/filename.c
@@ -135,7 +135,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen
if (SMB_VFS_STAT(conn,name,&st) == 0) {
*pst = st;
}
- DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
+ DEBUG(5,("conversion finished \"\" -> %s\n",name));
return(True);
}
@@ -237,6 +237,15 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen
*/
DEBUG(5,("Not a dir %s\n",start));
*end = '/';
+ /*
+ * We need to return the fact that the intermediate
+ * name resolution failed. This is used to return an
+ * error of ERRbadpath rather than ERRbadfile. Some
+ * Windows applications depend on the difference between
+ * these two errors.
+ */
+ errno = ENOTDIR;
+ *bad_path = True;
return(False);
}
@@ -265,6 +274,9 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen
if (end)
pstrcpy(rest,end+1);
+ /* Reset errno so we can detect directory open errors. */
+ errno = 0;
+
/*
* Try to find this part of the path in the directory.
*/
@@ -292,6 +304,11 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen
return(False);
}
+ if (errno == ENOTDIR) {
+ *bad_path = True;
+ return(False);
+ }
+
/*
* Just the last part of the name doesn't exist.
* We may need to strupper() or strlower() it in case
@@ -392,12 +409,11 @@ BOOL check_name(pstring name,connection_struct *conn)
{
BOOL ret = True;
- errno = 0;
-
if (IS_VETO_PATH(conn, name)) {
/* Is it not dot or dot dot. */
if (!((name[0] == '.') && (!name[1] || (name[1] == '.' && !name[2])))) {
DEBUG(5,("file path name %s vetoed\n",name));
+ errno = ENOENT;
return False;
}
}
@@ -416,13 +432,15 @@ BOOL check_name(pstring name,connection_struct *conn)
if ( (SMB_VFS_LSTAT(conn,name,&statbuf) != -1) &&
(S_ISLNK(statbuf.st_mode)) ) {
DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
+ errno = EACCES;
ret = False;
}
}
#endif
- if (!ret)
+ if (!ret) {
DEBUG(5,("check_name on %s failed\n",name));
+ }
return(ret);
}
@@ -496,5 +514,6 @@ static BOOL scan_directory(const char *path, char *name, size_t maxlength,
}
CloseDir(cur_dir);
+ errno = ENOENT;
return(False);
}
diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c
index c4df84e76c7..dd9708356e7 100644
--- a/source/smbd/lanman.c
+++ b/source/smbd/lanman.c
@@ -1121,11 +1121,11 @@ static int fill_srv_info(struct srv_info_struct *service,
switch (uLevel)
{
case 0:
- push_ascii(p,service->name, 15, STR_TERMINATE);
+ push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
break;
case 1:
- push_ascii(p,service->name,15, STR_TERMINATE);
+ push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
SIVAL(p,18,service->type);
SIVAL(p,22,PTR_DIFF(p2,baseaddr));
len += CopyAndAdvance(&p2,service->comment,&l2);
diff --git a/source/smbd/mangle_hash.c b/source/smbd/mangle_hash.c
index 7b8cbdbddba..d7239b82a79 100644
--- a/source/smbd/mangle_hash.c
+++ b/source/smbd/mangle_hash.c
@@ -546,8 +546,10 @@ static void cache_mangled_name( char *mangled_name, char *raw_name )
/* Fill the new cache entry, and add it to the cache. */
s1 = (char *)(new_entry + 1);
s2 = (char *)&(s1[mangled_len + 1]);
- safe_strcpy( s1, mangled_name, mangled_len );
- safe_strcpy( s2, raw_name, raw_len );
+ memcpy( s1, mangled_name, mangled_len );
+ s1[mangled_len] = '\0';
+ memcpy( s2, raw_name, raw_len );
+ s2[raw_len] = '\0';
ubi_cachePut( mangled_cache, i, new_entry, s1 );
}
diff --git a/source/smbd/msdfs.c b/source/smbd/msdfs.c
index c66f0477a84..6c132897f98 100644
--- a/source/smbd/msdfs.c
+++ b/source/smbd/msdfs.c
@@ -65,7 +65,7 @@ static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp)
DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
/* rest is reqpath */
- check_path_syntax(pdp->reqpath, p+1);
+ check_path_syntax(pdp->reqpath, p+1,True);
DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
return True;
@@ -111,7 +111,7 @@ static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path* pdp)
DEBUG(10,("parse_processed_dfs_path: servicename: %s\n",pdp->servicename));
/* rest is reqpath */
- check_path_syntax(pdp->reqpath, p+1);
+ check_path_syntax(pdp->reqpath, p+1,True);
DEBUG(10,("parse_processed_dfs_path: rest of the path: %s\n",pdp->reqpath));
return True;
diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c
index 1843c174bb5..5ff53f63007 100644
--- a/source/smbd/negprot.c
+++ b/source/smbd/negprot.c
@@ -401,8 +401,9 @@ protocol [LANMAN2.1]
#define ARCH_WIN2K 0xC /* Win2K is like NT */
#define ARCH_OS2 0x14 /* Again OS/2 is like NT */
#define ARCH_SAMBA 0x20
+#define ARCH_CIFSFS 0x40
-#define ARCH_ALL 0x3F
+#define ARCH_ALL 0x7F
/* List of supported protocols, most desired first */
static const struct {
@@ -413,6 +414,7 @@ static const struct {
} supported_protocols[] = {
{"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1},
{"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1},
+ {"POSIX 2", "NT1", reply_nt1, PROTOCOL_NT1},
{"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
{"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
{"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
@@ -460,7 +462,7 @@ int reply_negprot(connection_struct *conn,
else if (strcsequal(p,"DOS LANMAN2.1"))
arch &= ( ARCH_WFWG | ARCH_WIN95 );
else if (strcsequal(p,"NT LM 0.12"))
- arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
+ arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS);
else if (strcsequal(p,"LANMAN2.1"))
arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
else if (strcsequal(p,"LM1.2X002"))
@@ -472,12 +474,23 @@ int reply_negprot(connection_struct *conn,
else if (strcsequal(p,"Samba")) {
arch = ARCH_SAMBA;
break;
+ } else if (strcsequal(p,"POSIX 2")) {
+ arch = ARCH_CIFSFS;
+ break;
}
p += strlen(p) + 2;
}
-
+
+ /* CIFSFS can send one arch only, NT LM 0.12. */
+ if (Index == 1 && (arch & ARCH_CIFSFS)) {
+ arch = ARCH_CIFSFS;
+ }
+
switch ( arch ) {
+ case ARCH_CIFSFS:
+ set_remote_arch(RA_CIFSFS);
+ break;
case ARCH_SAMBA:
set_remote_arch(RA_SAMBA);
break;
diff --git a/source/smbd/notify_hash.c b/source/smbd/notify_hash.c
index ec414454f9e..843580f6edf 100644
--- a/source/smbd/notify_hash.c
+++ b/source/smbd/notify_hash.c
@@ -164,7 +164,7 @@ static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path,
if (!change_to_user(conn,vuid))
return True;
- if (!set_current_service(conn,True)) {
+ if (!set_current_service(conn,FLAG_CASELESS_PATHNAMES,True)) {
change_to_root_user();
return True;
}
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index 26be4434fdb..f717efac63e 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -651,7 +651,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
if(!dir_fsp->is_directory) {
- srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status,False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntcreateX);
return ERROR_NT(status);
@@ -693,14 +693,14 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
dir_name_len++;
}
- srvstr_get_path(inbuf, rel_fname, smb_buf(inbuf), sizeof(rel_fname), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, rel_fname, smb_buf(inbuf), sizeof(rel_fname), 0, STR_TERMINATE, &status,False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntcreateX);
return ERROR_NT(status);
}
pstrcat(fname, rel_fname);
} else {
- srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status,False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntcreateX);
return ERROR_NT(status);
@@ -762,7 +762,18 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
set_posix_case_semantics(conn, file_attributes);
unix_convert(fname,conn,0,&bad_path,&sbuf);
-
+ if (bad_path) {
+ restore_case_semantics(conn, file_attributes);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+ /* All file access must go through check_name() */
+ if (!check_name(fname,conn)) {
+ restore_case_semantics(conn, file_attributes);
+ END_PROFILE(SMBntcreateX);
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
+ }
+
/*
* If it's a request for a directory open, deal with it separately.
*/
@@ -863,6 +874,11 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
restore_case_semantics(conn, file_attributes);
END_PROFILE(SMBntcreateX);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ clear_cached_errors();
+ return -1;
+ }
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
}
@@ -1010,7 +1026,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, cha
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
- srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
@@ -1213,7 +1229,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
return ERROR_DOS(ERRDOS,ERRbadfid);
if(!dir_fsp->is_directory) {
- srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
@@ -1246,14 +1262,14 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
{
pstring tmpname;
- srvstr_get_path(inbuf, tmpname, params+53, sizeof(tmpname), parameter_count-53, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, tmpname, params+53, sizeof(tmpname), parameter_count-53, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
pstrcat(fname, tmpname);
}
} else {
- srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
@@ -1287,6 +1303,15 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ restore_case_semantics(conn, file_attributes);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+ /* All file access must go through check_name() */
+ if (!check_name(fname,conn)) {
+ restore_case_semantics(conn, file_attributes);
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
+ }
/*
* If it's a request for a directory open, deal with it separately.
@@ -1347,6 +1372,11 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
}
} else {
restore_case_semantics(conn, file_attributes);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ clear_cached_errors();
+ return -1;
+ }
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
}
@@ -1491,6 +1521,155 @@ int reply_ntcancel(connection_struct *conn,
}
/****************************************************************************
+ Copy a file.
+****************************************************************************/
+
+static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *newname, uint16 attrs)
+{
+ BOOL bad_path_oldname = False;
+ BOOL bad_path_newname = False;
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+ pstring last_component_oldname;
+ pstring last_component_newname;
+ files_struct *fsp1,*fsp2;
+ uint16 fmode;
+ int access_mode;
+ int smb_action;
+ SMB_OFF_T ret=-1;
+ int close_ret;
+ NTSTATUS status = NT_STATUS_OK;
+
+ ZERO_STRUCT(sbuf1);
+ ZERO_STRUCT(sbuf2);
+
+ /* No wildcards. */
+ if (ms_has_wild(newname) || ms_has_wild(oldname)) {
+ return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+ }
+
+ if (!CAN_WRITE(conn))
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+
+ unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
+ if (bad_path_oldname) {
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ /* Quick check for "." and ".." */
+ if (last_component_oldname[0] == '.') {
+ if (!last_component_oldname[1] || (last_component_oldname[1] == '.' && !last_component_oldname[2])) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ }
+
+ /* Source must already exist. */
+ if (!VALID_STAT(sbuf1)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ if (!check_name(oldname,conn)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Ensure attributes match. */
+ fmode = dos_mode(conn,oldname,&sbuf1);
+ if ((fmode & ~attrs) & (aHIDDEN | aSYSTEM))
+ return NT_STATUS_NO_SUCH_FILE;
+
+ unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
+ if (bad_path_newname) {
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ /* Quick check for "." and ".." */
+ if (last_component_newname[0] == '.') {
+ if (!last_component_newname[1] || (last_component_newname[1] == '.' && !last_component_newname[2])) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ }
+
+ /* Disallow if newname already exists. */
+ if (VALID_STAT(sbuf2)) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ if (!check_name(newname,conn)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* No links from a directory. */
+ if (S_ISDIR(sbuf1.st_mode)) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+
+ /* Ensure this is within the share. */
+ if (!reduce_name(conn, oldname) != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG(10,("copy_internals: doing file copy %s to %s\n", oldname, newname));
+
+ fsp1 = open_file_shared1(conn,oldname,&sbuf1,FILE_READ_DATA,SET_DENY_MODE(DENY_ALL)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),FILE_ATTRIBUTE_NORMAL,0,
+ &access_mode,&smb_action);
+
+ if (!fsp1) {
+ status = NT_STATUS_ACCESS_DENIED;
+ if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
+ status = NT_STATUS_SHARING_VIOLATION;
+ unix_ERR_class = 0;
+ unix_ERR_code = 0;
+ unix_ERR_ntstatus = NT_STATUS_OK;
+ return status;
+ }
+
+ fsp2 = open_file_shared1(conn,newname,&sbuf2,FILE_WRITE_DATA,SET_DENY_MODE(DENY_ALL)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
+ (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL),fmode,INTERNAL_OPEN_ONLY,
+ &access_mode,&smb_action);
+
+ if (!fsp2) {
+ status = NT_STATUS_ACCESS_DENIED;
+ if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
+ status = NT_STATUS_SHARING_VIOLATION;
+ unix_ERR_class = 0;
+ unix_ERR_code = 0;
+ unix_ERR_ntstatus = NT_STATUS_OK;
+ close_file(fsp1,False);
+ return status;
+ }
+
+ if (sbuf1.st_size)
+ ret = vfs_transfer_file(fsp1, fsp2, sbuf1.st_size);
+
+ /*
+ * As we are opening fsp1 read-only we only expect
+ * an error on close on fsp2 if we are out of space.
+ * Thus we don't look at the error return from the
+ * close of fsp1.
+ */
+ close_file(fsp1,False);
+
+ /* Ensure the modtime is set correctly on the destination file. */
+ fsp2->pending_modtime = sbuf1.st_mtime;
+
+ close_ret = close_file(fsp2,False);
+
+ /* Grrr. We have to do this as open_file_shared1 adds aARCH when it
+ creates the file. This isn't the correct thing to do in the copy case. JRA */
+ file_set_dosmode(conn, newname, fmode, &sbuf2);
+
+ if (ret < (SMB_OFF_T)sbuf1.st_size) {
+ return NT_STATUS_DISK_FULL;
+ }
+
+ if (close_ret != 0) {
+ status = map_nt_error_from_unix(close_ret);
+ DEBUG(3,("copy_internals: Error %s copy file %s to %s\n",
+ nt_errstr(status), oldname, newname));
+ }
+ return status;
+}
+
+/****************************************************************************
Reply to a NT rename request.
****************************************************************************/
@@ -1507,13 +1686,8 @@ int reply_ntrename(connection_struct *conn,
START_PROFILE(SMBntrename);
- if ((rename_type != RENAME_FLAG_RENAME) && (rename_type != RENAME_FLAG_HARD_LINK)) {
- END_PROFILE(SMBntrename);
- return ERROR_NT(NT_STATUS_ACCESS_DENIED);
- }
-
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status);
+ p += srvstr_get_path(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status, True);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
return ERROR_NT(status);
@@ -1525,8 +1699,13 @@ int reply_ntrename(connection_struct *conn,
return ERROR_NT(NT_STATUS_ACCESS_DENIED);
}
+ if (ms_has_wild(oldname)) {
+ END_PROFILE(SMBntrename);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+ }
+
p++;
- p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status);
+ p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
return ERROR_NT(status);
@@ -1537,14 +1716,31 @@ int reply_ntrename(connection_struct *conn,
DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname));
- if (rename_type == RENAME_FLAG_RENAME) {
- status = rename_internals(conn, oldname, newname, attrs, False);
- } else {
- status = hardlink_internals(conn, oldname, newname);
+ switch(rename_type) {
+ case RENAME_FLAG_RENAME:
+ status = rename_internals(conn, oldname, newname, attrs, False);
+ break;
+ case RENAME_FLAG_HARD_LINK:
+ status = hardlink_internals(conn, oldname, newname);
+ break;
+ case RENAME_FLAG_COPY:
+ status = copy_internals(conn, oldname, newname, attrs);
+ break;
+ case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
+ status = NT_STATUS_INVALID_PARAMETER;
+ break;
+ default:
+ status = NT_STATUS_ACCESS_DENIED; /* Default error. */
+ break;
}
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ clear_cached_errors();
+ return -1;
+ }
return ERROR_NT(status);
}
@@ -1630,7 +1826,7 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o
fsp = file_fsp(params, 0);
replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
CHECK_FSP(fsp, conn);
- srvstr_get_path(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE, &status, True);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 3b4f50b0656..65500c65cee 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
file opening and share modes
Copyright (C) Andrew Tridgell 1992-1998
- Copyright (C) Jeremy Allison 2001
+ Copyright (C) Jeremy Allison 2001-2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,6 +26,11 @@ extern uint16 global_oplock_port;
extern uint16 global_smbpid;
extern BOOL global_client_failed_oplock_break;
+struct dev_inode_bundle {
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+};
+
/****************************************************************************
fd support routines - attempt to do a dos_open.
****************************************************************************/
@@ -239,11 +244,12 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
conn->num_files_open + 1));
+ errno = 0;
return True;
}
/*******************************************************************
-return True if the filename is one of the special executable types
+ Return True if the filename is one of the special executable types.
********************************************************************/
static BOOL is_executable(const char *fname)
@@ -262,12 +268,13 @@ static BOOL is_executable(const char *fname)
enum {AFAIL,AREAD,AWRITE,AALL};
/*******************************************************************
-reproduce the share mode access table
-this is horrendoously complex, and really can't be justified on any
-rational grounds except that this is _exactly_ what NT does. See
-the DENY1 and DENY2 tests in smbtorture for a comprehensive set of
-test routines.
+ Reproduce the share mode access table.
+ This is horrendoously complex, and really can't be justified on any
+ rational grounds except that this is _exactly_ what NT does. See
+ the DENY1 and DENY2 tests in smbtorture for a comprehensive set of
+ test routines.
********************************************************************/
+
static int access_table(int new_deny,int old_deny,int old_mode,
BOOL same_pid, BOOL isexe)
{
@@ -353,9 +360,8 @@ static int access_table(int new_deny,int old_deny,int old_mode,
return(AFAIL);
}
-
/****************************************************************************
-check if we can open a file with a share mode
+ Check if we can open a file with a share mode.
****************************************************************************/
static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode, uint32 desired_access,
@@ -364,6 +370,8 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i
int deny_mode = GET_DENY_MODE(share_mode);
int old_open_mode = GET_OPEN_MODE(share->share_mode);
int old_deny_mode = GET_DENY_MODE(share->share_mode);
+ BOOL non_io_open_request;
+ BOOL non_io_open_existing;
/*
* share modes = false means don't bother to check for
@@ -373,6 +381,18 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i
if(!lp_share_modes(SNUM(conn)))
return True;
+ if (desired_access & ~(SYNCHRONIZE_ACCESS|READ_CONTROL_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) {
+ non_io_open_request = False;
+ } else {
+ non_io_open_request = True;
+ }
+
+ if (share->desired_access & ~(SYNCHRONIZE_ACCESS|READ_CONTROL_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) {
+ non_io_open_existing = False;
+ } else {
+ non_io_open_existing = True;
+ }
+
/*
* Don't allow any opens once the delete on close flag has been
* set.
@@ -411,8 +431,7 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i
* and the existing desired_acces then share modes don't conflict.
*/
- if ( !(desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) &&
- !(share->desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ) {
+ if (non_io_open_request && non_io_open_existing) {
/*
* Wrinkle discovered by smbtorture....
@@ -436,6 +455,13 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i
and existing desired access (0x%x) are non-data opens\n",
fname, (unsigned int)desired_access, (unsigned int)share->desired_access ));
return True;
+ } else if (non_io_open_request || non_io_open_existing) {
+ /*
+ * If either are non-io opens then share modes don't conflict.
+ */
+ DEBUG(5,("check_share_mode: One non-io open. Allowing open on file %s as desired access (0x%x) doesn't conflict with\
+existing desired access (0x%x).\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access ));
+ return True;
}
/*
@@ -537,6 +563,20 @@ static void validate_my_share_entries(int num, share_mode_entry *share_entry)
}
#endif
+struct share_mode_entry_list {
+ struct share_mode_entry_list *next, *prev;
+ share_mode_entry entry;
+};
+
+static void free_broken_entry_list(struct share_mode_entry_list *broken_entry_list)
+{
+ while (broken_entry_list) {
+ struct share_mode_entry_list *broken_entry = broken_entry_list;
+ DLIST_REMOVE(broken_entry_list, broken_entry);
+ SAFE_FREE(broken_entry);
+ }
+}
+
/****************************************************************************
Deal with open deny mode and oplock break processing.
Invarient: Share mode must be locked on entry and exit.
@@ -554,8 +594,8 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T
int oplock_contention_count = 0;
share_mode_entry *old_shares = 0;
BOOL fcbopen = False;
- BOOL broke_oplock;
-
+ BOOL broke_oplock;
+
if(GET_OPEN_MODE(share_mode) == DOS_OPEN_FCB)
fcbopen = True;
@@ -564,17 +604,25 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T
if(num_share_modes == 0)
return 0;
+ if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) &&
+ ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) {
+ /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */
+ return num_share_modes;
+ }
+
/*
* Check if the share modes will give us access.
*/
do {
- share_mode_entry broken_entry;
-
+ struct share_mode_entry_list *broken_entry_list = NULL;
+ struct share_mode_entry_list *broken_entry = NULL;
+
broke_oplock = False;
*p_all_current_opens_are_level_II = True;
for(i = 0; i < num_share_modes; i++) {
+ BOOL cause_oplock_break = False;
share_mode_entry *share_entry = &old_shares[i];
#if defined(DEVELOPER)
@@ -589,9 +637,17 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T
* it before continuing.
*/
- if((*p_oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) ||
+ /* Was this a delete this file request ? */
+ if (!*p_oplock_request && desired_access == DELETE_ACCESS &&
+ !BATCH_OPLOCK_TYPE(share_entry->op_type)) {
+ /* Don't break the oplock in this case. */
+ cause_oplock_break = False;
+ } else if((*p_oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) ||
(!*p_oplock_request && (share_entry->op_type != NO_OPLOCK))) {
-
+ cause_oplock_break = True;
+ }
+
+ if(cause_oplock_break) {
BOOL opb_ret;
DEBUG(5,("open_mode_check: oplock_request = %d, breaking oplock (%x) on file %s, \
@@ -622,50 +678,65 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
return -1;
}
+ broken_entry = malloc(sizeof(struct share_mode_entry_list));
+ if (!broken_entry) {
+ smb_panic("open_mode_check: malloc fail.\n");
+ }
+ broken_entry->entry = *share_entry;
+ DLIST_ADD(broken_entry_list, broken_entry);
broke_oplock = True;
- broken_entry = *share_entry;
- break;
} else if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
*p_all_current_opens_are_level_II = False;
}
-
+ } /* end for */
+
+ if (broke_oplock) {
+ /* Update the current open table. */
+ SAFE_FREE(old_shares);
+ num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+ }
+
+ /* Now we check the share modes, after any oplock breaks. */
+ for(i = 0; i < num_share_modes; i++) {
+ share_mode_entry *share_entry = &old_shares[i];
+
/* someone else has a share lock on it, check to see if we can too */
if (!check_share_mode(conn, share_entry, share_mode, desired_access,
fname, fcbopen, p_flags)) {
SAFE_FREE(old_shares);
+ free_broken_entry_list(broken_entry_list);
errno = EACCES;
return -1;
}
-
- } /* end for */
-
- if(broke_oplock) {
- SAFE_FREE(old_shares);
- num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+ }
+
+ for(broken_entry = broken_entry_list; broken_entry; broken_entry = broken_entry->next) {
oplock_contention_count++;
/* Paranoia check that this is no longer an exlusive entry. */
for(i = 0; i < num_share_modes; i++) {
share_mode_entry *share_entry = &old_shares[i];
- if (share_modes_identical(&broken_entry, share_entry) &&
- EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) {
+ if (share_modes_identical(&broken_entry->entry, share_entry) &&
+ EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) {
/*
* This should not happen. The target left this oplock
* as exlusive.... The process *must* be dead....
*/
- DEBUG(0,("open_mode_check: exlusive oplock left by process %d after break ! For file %s, \
-dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fname, (unsigned int)dev, (double)inode));
+ DEBUG(0,("open_mode_check: exlusive oplock left by process %d \
+after break ! For file %s, dev = %x, inode = %.0f. Deleting it to continue...\n",
+ (int)broken_entry->entry.pid, fname, (unsigned int)dev, (double)inode));
- if (process_exists(broken_entry.pid)) {
+ if (process_exists(broken_entry->entry.pid)) {
DEBUG(0,("open_mode_check: Existent process %lu left active oplock.\n",
- (unsigned long)broken_entry.pid ));
+ (unsigned long)broken_entry->entry.pid ));
}
- if (del_share_entry(dev, inode, &broken_entry, NULL) == -1) {
+ if (del_share_entry(dev, inode, &broken_entry->entry, NULL) == -1) {
+ free_broken_entry_list(broken_entry_list);
errno = EACCES;
unix_ERR_class = ERRDOS;
unix_ERR_code = ERRbadshare;
@@ -683,8 +754,8 @@ dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fn
break;
}
} /* end for paranoia... */
- } /* end if broke_oplock */
-
+ } /* end for broken_entry */
+ free_broken_entry_list(broken_entry_list);
} while(broke_oplock);
if(old_shares != 0)
@@ -705,9 +776,119 @@ dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fn
}
/****************************************************************************
-set a kernel flock on a file for NFS interoperability
-this requires a patch to Linux
+ Delete the record for a handled deferred open entry.
****************************************************************************/
+
+static void delete_defered_open_entry_record(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode)
+{
+ uint16 mid = get_current_mid();
+ pid_t mypid = sys_getpid();
+ deferred_open_entry *de_array = NULL;
+ int num_de_entries, i;
+
+ if (!lp_defer_sharing_violations()) {
+ return;
+ }
+
+ num_de_entries = get_deferred_opens(conn, dev, inode, &de_array);
+ for (i = 0; i < num_de_entries; i++) {
+ deferred_open_entry *entry = &de_array[i];
+ if (entry->pid == mypid && entry->mid == mid && entry->dev == dev &&
+ entry->inode == inode) {
+
+ /* Remove the deferred open entry from the array. */
+ delete_deferred_open_entry(entry);
+ SAFE_FREE(de_array);
+ return;
+ }
+ }
+ SAFE_FREE(de_array);
+}
+
+/****************************************************************************
+ Handle the 1 second delay in returning a SHARING_VIOLATION error.
+****************************************************************************/
+
+void defer_open_sharing_error(connection_struct *conn, struct timeval *ptv,
+ char *fname, SMB_DEV_T dev, SMB_INO_T inode)
+{
+ uint16 mid = get_current_mid();
+ pid_t mypid = sys_getpid();
+ deferred_open_entry *de_array = NULL;
+ int num_de_entries, i;
+ struct dev_inode_bundle dib;
+
+ if (!lp_defer_sharing_violations()) {
+ return;
+ }
+
+ dib.dev = dev;
+ dib.inode = inode;
+
+ num_de_entries = get_deferred_opens(conn, dev, inode, &de_array);
+ for (i = 0; i < num_de_entries; i++) {
+ deferred_open_entry *entry = &de_array[i];
+ if (entry->pid == mypid && entry->mid == mid) {
+ /*
+ * Check if a 1 second timeout has expired.
+ */
+ if (usec_time_diff(ptv, &entry->time) > SHARING_VIOLATION_USEC_WAIT) {
+ DEBUG(10,("defer_open_sharing_error: Deleting deferred open entry for mid %u, \
+file %s\n",
+ (unsigned int)mid, fname ));
+
+ /* Expired, return a real error. */
+ /* Remove the deferred open entry from the array. */
+
+ delete_deferred_open_entry(entry);
+ SAFE_FREE(de_array);
+ return;
+ }
+ /*
+ * If the timeout hasn't expired yet and we still have a sharing violation,
+ * just leave the entry in the deferred open array alone. We do need to
+ * reschedule this open call though (with the original created time).
+ */
+ DEBUG(10,("defer_open_sharing_error: time [%u.%06u] updating \
+deferred open entry for mid %u, file %s\n",
+ (unsigned int)entry->time.tv_sec,
+ (unsigned int)entry->time.tv_usec,
+ (unsigned int)mid, fname ));
+
+ push_sharing_violation_open_smb_message(&entry->time, (char *)&dib, sizeof(dib));
+ SAFE_FREE(de_array);
+ return;
+ }
+ }
+
+ DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred open entry for mid %u, file %s\n",
+ (unsigned int)ptv->tv_sec, (unsigned int)ptv->tv_usec, (unsigned int)mid, fname ));
+
+ if (!push_sharing_violation_open_smb_message(ptv, (char *)&dib, sizeof(dib))) {
+ SAFE_FREE(de_array);
+ return;
+ }
+ if (!add_deferred_open(mid, ptv, dev, inode, global_oplock_port, fname)) {
+ remove_sharing_violation_open_smb_message(mid);
+ }
+
+ /*
+ * Push the MID of this packet on the signing queue.
+ * We only do this once, the first time we push the packet
+ * onto the deferred open queue, as this has a side effect
+ * of incrementing the response sequence number.
+ */
+
+ srv_defer_sign_response(mid);
+
+ SAFE_FREE(de_array);
+}
+
+/****************************************************************************
+ Set a kernel flock on a file for NFS interoperability.
+ This requires a patch to Linux.
+****************************************************************************/
+
static void kernel_flock(files_struct *fsp, int deny_mode)
{
#if HAVE_KERNEL_SHARE_MODES
@@ -781,6 +962,8 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
BOOL file_existed = VALID_STAT(*psbuf);
BOOL fcbopen = False;
BOOL def_acl = False;
+ BOOL add_share_mode = True;
+ BOOL internal_only_open = False;
SMB_DEV_T dev = 0;
SMB_INO_T inode = 0;
int num_share_modes = 0;
@@ -792,9 +975,50 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
mode_t new_mode = (mode_t)0;
int action;
uint32 existing_dos_mode = 0;
+ struct pending_message_list *pml = NULL;
+ uint16 mid = get_current_mid();
/* We add aARCH to this as this mode is only used if the file is created new. */
mode_t mode = unix_mode(conn,new_dos_mode | aARCH,fname);
+ if (oplock_request == INTERNAL_OPEN_ONLY) {
+ internal_only_open = True;
+ oplock_request = 0;
+ }
+
+ if ((pml = get_open_deferred_message(mid)) != NULL) {
+ struct dev_inode_bundle dib;
+
+ memcpy(&dib, pml->private_data.data, sizeof(dib));
+
+ /* There could be a race condition where the dev/inode pair
+ has changed since we deferred the message. If so, just
+ remove the deferred open entry and return sharing violation. */
+
+ /* If the timeout value is non-zero, we need to just
+ return sharing violation. Don't retry the open
+ as we were not notified of a close and we don't want to
+ trigger another spurious oplock break. */
+
+ if (!file_existed || dib.dev != psbuf->st_dev || dib.inode != psbuf->st_ino ||
+ pml->msg_time.tv_sec || pml->msg_time.tv_usec) {
+ /* Ensure we don't reprocess this message. */
+ remove_sharing_violation_open_smb_message(mid);
+
+ /* Now remove the deferred open entry under lock. */
+ lock_share_entry(conn, dib.dev, dib.inode);
+ delete_defered_open_entry_record(conn, dib.dev, dib.inode);
+ unlock_share_entry(conn, dib.dev, dib.inode);
+
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+ unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION;
+ return NULL;
+ }
+ /* Ensure we don't reprocess this message. */
+ remove_sharing_violation_open_smb_message(mid);
+
+ }
+
if (conn->printer) {
/* printers are handled completely differently. Most of the passed parameters are
ignored */
@@ -805,25 +1029,6 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
return print_fsp_open(conn, fname);
}
- if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) &&
- ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) {
- /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */
- oplock_request = 0;
- fsp = open_file_stat(conn, fname, psbuf);
- if (!fsp)
- return NULL;
-
- fsp->desired_access = desired_access;
- if (Access)
- *Access = DOS_OPEN_RDONLY;
- if (paction)
- *paction = FILE_WAS_OPENED;
-
- DEBUG(10,("open_file_shared: stat open for fname = %s share_mode = %x\n",
- fname, share_mode ));
- return fsp;
- }
-
fsp = file_new(conn);
if(!fsp)
return NULL;
@@ -947,6 +1152,17 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
return NULL;
}
+ if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) &&
+ ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) {
+ /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */
+ deny_mode = DENY_NONE;
+ if (file_existed) {
+ oplock_request = 0;
+ add_share_mode = False;
+ flags2 &= ~O_CREAT;
+ }
+ }
+
if (file_existed) {
dev = psbuf->st_dev;
@@ -985,17 +1201,28 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
unix_ERR_ntstatus = NT_STATUS_ACCESS_DENIED;
}
+ /*
+ * If we're returning a share violation, ensure we cope with
+ * the braindead 1 second delay.
+ */
+
+ if (!internal_only_open && NT_STATUS_EQUAL(unix_ERR_ntstatus,NT_STATUS_SHARING_VIOLATION)) {
+ /* The fsp->open_time here represents the current time of day. */
+ defer_open_sharing_error(conn, &fsp->open_time, fname, dev, inode);
+ }
+
unlock_share_entry(conn, dev, inode);
- if (fsp_open)
+ if (fsp_open) {
fd_close(conn, fsp);
+ /*
+ * We have detected a sharing violation here
+ * so return the correct error code
+ */
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+ unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION;
+ }
file_free(fsp);
- /*
- * We have detected a sharing violation here
- * so return the correct error code
- */
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadshare;
- unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION;
return NULL;
}
@@ -1060,6 +1287,16 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
&flags, &oplock_request, &all_current_opens_are_level_II);
if(num_share_modes == -1) {
+ /*
+ * If we're returning a share violation, ensure we cope with
+ * the braindead 1 second delay.
+ */
+
+ if (!internal_only_open && NT_STATUS_EQUAL(unix_ERR_ntstatus,NT_STATUS_SHARING_VIOLATION)) {
+ /* The fsp->open_time here represents the current time of day. */
+ defer_open_sharing_error(conn, &fsp->open_time, fname, dev, inode);
+ }
+
unlock_share_entry_fsp(fsp);
fd_close(conn,fsp);
file_free(fsp);
@@ -1166,14 +1403,18 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
oplock_request = 0;
}
- set_share_mode(fsp, port, oplock_request);
+ if (add_share_mode) {
+ set_share_mode(fsp, port, oplock_request);
+ }
if (delete_on_close) {
NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close);
if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) {
/* Remember to delete the mode we just added. */
- del_share_mode(fsp, NULL);
+ if (add_share_mode) {
+ del_share_mode(fsp, NULL);
+ }
unlock_share_entry_fsp(fsp);
fd_close(conn,fsp);
file_free(fsp);
@@ -1224,6 +1465,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
fname, (int)new_mode));
}
+ /* If this is a successful open, we must remove any deferred open records. */
+ delete_defered_open_entry_record(conn, fsp->dev, fsp->inode);
unlock_share_entry_fsp(fsp);
conn->num_files_open++;
diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c
index 19e6956d9ef..1ffc798b1fc 100644
--- a/source/smbd/oplock.c
+++ b/source/smbd/oplock.c
@@ -388,6 +388,30 @@ pid %d, port %d, dev = %x, inode = %.0f, file_id = %lu\n",
(int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id));
break;
+ case RETRY_DEFERRED_OPEN_CMD:
+
+ /* Request to retry and open that would return SHARING_VIOLATION. */
+ if (msg_len != DEFERRED_OPEN_MSG_LEN) {
+ DEBUG(0,("process_local_message: incorrect length for RETRY_DEFERRED_OPEN_CMD (was %d, should be %d).\n",
+ (int)msg_len, (int)DEFERRED_OPEN_MSG_LEN));
+ return False;
+ }
+ {
+ uint16 mid;
+
+ memcpy((char *)&remotepid, msg_start+DEFERRED_OPEN_PID_OFFSET,sizeof(remotepid));
+ memcpy((char *)&inode, msg_start+DEFERRED_OPEN_INODE_OFFSET,sizeof(inode));
+ memcpy((char *)&dev, msg_start+DEFERRED_OPEN_DEV_OFFSET,sizeof(dev));
+ memcpy((char *)&mid, msg_start+DEFERRED_OPEN_MID_OFFSET,sizeof(mid));
+
+ DEBUG(5,("process_local_message: RETRY_DEFERRED_OPEN from \
+pid %d, port %d, dev = %x, inode = %.0f, mid = %u\n",
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode, (unsigned int)mid));
+
+ schedule_sharing_violation_open_smb_message(mid);
+ }
+ return True;
+
/*
* Keep this as a debug case - eventually we can remove it.
*/
@@ -592,6 +616,8 @@ BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token)
*/
if (global_client_caps & CAP_LEVEL_II_OPLOCKS) {
+ BOOL sign_state;
+
/*
* If we are sending an oplock break due to an SMB sent
* by our own client we ensure that we wait at leat
@@ -603,10 +629,16 @@ BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token)
wait_before_sending_break(local_request);
/* Prepare the SMBlockingX message. */
-
prepare_break_message( outbuf, fsp, False);
+
+ /* Save the server smb signing state. */
+ sign_state = srv_oplock_set_signing(False);
+
if (!send_smb(smbd_server_fd(), outbuf))
exit_server("oplock_break_level2: send_smb failed.");
+
+ /* Restore the sign state to what it was. */
+ srv_oplock_set_signing(sign_state);
}
/*
@@ -1215,7 +1247,51 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
}
/****************************************************************************
-setup oplocks for this process
+ Send a 'retry your open' message to a process with a deferred open entry.
+****************************************************************************/
+
+BOOL send_deferred_open_retry_message(deferred_open_entry *entry)
+{
+ char de_msg[DEFERRED_OPEN_MSG_LEN];
+ struct sockaddr_in addr_out;
+ pid_t pid = sys_getpid();
+
+ memset(de_msg, '\0', DEFERRED_OPEN_MSG_LEN);
+ SSVAL(de_msg,DEFERRED_OPEN_CMD_OFFSET,RETRY_DEFERRED_OPEN_CMD);
+ memcpy(de_msg+DEFERRED_OPEN_PID_OFFSET,(char *)&pid,sizeof(pid));
+ memcpy(de_msg+DEFERRED_OPEN_DEV_OFFSET,(char *)&entry->dev,sizeof(entry->dev));
+ memcpy(de_msg+DEFERRED_OPEN_INODE_OFFSET,(char *)&entry->inode,sizeof(entry->inode));
+ memcpy(de_msg+DEFERRED_OPEN_MID_OFFSET,(char *)&entry->mid,sizeof(entry->mid));
+
+ /* Set the address and port. */
+ memset((char *)&addr_out,'\0',sizeof(addr_out));
+ addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr_out.sin_port = htons( entry->port );
+ addr_out.sin_family = AF_INET;
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "send_deferred_open_retry_message: sending a message to ");
+ dbgtext( "pid %d on port %d ", (int)entry->pid, entry->port );
+ dbgtext( "for dev = %x, inode = %.0f, mid = %u\n",
+ (unsigned int)entry->dev, (double)entry->inode, (unsigned int)entry->mid );
+ }
+
+ if(sys_sendto(oplock_sock,de_msg,DEFERRED_OPEN_MSG_LEN,0,
+ (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "send_deferred_open_retry_message: failed sending a message to ");
+ dbgtext( "pid %d on port %d ", (int)entry->pid, entry->port );
+ dbgtext( "for dev = %x, inode = %.0f, mid = %u\n",
+ (unsigned int)entry->dev, (double)entry->inode, (unsigned int)entry->mid );
+ dbgtext( "Error was %s\n", strerror(errno) );
+ }
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ Setup oplocks for this process.
****************************************************************************/
BOOL init_oplocks(void)
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c
index 584164e9309..2d9591e6baa 100644
--- a/source/smbd/posix_acls.c
+++ b/source/smbd/posix_acls.c
@@ -880,7 +880,7 @@ static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
Unpack a SEC_DESC into a UNIX owner and group.
****************************************************************************/
-static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
+static BOOL unpack_nt_owners(int snum, SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
{
DOM_SID owner_sid;
DOM_SID grp_sid;
@@ -910,15 +910,17 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp,
if (security_info_sent & OWNER_SECURITY_INFORMATION) {
sid_copy(&owner_sid, psd->owner_sid);
if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid, puser))) {
-#if ACL_FORCE_UNMAPPABLE
- /* this allows take ownership to work reasonably */
- extern struct current_user current_user;
- *puser = current_user.uid;
-#else
- DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n",
- sid_string_static(&owner_sid)));
- return False;
-#endif
+ if (lp_force_unknown_acl_user(snum)) {
+ /* this allows take ownership to work
+ * reasonably */
+ extern struct current_user current_user;
+ *puser = current_user.uid;
+ } else {
+ DEBUG(3,("unpack_nt_owners: unable to validate"
+ " owner sid for %s\n",
+ sid_string_static(&owner_sid)));
+ return False;
+ }
}
}
@@ -930,14 +932,16 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp,
if (security_info_sent & GROUP_SECURITY_INFORMATION) {
sid_copy(&grp_sid, psd->grp_sid);
if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid, pgrp))) {
-#if ACL_FORCE_UNMAPPABLE
- /* this allows take group ownership to work reasonably */
- extern struct current_user current_user;
- *pgrp = current_user.gid;
-#else
- DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
- return False;
-#endif
+ if (lp_force_unknown_acl_user(snum)) {
+ /* this allows take group ownership to work
+ * reasonably */
+ extern struct current_user current_user;
+ *pgrp = current_user.gid;
+ } else {
+ DEBUG(3,("unpack_nt_owners: unable to validate"
+ " group sid.\n"));
+ return False;
+ }
}
}
@@ -3005,7 +3009,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
* Unpack the user/group/world id's.
*/
- if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
+ if (!unpack_nt_owners( SNUM(conn), &sbuf, &user, &grp, security_info_sent, psd))
return False;
/*
diff --git a/source/smbd/process.c b/source/smbd/process.c
index 12fd809b784..60ce1499e8d 100644
--- a/source/smbd/process.c
+++ b/source/smbd/process.c
@@ -61,55 +61,215 @@ uint16 get_current_mid(void)
for processing.
****************************************************************************/
-typedef struct {
- ubi_slNode msg_next;
- char *msg_buf;
- int msg_len;
-} pending_message_list;
+static struct pending_message_list *smb_oplock_queue;
+static struct pending_message_list *smb_sharing_violation_queue;
-static ubi_slList smb_oplock_queue = { NULL, (ubi_slNodePtr)&smb_oplock_queue, 0};
+enum q_type { OPLOCK_QUEUE, SHARE_VIOLATION_QUEUE };
+
+/****************************************************************************
+ Free up a message.
+****************************************************************************/
+
+static void free_queued_message(struct pending_message_list *msg)
+{
+ data_blob_free(&msg->buf);
+ data_blob_free(&msg->private_data);
+ SAFE_FREE(msg);
+}
/****************************************************************************
Function to push a message onto the tail of a linked list of smb messages ready
for processing.
****************************************************************************/
-static BOOL push_message(ubi_slList *list_head, char *buf, int msg_len)
+static BOOL push_queued_message(enum q_type qt, char *buf, int msg_len, struct timeval *ptv, char *private, size_t private_len)
{
- pending_message_list *msg = (pending_message_list *)
- malloc(sizeof(pending_message_list));
+ struct pending_message_list *tmp_msg;
+ struct pending_message_list *msg = (struct pending_message_list *)
+ malloc(sizeof(struct pending_message_list));
if(msg == NULL) {
DEBUG(0,("push_message: malloc fail (1)\n"));
return False;
}
- msg->msg_buf = (char *)malloc(msg_len);
- if(msg->msg_buf == NULL) {
+ memset(msg,'\0',sizeof(*msg));
+
+ msg->buf = data_blob(buf, msg_len);
+ if(msg->buf.data == NULL) {
DEBUG(0,("push_message: malloc fail (2)\n"));
SAFE_FREE(msg);
return False;
}
- memcpy(msg->msg_buf, buf, msg_len);
- msg->msg_len = msg_len;
+ if (ptv) {
+ msg->msg_time = *ptv;
+ }
+
+ if (private) {
+ msg->private_data = data_blob(private, private_len);
+ if (msg->private_data.data == NULL) {
+ DEBUG(0,("push_message: malloc fail (3)\n"));
+ data_blob_free(&msg->buf);
+ SAFE_FREE(msg);
+ }
+ }
- ubi_slAddTail( list_head, msg);
+ if (qt == OPLOCK_QUEUE) {
+ DLIST_ADD_END(smb_oplock_queue, msg, tmp_msg);
+ } else {
+ DLIST_ADD_END(smb_sharing_violation_queue, msg, tmp_msg);
+ }
- /* Push the MID of this packet on the signing queue. */
- srv_defer_sign_response(SVAL(buf,smb_mid));
+ DEBUG(10,("push_message: pushed message length %u on queue %s\n",
+ (unsigned int)msg_len,
+ qt == OPLOCK_QUEUE ? "smb_oplock_queue" : "smb_sharing_violation_queue" ));
return True;
}
/****************************************************************************
- Function to push a smb message onto a linked list of local smb messages ready
+ Function to push an oplock smb message onto a linked list of local smb messages ready
for processing.
****************************************************************************/
BOOL push_oplock_pending_smb_message(char *buf, int msg_len)
{
- return push_message(&smb_oplock_queue, buf, msg_len);
+ BOOL ret = push_queued_message(OPLOCK_QUEUE, buf, msg_len, NULL, NULL, 0);
+ if (ret) {
+ /* Push the MID of this packet on the signing queue. */
+ srv_defer_sign_response(SVAL(buf,smb_mid));
+ }
+ return ret;
+}
+
+/****************************************************************************
+ Function to delete a sharing violation open message by mid.
+****************************************************************************/
+
+void remove_sharing_violation_open_smb_message(uint16 mid)
+{
+ struct pending_message_list *pml;
+
+ if (!lp_defer_sharing_violations()) {
+ return;
+ }
+
+ for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
+ if (mid == SVAL(pml->buf.data,smb_mid)) {
+ DEBUG(10,("remove_sharing_violation_open_smb_message: deleting mid %u len %u\n",
+ (unsigned int)mid, (unsigned int)pml->buf.length ));
+ DLIST_REMOVE(smb_sharing_violation_queue, pml);
+ free_queued_message(pml);
+ return;
+ }
+ }
+}
+
+/****************************************************************************
+ Move a sharing violation open retry message to the front of the list and
+ schedule it for immediate processing.
+****************************************************************************/
+
+void schedule_sharing_violation_open_smb_message(uint16 mid)
+{
+ struct pending_message_list *pml;
+ int i = 0;
+
+ if (!lp_defer_sharing_violations()) {
+ return;
+ }
+
+ for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
+ uint16 msg_mid = SVAL(pml->buf.data,smb_mid);
+ DEBUG(10,("schedule_sharing_violation_open_smb_message: [%d] msg_mid = %u\n", i++,
+ (unsigned int)msg_mid ));
+ if (mid == msg_mid) {
+ DEBUG(10,("schedule_sharing_violation_open_smb_message: scheduling mid %u\n",
+ mid ));
+ pml->msg_time.tv_sec = 0;
+ pml->msg_time.tv_usec = 0;
+ DLIST_PROMOTE(smb_sharing_violation_queue, pml);
+ return;
+ }
+ }
+
+ DEBUG(10,("schedule_sharing_violation_open_smb_message: failed to find message mid %u\n",
+ mid ));
+}
+
+/****************************************************************************
+ Return true if this mid is on the deferred queue.
+****************************************************************************/
+
+BOOL open_was_deferred(uint16 mid)
+{
+ struct pending_message_list *pml;
+
+ if (!lp_defer_sharing_violations()) {
+ return False;
+ }
+
+ for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
+ if (SVAL(pml->buf.data,smb_mid) == mid) {
+ return True;
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+ Return the message queued by this mid.
+****************************************************************************/
+
+struct pending_message_list *get_open_deferred_message(uint16 mid)
+{
+ struct pending_message_list *pml;
+
+ if (!lp_defer_sharing_violations()) {
+ return NULL;
+ }
+
+ for (pml = smb_sharing_violation_queue; pml; pml = pml->next) {
+ if (SVAL(pml->buf.data,smb_mid) == mid) {
+ return pml;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Function to push a sharing violation open smb message onto a linked list of local smb messages ready
+ for processing.
+****************************************************************************/
+
+BOOL push_sharing_violation_open_smb_message(struct timeval *ptv, char *private, size_t priv_len)
+{
+ uint16 mid = SVAL(InBuffer,smb_mid);
+ struct timeval tv;
+ SMB_BIG_INT tdif;
+
+ if (!lp_defer_sharing_violations()) {
+ return True;
+ }
+
+ tv = *ptv;
+ tdif = tv.tv_sec;
+ tdif *= 1000000;
+ tdif += tv.tv_usec;
+
+ /* Add on the timeout. */
+ tdif += SHARING_VIOLATION_USEC_WAIT;
+
+ tv.tv_sec = tdif / 1000000;
+ tv.tv_usec = tdif % 1000000;
+
+ DEBUG(10,("push_sharing_violation_open_smb_message: pushing message len %u mid %u\
+ timeout time [%u.%06u]\n", (unsigned int) smb_len(InBuffer)+4, (unsigned int)mid,
+ (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec));
+
+ return push_queued_message(SHARE_VIOLATION_QUEUE, InBuffer,
+ smb_len(InBuffer)+4, &tv, private, priv_len);
}
/****************************************************************************
@@ -168,12 +328,17 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
fd_set fds;
int selrtn;
struct timeval to;
+ struct timeval *pto;
int maxfd;
smb_read_error = 0;
again:
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
+ pto = timeout > 0 ? &to : NULL;
+
/*
* Note that this call must be before processing any SMB
* messages as we need to synchronously process any messages
@@ -185,18 +350,57 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
* Check to see if we already have a message on the smb queue.
* If so - copy and return it.
*/
- if(ubi_slCount(&smb_oplock_queue) != 0) {
- pending_message_list *msg = (pending_message_list *)ubi_slRemHead(&smb_oplock_queue);
- memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
+ if(smb_oplock_queue != NULL) {
+ struct pending_message_list *msg = smb_oplock_queue;
+ memcpy(buffer, msg->buf.data, MIN(buffer_len, msg->buf.length));
/* Free the message we just copied. */
- SAFE_FREE(msg->msg_buf);
- SAFE_FREE(msg);
+ DLIST_REMOVE(smb_oplock_queue, msg);
+ free_queued_message(msg);
DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
return True;
}
+ /*
+ * Check to see if we already have a message on the deferred open queue
+ * and it's time to schedule.
+ */
+ if(smb_sharing_violation_queue != NULL) {
+ BOOL pop_message = False;
+ struct pending_message_list *msg = smb_sharing_violation_queue;
+
+ if (msg->msg_time.tv_sec == 0 && msg->msg_time.tv_usec == 0) {
+ pop_message = True;
+ } else {
+ struct timeval tv;
+ SMB_BIG_INT tdif;
+
+ GetTimeOfDay(&tv);
+ tdif = usec_time_diff(&msg->msg_time, &tv);
+ if (tdif <= 0) {
+ /* Timed out. Schedule...*/
+ pop_message = True;
+ DEBUG(10,("receive_message_or_smb: queued message timed out.\n"));
+ } else {
+ /* Make a more accurate select timeout. */
+ to.tv_sec = tdif / 1000000;
+ to.tv_usec = tdif % 1000000;
+ pto = &to;
+ DEBUG(10,("receive_message_or_smb: select with timeout of [%u.%06u]\n",
+ (unsigned int)pto->tv_sec, (unsigned int)pto->tv_usec ));
+ }
+ }
+
+ if (pop_message) {
+ memcpy(buffer, msg->buf.data, MIN(buffer_len, msg->buf.length));
+
+ /* We leave this message on the queue so the open code can
+ know this is a retry. */
+ DEBUG(5,("receive_message_or_smb: returning deferred open smb message.\n"));
+ return True;
+ }
+ }
/*
* Setup the select read fd set.
@@ -227,10 +431,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
FD_SET(smbd_server_fd(),&fds);
maxfd = setup_oplock_select_set(&fds);
- to.tv_sec = timeout / 1000;
- to.tv_usec = (timeout % 1000) * 1000;
-
- selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,timeout>0?&to:NULL);
+ selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,pto);
/* if we get EINTR then maybe we have received an oplock
signal - treat this as select returning 1. This is ugly, but
@@ -755,7 +956,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
return(ERROR_DOS(ERRSRV,ERRaccess));
/* load service specific parameters */
- if (conn && !set_current_service(conn,(flags & (AS_USER|DO_CHDIR)?True:False)))
+ if (conn && !set_current_service(conn,SVAL(inbuf,smb_flg),(flags & (AS_USER|DO_CHDIR)?True:False)))
return(ERROR_DOS(ERRSRV,ERRaccess));
/* does this protocol need to be run as guest? */
diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c
index e439c1e571a..3c4d4319f63 100644
--- a/source/smbd/quotas.c
+++ b/source/smbd/quotas.c
@@ -933,6 +933,176 @@ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB
#include <devnm.h>
#endif
+#if defined(__FreeBSD__)
+
+#include <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpcsvc/rquota.h>
+#include <rpc/nettype.h>
+#include <rpc/xdr.h>
+
+static int quotastat;
+
+static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
+{
+ if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
+ return(0);
+ if (!xdr_int(xdrsp, &args->gqa_uid))
+ return(0);
+ return (1);
+}
+
+static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
+{
+ if (!xdr_int(xdrsp, &quotastat)) {
+ DEBUG(6,("nfs_quotas: Status bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
+ DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
+ DEBUG(6,("nfs_quotas: Active bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
+ DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
+ DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
+ return 0;
+ }
+ if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
+ DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
+ return 0;
+ }
+ return (1);
+}
+
+/* Works on FreeBSD, too. :-) */
+static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+ uid_t uid = euser_id;
+ struct dqblk D;
+ char *mnttype = nfspath;
+ CLIENT *clnt;
+ struct getquota_rslt gqr;
+ struct getquota_args args;
+ char *cutstr, *pathname, *host, *testpath;
+ int len;
+ static struct timeval timeout = {2,0};
+ enum clnt_stat clnt_stat;
+ BOOL ret = True;
+
+ *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
+
+ len=strcspn(mnttype, ":");
+ pathname=strstr(mnttype, ":");
+ cutstr = (char *) malloc(len+1);
+ if (!cutstr)
+ return False;
+
+ memset(cutstr, '\0', len+1);
+ host = strncat(cutstr,mnttype, sizeof(char) * len );
+ DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
+ DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
+ testpath=strchr_m(mnttype, ':');
+ args.gqa_pathp = testpath+1;
+ args.gqa_uid = uid;
+
+ DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
+
+ if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
+ ret = False;
+ goto out;
+ }
+
+ clnt->cl_auth = authunix_create_default();
+ DEBUG(9,("nfs_quotas: auth_success\n"));
+
+ clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, (const xdrproc_t) my_xdr_getquota_args, (caddr_t)&args, (const xdrproc_t) my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
+
+ if (clnt_stat != RPC_SUCCESS) {
+ DEBUG(9,("nfs_quotas: clnt_call fail\n"));
+ ret = False;
+ goto out;
+ }
+
+ /*
+ * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
+ * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
+ * something sensible.
+ */
+
+ switch ( quotastat ) {
+ case 0:
+ DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
+ ret = False;
+ goto out;
+
+ case 1:
+ DEBUG(9,("nfs_quotas: Good quota data\n"));
+ D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
+ D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
+ D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
+ break;
+
+ case 2:
+ case 3:
+ D.dqb_bsoftlimit = 1;
+ D.dqb_curblocks = 1;
+ DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
+ break;
+
+ default:
+ DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
+ break;
+ }
+
+ DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
+ quotastat,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
+ gqr.getquota_rslt_u.gqr_rquota.rq_active,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
+ gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
+ gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
+
+ if (D.dqb_bsoftlimit == 0)
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+ if (D.dqb_bsoftlimit == 0)
+ return False;
+
+ *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
+ *dsize = D.dqb_bsoftlimit;
+
+ if (D.dqb_curblocks == D.dqb_curblocks == 1)
+ *bsize = DEV_BSIZE;
+
+ if (D.dqb_curblocks > D.dqb_bsoftlimit) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+
+ out:
+
+ if (clnt) {
+ if (clnt->cl_auth)
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
+
+ DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
+
+ SAFE_FREE(cutstr);
+ DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
+ return ret;
+}
+
+#endif
+
/****************************************************************************
try to get the disk space from disk quotas - default version
****************************************************************************/
@@ -976,10 +1146,42 @@ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB
{
/* FreeBSD patches from Marty Moll <martym@arbor.edu> */
gid_t egrp_id;
-
+#if defined(__FreeBSD__)
+ SMB_DEV_T devno;
+ struct statfs *mnts;
+ SMB_STRUCT_STAT st;
+ int mntsize, i;
+
+ if (sys_stat(path,&st) < 0)
+ return False;
+ devno = st.st_dev;
+
+ mntsize = getmntinfo(&mnts,MNT_NOWAIT);
+ if (mntsize <= 0)
+ return False;
+
+ for (i = 0; i < mntsize; i++) {
+ if (sys_stat(mnts[i].f_mntonname,&st) < 0)
+ return False;
+ if (st.st_dev == devno)
+ break;
+ }
+ if (i == mntsize)
+ return False;
+#endif
+
save_re_uid();
set_effective_uid(0);
+#if defined(__FreeBSD__)
+ if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
+ BOOL retval;
+ retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
+ restore_re_uid();
+ return retval;
+ }
+#endif
+
egrp_id = getegid();
r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index 560208ae157..71efb793af0 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -43,7 +43,7 @@ extern BOOL global_encrypted_passwords_negotiated;
set.
****************************************************************************/
-NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
+NTSTATUS check_path_syntax(pstring destname, const pstring srcname, BOOL allow_wcard_names)
{
char *d = destname;
const char *s = srcname;
@@ -119,7 +119,21 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
s++;
} else {
if (!(*s & 0x80)) {
- *d++ = *s++;
+ if (allow_wcard_names) {
+ *d++ = *s++;
+ } else {
+ switch (*s) {
+ case '*':
+ case '?':
+ case '<':
+ case '>':
+ case '"':
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ default:
+ *d++ = *s++;
+ break;
+ }
+ }
} else {
switch(next_mb_char_size(s)) {
case 4:
@@ -147,7 +161,7 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
Pull a string and check the path - provide for error return.
****************************************************************************/
-size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err)
+size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err, BOOL allow_wcard_names)
{
pstring tmppath;
char *tmppath_ptr = tmppath;
@@ -161,7 +175,7 @@ size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len
} else {
ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
}
- *err = check_path_syntax(dest, tmppath);
+ *err = check_path_syntax(dest, tmppath, allow_wcard_names);
return ret;
}
@@ -516,7 +530,7 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
START_PROFILE(SMBchkpth);
- srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBchkpth);
return ERROR_NT(status);
@@ -525,6 +539,10 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
unix_convert(name,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ END_PROFILE(SMBchkpth);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
mode = SVAL(inbuf,smb_vwv0);
@@ -548,18 +566,11 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
* the parent directory is valid but not the
* last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
* for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
- * if the path is invalid.
+ * if the path is invalid. This is different from set_bad_path_error()
+ * in the non-NT error case.
*/
- if (bad_path) {
- END_PROFILE(SMBchkpth);
- return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
- } else {
- END_PROFILE(SMBchkpth);
- return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND);
- }
- } else if (errno == ENOTDIR) {
END_PROFILE(SMBchkpth);
- return ERROR_NT(NT_STATUS_NOT_A_DIRECTORY);
+ return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath);
}
END_PROFILE(SMBchkpth);
@@ -594,7 +605,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
START_PROFILE(SMBgetatr);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status);
+ p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBgetatr);
return ERROR_NT(status);
@@ -613,6 +624,10 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
ok = True;
} else {
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ END_PROFILE(SMBgetatr);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
if (check_name(fname,conn)) {
if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,fname,&sbuf) == 0) {
mode = dos_mode(conn,fname,&sbuf);
@@ -669,13 +684,17 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
START_PROFILE(SMBsetatr);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status);
+ p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBsetatr);
return ERROR_NT(status);
}
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ END_PROFILE(SMBsetatr);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
mode = SVAL(inbuf,smb_vwv0);
mtime = make_unix_date3(inbuf+smb_vwv1);
@@ -798,7 +817,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
maxentries = SVAL(inbuf,smb_vwv0);
dirtype = SVAL(inbuf,smb_vwv1);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &nt_status);
+ p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &nt_status, True);
if (!NT_STATUS_IS_OK(nt_status)) {
END_PROFILE(SMBsearch);
return ERROR_NT(nt_status);
@@ -976,7 +995,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
outsize = set_message(outbuf,1,0,True);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err);
+ p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err, True);
if (!NT_STATUS_IS_OK(err)) {
END_PROFILE(SMBfclose);
return ERROR_NT(err);
@@ -1028,7 +1047,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
share_mode = SVAL(inbuf,smb_vwv0);
- srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBopen);
return ERROR_NT(status);
@@ -1037,12 +1056,21 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ END_PROFILE(SMBopen);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
(uint32)dos_attr, oplock_request,&rmode,NULL);
if (!fsp) {
END_PROFILE(SMBopen);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ clear_cached_errors();
+ return -1;
+ }
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
}
@@ -1117,7 +1145,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
}
/* XXXX we need to handle passed times, sattr and flags */
- srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBopenX);
return ERROR_NT(status);
@@ -1126,12 +1154,21 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ END_PROFILE(SMBopenX);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,(uint32)smb_attr,
oplock_request, &rmode,&smb_action);
if (!fsp) {
END_PROFILE(SMBopenX);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ clear_cached_errors();
+ return -1;
+ }
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
}
@@ -1230,7 +1267,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
com = SVAL(inbuf,smb_com);
createmode = SVAL(inbuf,smb_vwv0);
- srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcreate);
return ERROR_NT(status);
@@ -1239,6 +1276,10 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ END_PROFILE(SMBcreate);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
if (createmode & aVOLID)
DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
@@ -1257,6 +1298,11 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (!fsp) {
END_PROFILE(SMBcreate);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ clear_cached_errors();
+ return -1;
+ }
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
}
@@ -1297,7 +1343,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
START_PROFILE(SMBctemp);
createattr = SVAL(inbuf,smb_vwv0);
- srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBctemp);
return ERROR_NT(status);
@@ -1311,6 +1357,10 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ END_PROFILE(SMBctemp);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
tmpfd = smb_mkstemp(fname);
if (tmpfd == -1) {
@@ -1332,6 +1382,11 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (!fsp) {
END_PROFILE(SMBctemp);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ clear_cached_errors();
+ return -1;
+ }
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
}
@@ -1373,15 +1428,20 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
Check if a user is allowed to rename a file.
********************************************************************/
-static NTSTATUS can_rename(char *fname,connection_struct *conn, SMB_STRUCT_STAT *pst)
+static NTSTATUS can_rename(char *fname,connection_struct *conn, uint16 dirtype, SMB_STRUCT_STAT *pst)
{
int smb_action;
int access_mode;
files_struct *fsp;
+ uint16 fmode;
if (!CAN_WRITE(conn))
return NT_STATUS_MEDIA_WRITE_PROTECTED;
-
+
+ fmode = dos_mode(conn,fname,pst);
+ if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
+ return NT_STATUS_NO_SUCH_FILE;
+
if (S_ISDIR(pst->st_mode))
return NT_STATUS_OK;
@@ -1561,7 +1621,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
/* Quick check for "." and ".." */
if (fname[0] == '.') {
if (!fname[1] || (fname[1] == '.' && !fname[2])) {
- if ((dirtype & aDIR)) {
+ if ((dirtype & FILE_ATTRIBUTE_DIRECTORY) && (dirtype & FILE_ATTRIBUTE_SYSTEM)) {
sys_direntry = True;
} else {
continue;
@@ -1574,6 +1634,8 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
if (sys_direntry) {
error = NT_STATUS_OBJECT_NAME_INVALID;
+ DEBUG(3,("unlink_internals: system directory delete denied [%s] mask [%s]\n",
+ fname, mask));
break;
}
@@ -1612,7 +1674,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
dirtype = SVAL(inbuf,smb_vwv0);
- srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status, True);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBunlink);
return ERROR_NT(status);
@@ -1623,8 +1685,14 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
DEBUG(3,("reply_unlink : %s\n",name));
status = unlink_internals(conn, dirtype, name);
- if (!NT_STATUS_IS_OK(status))
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ clear_cached_errors();
+ return -1;
+ }
return ERROR_NT(status);
+ }
/*
* Win2k needs a changenotify request response before it will
@@ -1661,12 +1729,13 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
#if defined(WITH_SENDFILE)
/*
- * We can only use sendfile on a non-chained packet and on a file
- * that is exclusively oplocked. reply_readbraw has already checked the length.
+ * We can only use sendfile on a non-chained packet
+ * but we can use on a non-oplocked file. tridge proved this
+ * on a train in Germany :-). JRA.
+ * reply_readbraw has already checked the length.
*/
- if ((nread > 0) && (lp_write_cache_size(SNUM(conn)) == 0) &&
- EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && lp_use_sendfile(SNUM(conn)) ) {
+ if ((nread > 0) && (lp_write_cache_size(SNUM(conn)) == 0) && lp_use_sendfile(SNUM(conn)) ) {
DATA_BLOB header;
_smb_setlen(outbuf,nread);
@@ -1999,12 +2068,13 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
#if defined(WITH_SENDFILE)
/*
- * We can only use sendfile on a non-chained packet and on a file
- * that is exclusively oplocked.
+ * We can only use sendfile on a non-chained packet
+ * but we can use on a non-oplocked file. tridge proved this
+ * on a train in Germany :-). JRA.
*/
- if ((CVAL(inbuf,smb_vwv0) == 0xFF) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) &&
- lp_use_sendfile(SNUM(conn)) && (lp_write_cache_size(SNUM(conn)) == 0) ) {
+ if ((CVAL(inbuf,smb_vwv0) == 0xFF) && lp_use_sendfile(SNUM(conn)) &&
+ (lp_write_cache_size(SNUM(conn)) == 0) ) {
SMB_STRUCT_STAT sbuf;
DATA_BLOB header;
@@ -3138,15 +3208,16 @@ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
return NT_STATUS_OBJECT_NAME_INVALID;
}
+ if (bad_path) {
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
if (check_name(directory, conn))
ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
if (ret == -1) {
if(errno == ENOENT) {
- if (bad_path)
- return NT_STATUS_OBJECT_PATH_NOT_FOUND;
- else
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
return map_nt_error_from_unix(errno);
}
@@ -3165,7 +3236,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
NTSTATUS status;
START_PROFILE(SMBmkdir);
- srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmkdir);
return ERROR_NT(status);
@@ -3335,7 +3406,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
NTSTATUS status;
START_PROFILE(SMBrmdir);
- srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBrmdir);
return ERROR_NT(status);
@@ -3344,6 +3415,10 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
unix_convert(directory,conn, NULL,&bad_path,&sbuf);
+ if (bad_path) {
+ END_PROFILE(SMBrmdir);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
if (check_name(directory,conn)) {
dptr_closepath(directory,SVAL(inbuf,smb_pid));
@@ -3475,7 +3550,7 @@ static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T
Rename an open file - given an fsp.
****************************************************************************/
-NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, BOOL replace_if_exists)
+NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, uint16 attrs, BOOL replace_if_exists)
{
SMB_STRUCT_STAT sbuf;
BOOL bad_path = False;
@@ -3556,7 +3631,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
return NT_STATUS_OBJECT_NAME_COLLISION;
}
- error = can_rename(newname,conn,&sbuf);
+ error = can_rename(newname,conn,attrs,&sbuf);
if (dest_exists && !NT_STATUS_IS_OK(error)) {
DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
@@ -3762,7 +3837,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
return NT_STATUS_OBJECT_PATH_NOT_FOUND;
}
- error = can_rename(directory,conn,&sbuf1);
+ error = can_rename(directory,conn,attrs,&sbuf1);
if (!NT_STATUS_IS_OK(error)) {
DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
@@ -3853,7 +3928,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error)));
continue;
}
- error = can_rename(fname,conn,&sbuf1);
+ error = can_rename(fname,conn,attrs,&sbuf1);
if (!NT_STATUS_IS_OK(error)) {
DEBUG(6,("rename %s refused\n", fname));
continue;
@@ -3924,13 +3999,13 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
START_PROFILE(SMBmv);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status);
+ p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, True);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
return ERROR_NT(status);
}
p++;
- p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status);
+ p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, True);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
return ERROR_NT(status);
@@ -3944,6 +4019,11 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
status = rename_internals(conn, name, newname, attrs, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ clear_cached_errors();
+ return -1;
+ }
return ERROR_NT(status);
}
@@ -3989,7 +4069,8 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
return(False);
fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),FILE_ATTRIBUTE_NORMAL,0,&Access,&action);
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),FILE_ATTRIBUTE_NORMAL,INTERNAL_OPEN_ONLY,
+ &Access,&action);
if (!fsp1)
return(False);
@@ -4002,7 +4083,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
ZERO_STRUCTP(&sbuf2);
fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
- ofun,dosattrs,0,&Access,&action);
+ ofun,dosattrs,INTERNAL_OPEN_ONLY,&Access,&action);
if (!fsp2) {
close_file(fsp1,False);
@@ -4070,12 +4151,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
*directory = *mask = 0;
p = smb_buf(inbuf);
- p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status);
+ p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, True);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcopy);
return ERROR_NT(status);
}
- p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status);
+ p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, True);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcopy);
return ERROR_NT(status);
@@ -4235,7 +4316,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
- srvstr_get_path(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(pathworks_setdir);
return ERROR_NT(status);
diff --git a/source/smbd/server.c b/source/smbd/server.c
index 343a835be8a..c3e0da542e2 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -494,18 +494,16 @@ BOOL reload_services(BOOL test)
load_interfaces();
- {
- if (smbd_server_fd() != -1) {
- set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
- set_socket_options(smbd_server_fd(), user_socket_options);
- }
+ if (smbd_server_fd() != -1) {
+ set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
+ set_socket_options(smbd_server_fd(), user_socket_options);
}
mangle_reset_cache();
reset_stat_cache();
/* this forces service parameters to be flushed */
- set_current_service(NULL,True);
+ set_current_service(NULL,0,True);
return(ret);
}
diff --git a/source/smbd/service.c b/source/smbd/service.c
index c74537c299e..3b499d5cc1d 100644
--- a/source/smbd/service.c
+++ b/source/smbd/service.c
@@ -28,10 +28,11 @@ extern userdom_struct current_user_info;
Load parameters specific to a connection/service.
****************************************************************************/
-BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
+BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
{
extern char magic_char;
static connection_struct *last_conn;
+ static uint16 last_flags;
int snum;
if (!conn) {
@@ -51,10 +52,24 @@ BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
return(False);
}
- if (conn == last_conn)
+ if ((conn == last_conn) && (last_flags == flags)) {
return(True);
+ }
last_conn = conn;
+ last_flags = flags;
+
+ /* Obey the client case sensitivity requests - only for clients that support it. */
+ if (lp_casesensitive(snum) == Auto) {
+ /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
+ enum remote_arch_types ra_type = get_remote_arch();
+ if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
+ /* Client can't support per-packet case sensitive pathnames. */
+ conn->case_sensitive = False;
+ } else {
+ conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
+ }
+ }
magic_char = lp_magicchar(snum);
return(True);
@@ -347,7 +362,13 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
conn->dirptr = NULL;
/* Case options for the share. */
- conn->case_sensitive = lp_casesensitive(snum);
+ if (lp_casesensitive(snum) == Auto) {
+ /* We will be setting this per packet. Set to be case insensitive for now. */
+ conn->case_sensitive = False;
+ } else {
+ conn->case_sensitive = (BOOL)lp_casesensitive(snum);
+ }
+
conn->case_preserve = lp_preservecase(snum);
conn->short_case_preserve = lp_shortpreservecase(snum);
@@ -499,6 +520,20 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
return NULL;
}
+ /*
+ * If widelinks are disallowed we need to canonicalise the
+ * connect path here to ensure we don't have any symlinks in
+ * the connectpath. We will be checking all paths on this
+ * connection are below this directory. We must do this after
+ * the VFS init as we depend on the realpath() pointer in the vfs table. JRA.
+ */
+ if (!lp_widelinks(snum)) {
+ pstring s;
+ pstrcpy(s,conn->connectpath);
+ canonicalize_path(conn, s);
+ string_set(&conn->connectpath,s);
+ }
+
/* ROOT Activities: */
/* check number of connections */
if (!claim_connection(conn,
diff --git a/source/smbd/session.c b/source/smbd/session.c
index 61118f13dd9..91ebaeb830b 100644
--- a/source/smbd/session.c
+++ b/source/smbd/session.c
@@ -34,8 +34,8 @@ BOOL session_init(void)
if (tdb)
return True;
- tdb = tdb_open_ex(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
- O_RDWR | O_CREAT, 0644, smbd_tdb_log);
+ tdb = tdb_open_log(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
if (!tdb) {
DEBUG(1,("session_init: failed to open sessionid tdb\n"));
return False;
diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c
index 8a56478929f..0122b662ebf 100644
--- a/source/smbd/sesssetup.c
+++ b/source/smbd/sesssetup.c
@@ -152,7 +152,6 @@ static int reply_spnego_kerberos(connection_struct *conn,
auth_serversupplied_info *server_info = NULL;
DATA_BLOB session_key = data_blob(NULL, 0);
uint8 tok_id[2];
- BOOL foreign = False;
DATA_BLOB nullblob = data_blob(NULL, 0);
fstring real_username;
@@ -197,7 +196,6 @@ static int reply_spnego_kerberos(connection_struct *conn,
SAFE_FREE(client);
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
- foreign = True;
}
/* this gives a fully qualified user name (ie. with full realm).
@@ -244,6 +242,8 @@ static int reply_spnego_kerberos(connection_struct *conn,
/* lookup the passwd struct, create a new user if necessary */
+ map_username( user );
+
pw = smb_getpwnam( user, real_username, True );
if (!pw) {
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 738d12e020f..a7db9daf7d6 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -607,7 +607,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
if (IS_IPC(conn))
return(ERROR_DOS(ERRSRV,ERRaccess));
- srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
@@ -618,6 +618,9 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
/* XXXX we need to handle passed times, sattr and flags */
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
if (!check_name(fname,conn)) {
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
@@ -627,6 +630,11 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
oplock_request, &rmode,&smb_action);
if (!fsp) {
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ clear_cached_errors();
+ return -1;
+ }
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
@@ -1371,7 +1379,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
return(ERROR_DOS(ERRDOS,ERRunknownlevel));
}
- srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus);
+ srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, True);
if (!NT_STATUS_IS_OK(ntstatus)) {
return ERROR_NT(ntstatus);
}
@@ -1379,6 +1387,9 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf);
unix_convert(directory,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
if(!check_name(directory,conn)) {
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
@@ -1564,7 +1575,7 @@ static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbu
*mask = *directory = *resume_name = 0;
- srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus);
+ srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus, True);
if (!NT_STATUS_IS_OK(ntstatus)) {
return ERROR_NT(ntstatus);
}
@@ -2257,6 +2268,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
if (!params)
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ ZERO_STRUCT(sbuf);
+
if (tran_call == TRANSACT2_QFILEINFO) {
if (total_params < 4)
return(ERROR_DOS(ERRDOS,ERRinvalidparam));
@@ -2272,11 +2285,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
*/
pstrcpy(fname, fsp->fsp_name);
- unix_convert(fname,conn,0,&bad_path,&sbuf);
- if (!check_name(fname,conn)) {
- DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed for fake_file(%s)\n",fname,strerror(errno)));
- return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
- }
+ /* We know this name is ok, it's already passed the checks. */
} else if(fsp && (fsp->is_directory || fsp->fd == -1)) {
/*
@@ -2284,12 +2293,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
* handle (returned from an NT SMB). NT5.0 seems
* to do this call. JRA.
*/
+ /* We know this name is ok, it's already passed the checks. */
pstrcpy(fname, fsp->fsp_name);
- unix_convert(fname,conn,0,&bad_path,&sbuf);
- if (!check_name(fname,conn)) {
- DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
- return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
- }
if (INFO_LEVEL_IS_UNIX(info_level)) {
/* Always do lstat for UNIX calls. */
@@ -2297,7 +2302,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
- } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
+ } else if (SMB_VFS_STAT(conn,fname,&sbuf)) {
DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
@@ -2329,7 +2334,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
- srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
@@ -2337,6 +2342,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
if (!check_name(fname,conn)) {
DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
@@ -2871,7 +2879,6 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
BOOL bad_path_oldname = False;
BOOL bad_path_newname = False;
SMB_STRUCT_STAT sbuf1, sbuf2;
- BOOL rc, rcdest;
pstring last_component_oldname;
pstring last_component_newname;
NTSTATUS status = NT_STATUS_OK;
@@ -2884,8 +2891,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
}
- rc = unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
- if (!rc && bad_path_oldname) {
+ unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
+ if (bad_path_oldname) {
return NT_STATUS_OBJECT_PATH_NOT_FOUND;
}
@@ -2905,8 +2912,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
return NT_STATUS_ACCESS_DENIED;
}
- rcdest = unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
- if (!rcdest && bad_path_newname) {
+ unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
+ if (bad_path_newname) {
return NT_STATUS_OBJECT_PATH_NOT_FOUND;
}
@@ -2974,6 +2981,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
if (!params)
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ ZERO_STRUCT(sbuf);
+
if (tran_call == TRANSACT2_SETFILEINFO) {
if (total_params < 4)
return(ERROR_DOS(ERRDOS,ERRinvalidparam));
@@ -2988,8 +2997,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
* to do this call. JRA.
*/
pstrcpy(fname, fsp->fsp_name);
- unix_convert(fname,conn,0,&bad_path,&sbuf);
- if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) {
+ if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) {
DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
@@ -3027,11 +3035,14 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
return(ERROR_DOS(ERRDOS,ERRinvalidparam));
info_level = SVAL(params,0);
- srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
/*
* For CIFS UNIX extensions the target name may not exist.
@@ -3205,7 +3216,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
SET_OPEN_MODE(DOS_OPEN_RDWR),
(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
FILE_ATTRIBUTE_NORMAL,
- 0, &access_mode, &action);
+ INTERNAL_OPEN_ONLY, &access_mode, &action);
if (new_fsp == NULL)
return(UNIXERROR(ERRDOS,ERRbadpath));
@@ -3374,14 +3385,15 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
return(ERROR_DOS(ERRDOS,ERRnoaccess));
if (file_type != UNIX_TYPE_CHARDEV && file_type != UNIX_TYPE_BLKDEV &&
- file_type != UNIX_TYPE_FIFO)
+ file_type != UNIX_TYPE_FIFO &&
+ file_type != UNIX_TYPE_SOCKET)
return(ERROR_DOS(ERRDOS,ERRnoaccess));
DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \
0%o for file %s\n", (double)dev, unixmode, fname ));
/* Ok - do the mknod. */
- if (SMB_VFS_MKNOD(conn,dos_to_unix_static(fname), unixmode, dev) != 0)
+ if (SMB_VFS_MKNOD(conn,fname, unixmode, dev) != 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
inherit_access_acl(conn, fname, unixmode);
@@ -3482,7 +3494,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
char *newname = fname;
/* Set a hard link. */
- srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
@@ -3515,7 +3527,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
overwrite = (CVAL(pdata,0) ? True : False);
root_fid = IVAL(pdata,4);
len = IVAL(pdata,8);
- srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status);
+ srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status, False);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
@@ -3538,7 +3550,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
if (fsp) {
DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
fsp->fnum, fsp->fsp_name, base_name ));
- status = rename_internals_fsp(conn, fsp, base_name, overwrite);
+ status = rename_internals_fsp(conn, fsp, base_name, 0, overwrite);
} else {
DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
fname, newname ));
@@ -3654,7 +3666,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
SET_OPEN_MODE(DOS_OPEN_RDWR),
(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
FILE_ATTRIBUTE_NORMAL,
- 0, &access_mode, &action);
+ INTERNAL_OPEN_ONLY, &access_mode, &action);
if (new_fsp == NULL)
return(UNIXERROR(ERRDOS,ERRbadpath));
@@ -3695,7 +3707,7 @@ static int call_trans2mkdir(connection_struct *conn,
if (total_params < 4)
return(ERROR_DOS(ERRDOS,ERRinvalidparam));
- srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE, &status, False);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
@@ -3703,6 +3715,9 @@ static int call_trans2mkdir(connection_struct *conn,
DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
unix_convert(directory,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
if (check_name(directory,conn))
ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
diff --git a/source/smbd/uid.c b/source/smbd/uid.c
index e1864c74caa..de2f96450fc 100644
--- a/source/smbd/uid.c
+++ b/source/smbd/uid.c
@@ -125,6 +125,13 @@ static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
readonly_share = is_share_read_only_for_user(conn, vuser);
+ if (!readonly_share &&
+ !share_access_check(conn, snum, vuser, FILE_WRITE_DATA)) {
+ /* smb.conf allows r/w, but the security descriptor denies
+ * write. Fall back to looking at readonly. */
+ readonly_share = True;
+ }
+
if (!share_access_check(conn, snum, vuser, readonly_share ? FILE_READ_DATA : FILE_WRITE_DATA)) {
return False;
}
diff --git a/source/smbd/utmp.c b/source/smbd/utmp.c
index a521d0113d4..b1735dfcc49 100644
--- a/source/smbd/utmp.c
+++ b/source/smbd/utmp.c
@@ -514,10 +514,10 @@ static BOOL sys_utmp_fill(struct utmp *u,
* But note that we do the more precise ut_tv as the final assignment.
*/
#if defined(HAVE_UT_UT_TIME)
- gettimeofday(&timeval, NULL);
+ GetTimeOfDay(&timeval);
u->ut_time = timeval.tv_sec;
#elif defined(HAVE_UT_UT_TV)
- gettimeofday(&timeval, NULL);
+ GetTimeOfDay(&timeval);
u->ut_tv = timeval;
#else
#error "with-utmp must have UT_TIME or UT_TV"
diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c
index a415e0470e2..13cfdac0f35 100644
--- a/source/smbd/vfs.c
+++ b/source/smbd/vfs.c
@@ -784,6 +784,31 @@ char *vfs_GetWd(connection_struct *conn, char *path)
return (path);
}
+BOOL canonicalize_path(connection_struct *conn, pstring path)
+{
+#ifdef REALPATH_TAKES_NULL
+ char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
+ if (!resolved_name) {
+ return False;
+ }
+ pstrcpy(path, resolved_name);
+ SAFE_FREE(resolved_name);
+ return True;
+#else
+#ifdef PATH_MAX
+ char resolved_name_buf[PATH_MAX+1];
+#else
+ pstring resolved_name_buf;
+#endif
+ char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
+ if (!resolved_name) {
+ return False;
+ }
+ pstrcpy(path, resolved_name);
+ return True;
+#endif /* REALPATH_TAKES_NULL */
+}
+
/*******************************************************************
Reduce a file name, removing .. elements and checking that
it is below dir in the heirachy. This uses realpath.
@@ -804,6 +829,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
char *resolved_name = NULL;
size_t con_path_len = strlen(conn->connectpath);
char *p = NULL;
+ int saved_errno = errno;
DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
@@ -817,6 +843,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
switch (errno) {
case ENOTDIR:
DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
+ errno = saved_errno;
return False;
case ENOENT:
{
@@ -841,6 +868,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
#endif
if (!resolved_name) {
DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
+ errno = saved_errno;
return False;
}
pstrcpy(tmp_fname, resolved_name);
@@ -851,6 +879,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
resolved_name = strdup(tmp_fname);
if (!resolved_name) {
DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
+ errno = saved_errno;
return False;
}
#else
@@ -865,6 +894,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
}
default:
DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
+ errno = saved_errno;
return False;
}
}
@@ -875,13 +905,15 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
if (free_resolved_name)
SAFE_FREE(resolved_name);
+ errno = saved_errno;
return False;
}
if (strncmp(conn->connectpath, resolved_name, con_path_len) != 0) {
- DEBUG(2, ("reduce_name: Bad access attemt: %s is a symlink outside the share path", fname));
+ DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
if (free_resolved_name)
SAFE_FREE(resolved_name);
+ errno = EACCES;
return False;
}
@@ -900,11 +932,13 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",fname));
if (free_resolved_name)
SAFE_FREE(resolved_name);
+ errno = EACCES;
return False;
}
DEBUG(3,("reduce_name: %s reduced to %s\n", fname, p));
if (free_resolved_name)
SAFE_FREE(resolved_name);
+ errno = saved_errno;
return(True);
}
diff --git a/source/tdb/Makefile b/source/tdb/Makefile
index 59fbb079bd0..92bc33a661e 100644
--- a/source/tdb/Makefile
+++ b/source/tdb/Makefile
@@ -5,11 +5,14 @@
CFLAGS = -DSTANDALONE -DTDB_DEBUG -g -DHAVE_MMAP=1
CC = gcc
+ADMINPROGS = tdbdump tdbbackup
PROGS = tdbtest tdbtool tdbtorture
-TDB_OBJ = tdb.o spinlock.o
+TDB_OBJ = tdb.o spinlock.o tdbback.o
default: $(PROGS)
+admintools: $(ADMINPROGS)
+
tdbtest: tdbtest.o $(TDB_OBJ)
$(CC) $(CFLAGS) -o tdbtest tdbtest.o $(TDB_OBJ) -lgdbm
diff --git a/source/torture/torture.c b/source/torture/torture.c
index 161aa2cd73b..e3960d34061 100644
--- a/source/torture/torture.c
+++ b/source/torture/torture.c
@@ -45,12 +45,12 @@ static struct timeval tp1,tp2;
void start_timer(void)
{
- gettimeofday(&tp1,NULL);
+ GetTimeOfDay(&tp1);
}
double end_timer(void)
{
- gettimeofday(&tp2,NULL);
+ GetTimeOfDay(&tp2);
return((tp2.tv_sec - tp1.tv_sec) +
(tp2.tv_usec - tp1.tv_usec)*1.0e-6);
}
diff --git a/source/torture/vfstest.c b/source/torture/vfstest.c
index 88fe3486493..48556aa2570 100644
--- a/source/torture/vfstest.c
+++ b/source/torture/vfstest.c
@@ -466,7 +466,7 @@ BOOL reload_services(BOOL test)
reset_stat_cache();
/* this forces service parameters to be flushed */
- set_current_service(NULL,True);
+ set_current_service(NULL,0,True);
return (ret);
}
diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c
index 6eec71aedf3..b25303a97e0 100644
--- a/source/utils/net_ads.c
+++ b/source/utils/net_ads.c
@@ -55,6 +55,8 @@ int net_ads_usage(int argc, const char **argv)
"\n\tperform a raw LDAP search and dump the results\n"
"\nnet ads dn"\
"\n\tperform a raw LDAP search and dump attributes of a particular DN\n"
+"\nnet ads keytab"\
+"\n\tcreates and updates the kerberos system keytab file\n"
);
return -1;
}
@@ -109,8 +111,8 @@ static int net_ads_info(int argc, const char **argv)
d_printf("LDAP port: %d\n", ads->ldap_port);
d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
- d_printf("KDC server: %s\n", ads->auth.kdc_server );
- d_printf("Server time offset: %d\n", ads->auth.time_offset );
+ d_printf("KDC server: %s\n", ads->auth.kdc_server );
+ d_printf("Server time offset: %d\n", ads->auth.time_offset );
return 0;
}
@@ -214,6 +216,7 @@ static int net_ads_workgroup(int argc, const char **argv)
if (!(ads = ads_startup())) return -1;
if (!(ctx = talloc_init("net_ads_workgroup"))) {
+ ads_destroy(&ads);
return -1;
}
@@ -221,13 +224,14 @@ static int net_ads_workgroup(int argc, const char **argv)
d_printf("Failed to find workgroup for realm '%s'\n",
ads->config.realm);
talloc_destroy(ctx);
+ ads_destroy(&ads);
return -1;
}
d_printf("Workgroup: %s\n", workgroup);
talloc_destroy(ctx);
-
+ ads_destroy(&ads);
return 0;
}
@@ -274,7 +278,9 @@ static int ads_user_add(int argc, const char **argv)
if (argc < 1) return net_ads_user_usage(argc, argv);
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
status = ads_find_user_acct(ads, &res, argv[0]);
@@ -342,13 +348,18 @@ static int ads_user_info(int argc, const char **argv)
char **grouplist;
char *escaped_user = escape_ldap_string_alloc(argv[0]);
- if (argc < 1) return net_ads_user_usage(argc, argv);
+ if (argc < 1) {
+ return net_ads_user_usage(argc, argv);
+ }
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
if (!escaped_user) {
d_printf("ads_user_info: failed to escape user %s\n", argv[0]);
- return -1;
+ ads_destroy(&ads);
+ return -1;
}
asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
@@ -357,6 +368,7 @@ static int ads_user_info(int argc, const char **argv)
if (!ADS_ERR_OK(rc)) {
d_printf("ads_search: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
@@ -374,7 +386,6 @@ static int ads_user_info(int argc, const char **argv)
}
ads_msgfree(ads, res);
-
ads_destroy(&ads);
return 0;
}
@@ -386,13 +397,18 @@ static int ads_user_delete(int argc, const char **argv)
void *res;
char *userdn;
- if (argc < 1) return net_ads_user_usage(argc, argv);
+ if (argc < 1) {
+ return net_ads_user_usage(argc, argv);
+ }
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
rc = ads_find_user_acct(ads, &res, argv[0]);
if (!ADS_ERR_OK(rc)) {
DEBUG(0, ("User %s does not exist\n", argv[0]));
+ ads_destroy(&ads);
return -1;
}
userdn = ads_get_dn(ads, res);
@@ -401,10 +417,12 @@ static int ads_user_delete(int argc, const char **argv)
ads_memfree(ads, userdn);
if (!ADS_ERR_OK(rc)) {
d_printf("User %s deleted\n", argv[0]);
+ ads_destroy(&ads);
return 0;
}
d_printf("Error deleting user %s: %s\n", argv[0],
ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
@@ -423,7 +441,9 @@ int net_ads_user(int argc, const char **argv)
char *disp_fields[2] = {NULL, NULL};
if (argc == 0) {
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
if (opt_long_list_entries)
d_printf("\nUser name Comment"\
@@ -454,9 +474,13 @@ static int ads_group_add(int argc, const char **argv)
void *res=NULL;
int rc = -1;
- if (argc < 1) return net_ads_group_usage(argc, argv);
+ if (argc < 1) {
+ return net_ads_group_usage(argc, argv);
+ }
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
status = ads_find_user_acct(ads, &res, argv[0]);
@@ -495,13 +519,18 @@ static int ads_group_delete(int argc, const char **argv)
void *res;
char *groupdn;
- if (argc < 1) return net_ads_group_usage(argc, argv);
+ if (argc < 1) {
+ return net_ads_group_usage(argc, argv);
+ }
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
rc = ads_find_user_acct(ads, &res, argv[0]);
if (!ADS_ERR_OK(rc)) {
DEBUG(0, ("Group %s does not exist\n", argv[0]));
+ ads_destroy(&ads);
return -1;
}
groupdn = ads_get_dn(ads, res);
@@ -510,10 +539,12 @@ static int ads_group_delete(int argc, const char **argv)
ads_memfree(ads, groupdn);
if (!ADS_ERR_OK(rc)) {
d_printf("Group %s deleted\n", argv[0]);
+ ads_destroy(&ads);
return 0;
}
d_printf("Error deleting group %s: %s\n", argv[0],
ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
@@ -531,7 +562,9 @@ int net_ads_group(int argc, const char **argv)
char *disp_fields[2] = {NULL, NULL};
if (argc == 0) {
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
if (opt_long_list_entries)
d_printf("\nGroup name Comment"\
@@ -555,21 +588,25 @@ static int net_ads_status(int argc, const char **argv)
ADS_STATUS rc;
void *res;
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
rc = ads_find_machine_acct(ads, &res, global_myname());
if (!ADS_ERR_OK(rc)) {
d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
if (ads_count_replies(ads, res) == 0) {
d_printf("No machine account for '%s' found\n", global_myname());
+ ads_destroy(&ads);
return -1;
}
ads_dump(ads, res);
-
+ ads_destroy(&ads);
return 0;
}
@@ -593,13 +630,14 @@ static int net_ads_leave(int argc, const char **argv)
rc = ads_leave_realm(ads, global_myname());
if (!ADS_ERR_OK(rc)) {
- d_printf("Failed to delete host '%s' from the '%s' realm.\n",
- global_myname(), ads->config.realm);
- return -1;
+ d_printf("Failed to delete host '%s' from the '%s' realm.\n",
+ global_myname(), ads->config.realm);
+ ads_destroy(&ads);
+ return -1;
}
d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
-
+ ads_destroy(&ads);
return 0;
}
@@ -659,7 +697,9 @@ int net_ads_join(int argc, const char **argv)
const char *short_domain_name = NULL;
TALLOC_CTX *ctx = NULL;
- if (argc > 0) org_unit = argv[0];
+ if (argc > 0) {
+ org_unit = argv[0];
+ }
if (!secrets_init()) {
DEBUG(1,("Failed to initialise secrets database\n"));
@@ -669,15 +709,19 @@ int net_ads_join(int argc, const char **argv)
tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
password = strdup(tmp_password);
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
if (!*lp_realm()) {
d_printf("realm must be set in in smb.conf for ADS join to succeed.\n");
+ ads_destroy(&ads);
return -1;
}
if (strcmp(ads->config.realm, lp_realm()) != 0) {
d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads->config.realm, lp_realm());
+ ads_destroy(&ads);
return -1;
}
@@ -691,35 +735,41 @@ int net_ads_join(int argc, const char **argv)
if (rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) {
d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n",
org_unit, dn);
+ ads_destroy(&ads);
return -1;
}
free(dn);
if (!ADS_ERR_OK(rc)) {
d_printf("ads_join_realm: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
rc = ads_join_realm(ads, global_myname(), account_type, org_unit);
if (!ADS_ERR_OK(rc)) {
d_printf("ads_join_realm: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
rc = ads_domain_sid(ads, &dom_sid);
if (!ADS_ERR_OK(rc)) {
d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
- return -1;
+ ads_destroy(&ads);
+ return -1;
}
if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
d_printf("asprintf failed\n");
+ ads_destroy(&ads);
return -1;
}
rc = ads_set_machine_password(ads, machine_account, password);
if (!ADS_ERR_OK(rc)) {
d_printf("ads_set_machine_password: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
@@ -727,6 +777,7 @@ int net_ads_join(int argc, const char **argv)
if ( !(ctx = talloc_init("net ads join")) ) {
d_printf("talloc_init() failed!\n");
+ ads_destroy(&ads);
return -1;
}
@@ -738,9 +789,9 @@ int net_ads_join(int argc, const char **argv)
d_printf("Using the name [%s] from the server.\n", short_domain_name);
d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name);
}
- }
- else
+ } else {
short_domain_name = lp_workgroup();
+ }
d_printf("Using short domain name -- %s\n", short_domain_name);
@@ -751,30 +802,41 @@ int net_ads_join(int argc, const char **argv)
if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
DEBUG(1,("Failed to save domain sid\n"));
+ ads_destroy(&ads);
return -1;
}
if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) {
DEBUG(1,("Failed to save machine password\n"));
+ ads_destroy(&ads);
return -1;
}
if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
DEBUG(1,("Failed to save domain sid\n"));
+ ads_destroy(&ads);
return -1;
}
if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) {
DEBUG(1,("Failed to save machine password\n"));
+ ads_destroy(&ads);
return -1;
}
+ /* Now build the keytab, using the same ADS connection */
+ if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
+ DEBUG(1,("Error creating host keytab!\n"));
+ }
+
d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm);
SAFE_FREE(password);
SAFE_FREE(machine_account);
- if ( ctx )
+ if ( ctx ) {
talloc_destroy(ctx);
+ }
+ ads_destroy(&ads);
return 0;
}
@@ -801,26 +863,29 @@ static int net_ads_printer_search(int argc, const char **argv)
ADS_STATUS rc;
void *res = NULL;
- if (!(ads = ads_startup()))
+ if (!(ads = ads_startup())) {
return -1;
+ }
rc = ads_find_printers(ads, &res);
if (!ADS_ERR_OK(rc)) {
d_printf("ads_find_printer: %s\n", ads_errstr(rc));
ads_msgfree(ads, res);
- return -1;
+ ads_destroy(&ads);
+ return -1;
}
if (ads_count_replies(ads, res) == 0) {
d_printf("No results found\n");
ads_msgfree(ads, res);
+ ads_destroy(&ads);
return -1;
}
ads_dump(ads, res);
ads_msgfree(ads, res);
-
+ ads_destroy(&ads);
return 0;
}
@@ -831,34 +896,41 @@ static int net_ads_printer_info(int argc, const char **argv)
const char *servername, *printername;
void *res = NULL;
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
- if (argc > 0)
+ if (argc > 0) {
printername = argv[0];
- else
+ } else {
printername = "*";
+ }
- if (argc > 1)
+ if (argc > 1) {
servername = argv[1];
- else
+ } else {
servername = global_myname();
+ }
rc = ads_find_printer_on_server(ads, &res, printername, servername);
if (!ADS_ERR_OK(rc)) {
d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
ads_msgfree(ads, res);
+ ads_destroy(&ads);
return -1;
}
if (ads_count_replies(ads, res) == 0) {
d_printf("Printer '%s' not found\n", printername);
ads_msgfree(ads, res);
+ ads_destroy(&ads);
return -1;
}
ads_dump(ads, res);
ads_msgfree(ads, res);
+ ads_destroy(&ads);
return 0;
}
@@ -881,17 +953,21 @@ static int net_ads_printer_publish(int argc, const char **argv)
char *prt_dn, *srv_dn, **srv_cn;
void *res = NULL;
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
- if (argc < 1)
+ if (argc < 1) {
return net_ads_printer_usage(argc, argv);
+ }
printername = argv[0];
- if (argc == 2)
+ if (argc == 2) {
servername = argv[1];
- else
+ } else {
servername = global_myname();
+ }
/* Get printer data from SPOOLSS */
@@ -908,6 +984,7 @@ static int net_ads_printer_publish(int argc, const char **argv)
if (NT_STATUS_IS_ERR(nt_status)) {
d_printf("Unable to open a connnection to %s to obtain data "
"for %s\n", servername, printername);
+ ads_destroy(&ads);
return -1;
}
@@ -918,6 +995,7 @@ static int net_ads_printer_publish(int argc, const char **argv)
if (ads_count_replies(ads, res) == 0) {
d_printf("Could not find machine account for server %s\n",
servername);
+ ads_destroy(&ads);
return -1;
}
@@ -932,10 +1010,12 @@ static int net_ads_printer_publish(int argc, const char **argv)
rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
if (!ADS_ERR_OK(rc)) {
d_printf("ads_publish_printer: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
d_printf("published printer\n");
+ ads_destroy(&ads);
return 0;
}
@@ -948,27 +1028,33 @@ static int net_ads_printer_remove(int argc, const char **argv)
char *prt_dn;
void *res = NULL;
- if (!(ads = ads_startup())) return -1;
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
- if (argc < 1)
+ if (argc < 1) {
return net_ads_printer_usage(argc, argv);
+ }
- if (argc > 1)
+ if (argc > 1) {
servername = argv[1];
- else
+ } else {
servername = global_myname();
+ }
rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
if (!ADS_ERR_OK(rc)) {
d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc));
ads_msgfree(ads, res);
+ ads_destroy(&ads);
return -1;
}
if (ads_count_replies(ads, res) == 0) {
d_printf("Printer '%s' not found\n", argv[1]);
ads_msgfree(ads, res);
+ ads_destroy(&ads);
return -1;
}
@@ -979,9 +1065,11 @@ static int net_ads_printer_remove(int argc, const char **argv)
if (!ADS_ERR_OK(rc)) {
d_printf("ads_del_dn: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
+ ads_destroy(&ads);
return 0;
}
@@ -1001,116 +1089,123 @@ static int net_ads_printer(int argc, const char **argv)
static int net_ads_password(int argc, const char **argv)
{
- ADS_STRUCT *ads;
- const char *auth_principal = opt_user_name;
- const char *auth_password = opt_password;
- char *realm = NULL;
- char *new_password = NULL;
- char *c, *prompt;
- const char *user;
- ADS_STATUS ret;
-
- if (opt_user_name == NULL || opt_password == NULL) {
- d_printf("You must supply an administrator username/password\n");
- return -1;
- }
+ ADS_STRUCT *ads;
+ const char *auth_principal = opt_user_name;
+ const char *auth_password = opt_password;
+ char *realm = NULL;
+ char *new_password = NULL;
+ char *c, *prompt;
+ const char *user;
+ ADS_STATUS ret;
+
+ if (opt_user_name == NULL || opt_password == NULL) {
+ d_printf("You must supply an administrator username/password\n");
+ return -1;
+ }
+ if (argc < 1) {
+ d_printf("ERROR: You must say which username to change password for\n");
+ return -1;
+ }
+
+ user = argv[0];
+ if (!strchr_m(user, '@')) {
+ asprintf(&c, "%s@%s", argv[0], lp_realm());
+ user = c;
+ }
+
+ use_in_memory_ccache();
+ c = strchr(auth_principal, '@');
+ if (c) {
+ realm = ++c;
+ } else {
+ realm = lp_realm();
+ }
+
+ /* use the realm so we can eventually change passwords for users
+ in realms other than default */
+ if (!(ads = ads_init(realm, NULL, NULL))) {
+ return -1;
+ }
+
+ /* we don't actually need a full connect, but it's the easy way to
+ fill in the KDC's addresss */
+ ads_connect(ads);
- if (argc < 1) {
- d_printf("ERROR: You must say which username to change password for\n");
- return -1;
- }
-
- user = argv[0];
- if (!strchr(user, '@')) {
- asprintf(&c, "%s@%s", argv[0], lp_realm());
- user = c;
- }
-
- use_in_memory_ccache();
- c = strchr(auth_principal, '@');
- if (c) {
- realm = ++c;
- } else {
- realm = lp_realm();
- }
-
- /* use the realm so we can eventually change passwords for users
- in realms other than default */
- if (!(ads = ads_init(realm, NULL, NULL))) return -1;
-
- /* we don't actually need a full connect, but it's the easy way to
- fill in the KDC's addresss */
- ads_connect(ads);
-
- if (!ads || !ads->config.realm) {
- d_printf("Didn't find the kerberos server!\n");
- return -1;
- }
-
- if (argv[1]) {
- new_password = (char *)argv[1];
- } else {
- asprintf(&prompt, "Enter new password for %s:", user);
- new_password = getpass(prompt);
- free(prompt);
- }
-
- ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
+ if (!ads || !ads->config.realm) {
+ d_printf("Didn't find the kerberos server!\n");
+ return -1;
+ }
+
+ if (argv[1]) {
+ new_password = (char *)argv[1];
+ } else {
+ asprintf(&prompt, "Enter new password for %s:", user);
+ new_password = getpass(prompt);
+ free(prompt);
+ }
+
+ ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
auth_password, user, new_password, ads->auth.time_offset);
- if (!ADS_ERR_OK(ret)) {
- d_printf("Password change failed :-( ...\n");
- ads_destroy(&ads);
- return -1;
- }
+ if (!ADS_ERR_OK(ret)) {
+ d_printf("Password change failed :-( ...\n");
+ ads_destroy(&ads);
+ return -1;
+ }
- d_printf("Password change for %s completed.\n", user);
- ads_destroy(&ads);
+ d_printf("Password change for %s completed.\n", user);
+ ads_destroy(&ads);
- return 0;
+ return 0;
}
-
int net_ads_changetrustpw(int argc, const char **argv)
{
- ADS_STRUCT *ads;
- char *host_principal;
- char *hostname;
- ADS_STATUS ret;
+ ADS_STRUCT *ads;
+ char *host_principal;
+ fstring my_fqdn;
+ ADS_STATUS ret;
+
+ if (!secrets_init()) {
+ DEBUG(1,("Failed to initialise secrets database\n"));
+ return -1;
+ }
+
+ net_use_machine_password();
- if (!secrets_init()) {
- DEBUG(1,("Failed to initialise secrets database\n"));
- return -1;
- }
+ use_in_memory_ccache();
- net_use_machine_password();
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
- use_in_memory_ccache();
+ name_to_fqdn(my_fqdn, global_myname());
+ strlower_m(my_fqdn);
+ asprintf(&host_principal, "%s@%s", my_fqdn, ads->config.realm);
+ d_printf("Changing password for principal: HOST/%s\n", host_principal);
- if (!(ads = ads_startup())) {
- return -1;
- }
+ ret = ads_change_trust_account_password(ads, host_principal);
- hostname = strdup(global_myname());
- strlower_m(hostname);
- asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);
- SAFE_FREE(hostname);
- d_printf("Changing password for principal: HOST/%s\n", host_principal);
+ if (!ADS_ERR_OK(ret)) {
+ d_printf("Password change failed :-( ...\n");
+ ads_destroy(&ads);
+ SAFE_FREE(host_principal);
+ return -1;
+ }
- ret = ads_change_trust_account_password(ads, host_principal);
+ d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
+
+ if (lp_use_kerberos_keytab()) {
+ d_printf("Attempting to update system keytab with new password.\n");
+ if (ads_keytab_create_default(ads)) {
+ d_printf("Failed to update system keytab.\n");
+ }
+ }
- if (!ADS_ERR_OK(ret)) {
- d_printf("Password change failed :-( ...\n");
ads_destroy(&ads);
SAFE_FREE(host_principal);
- return -1;
- }
-
- d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
- ads_destroy(&ads);
- SAFE_FREE(host_principal);
- return 0;
+ return 0;
}
/*
@@ -1157,6 +1252,7 @@ static int net_ads_search(int argc, const char **argv)
ldap_exp, attrs, &res);
if (!ADS_ERR_OK(rc)) {
d_printf("search failed: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
@@ -1216,6 +1312,7 @@ static int net_ads_dn(int argc, const char **argv)
"(objectclass=*)", attrs, &res);
if (!ADS_ERR_OK(rc)) {
d_printf("search failed: %s\n", ads_errstr(rc));
+ ads_destroy(&ads);
return -1;
}
@@ -1230,6 +1327,86 @@ static int net_ads_dn(int argc, const char **argv)
return 0;
}
+static int net_ads_keytab_usage(int argc, const char **argv)
+{
+ d_printf(
+ "net ads keytab <COMMAND>\n"\
+"<COMMAND> can be either:\n"\
+" CREATE Creates a fresh keytab\n"\
+" ADD Adds new service principal\n"\
+" FLUSH Flushes out all keytab entries\n"\
+" HELP Prints this help message\n"\
+"The ADD command will take arguments, the other commands\n"\
+"will not take any arguments. The arguments given to ADD\n"\
+"should be a list of principals to add. For example, \n"\
+" net ads keytab add srv1 srv2\n"\
+"will add principals for the services srv1 and srv2 to the\n"\
+"system's keytab.\n"\
+"\n"
+ );
+ return -1;
+}
+
+static int net_ads_keytab_flush(int argc, const char **argv)
+{
+ int ret;
+ ADS_STRUCT *ads;
+
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
+ ret = ads_keytab_flush(ads);
+ ads_destroy(&ads);
+ return ret;
+}
+
+static int net_ads_keytab_add(int argc, const char **argv)
+{
+ int i;
+ int ret = 0;
+ ADS_STRUCT *ads;
+
+ d_printf("Processing principals to add...\n");
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
+ for (i = 0; i < argc; i++) {
+ ret |= ads_keytab_add_entry(ads, argv[i]);
+ }
+ ads_destroy(&ads);
+ return ret;
+}
+
+static int net_ads_keytab_create(int argc, const char **argv)
+{
+ ADS_STRUCT *ads;
+ int ret;
+
+ if (!(ads = ads_startup())) {
+ return -1;
+ }
+ ret = ads_keytab_create_default(ads);
+ ads_destroy(&ads);
+ return ret;
+}
+
+int net_ads_keytab(int argc, const char **argv)
+{
+ struct functable func[] = {
+ {"CREATE", net_ads_keytab_create},
+ {"ADD", net_ads_keytab_add},
+ {"FLUSH", net_ads_keytab_flush},
+ {"HELP", net_ads_keytab_usage},
+ {NULL, NULL}
+ };
+
+ if (!lp_use_kerberos_keytab()) {
+ d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
+use keytab functions.\n");
+ }
+
+ return net_run_function(argc, argv, func, net_ads_keytab_usage);
+}
int net_ads_help(int argc, const char **argv)
{
@@ -1269,6 +1446,7 @@ int net_ads(int argc, const char **argv)
{"DN", net_ads_dn},
{"WORKGROUP", net_ads_workgroup},
{"LOOKUP", net_ads_lookup},
+ {"KEYTAB", net_ads_keytab},
{"HELP", net_ads_help},
{NULL, NULL}
};
@@ -1284,6 +1462,11 @@ static int net_ads_noads(void)
return -1;
}
+int net_ads_keytab(int argc, const char **argv)
+{
+ return net_ads_noads();
+}
+
int net_ads_usage(int argc, const char **argv)
{
return net_ads_noads();
diff --git a/source/utils/net_rpc.c b/source/utils/net_rpc.c
index 817ba912b05..e21f79df303 100644
--- a/source/utils/net_rpc.c
+++ b/source/utils/net_rpc.c
@@ -1867,8 +1867,14 @@ rpc_group_list_internals(const DOM_SID *domain_sid, const char *domain_name,
do {
if (!local) break;
+ /* The max_size field in cli_samr_enum_als_groups is more like
+ * an account_control field with indiviual bits what to
+ * retrieve. Set this to 0xffff as NT4 usrmgr.exe does to get
+ * everything. I'm too lazy (sorry) to get this through to
+ * rpc_parse/ etc. Volker */
+
result = cli_samr_enum_als_groups(cli, mem_ctx, &domain_pol,
- &start_idx, max_entries,
+ &start_idx, 0xffff,
&groups, &num_entries);
if (!NT_STATUS_IS_OK(result) &&
@@ -2203,6 +2209,83 @@ static int rpc_group_members(int argc, const char **argv)
argc, argv);
}
+static NTSTATUS
+rpc_group_rename_internals(const DOM_SID *domain_sid,
+ const char *domain_name,
+ struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+ NTSTATUS result;
+ POLICY_HND connect_pol, domain_pol, group_pol;
+ uint32 num_rids, *rids, *rid_types;
+ GROUP_INFO_CTR ctr;
+
+ if (argc != 2) {
+ d_printf("Usage: 'net rpc group rename group newname'\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Get sam policy handle */
+
+ result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
+ &connect_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ /* Get domain policy handle */
+
+ result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ domain_sid, &domain_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ result = cli_samr_lookup_names(cli, mem_ctx, &domain_pol, 1000,
+ 1, argv, &num_rids, &rids, &rid_types);
+
+ if (num_rids != 1) {
+ d_printf("Couldn't find group %s\n", argv[0]);
+ return result;
+ }
+
+ if (rid_types[0] != SID_NAME_DOM_GRP) {
+ d_printf("Can only rename domain groups\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ result = cli_samr_open_group(cli, mem_ctx, &domain_pol,
+ MAXIMUM_ALLOWED_ACCESS,
+ rids[0], &group_pol);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ ZERO_STRUCT(ctr);
+
+ ctr.switch_value1 = 2;
+ init_samr_group_info2(&ctr.group.info2, argv[1]);
+
+ result = cli_samr_set_groupinfo(cli, mem_ctx, &group_pol, &ctr);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ return NT_STATUS_NO_SUCH_GROUP;
+}
+
+static int rpc_group_rename(int argc, const char **argv)
+{
+ if (argc != 2) {
+ return rpc_group_usage(argc, argv);
+ }
+
+ return run_rpc_command(NULL, PI_SAMR, 0,
+ rpc_group_rename_internals,
+ argc, argv);
+}
+
/**
* 'net rpc group' entrypoint.
* @param argc Standard main() style argc
@@ -2219,6 +2302,7 @@ int net_rpc_group(int argc, const char **argv)
{"delmem", rpc_group_delmem},
{"list", rpc_group_list},
{"members", rpc_group_members},
+ {"rename", rpc_group_rename},
{NULL, NULL}
};
diff --git a/source/utils/ntlm_auth.c b/source/utils/ntlm_auth.c
index f2fb7dcaaf3..39dcd9993d0 100644
--- a/source/utils/ntlm_auth.c
+++ b/source/utils/ntlm_auth.c
@@ -369,6 +369,7 @@ NTSTATUS contact_winbind_auth_crap(const char *username,
nt_status = NT_STATUS_UNSUCCESSFUL;
if (error_string)
*error_string = smb_xstrdup("Reading winbind reply failed!");
+ free_response(&response);
return nt_status;
}
@@ -376,6 +377,7 @@ NTSTATUS contact_winbind_auth_crap(const char *username,
if (!NT_STATUS_IS_OK(nt_status)) {
if (error_string)
*error_string = smb_xstrdup(response.data.auth.error_string);
+ free_response(&response);
return nt_status;
}
@@ -390,10 +392,12 @@ NTSTATUS contact_winbind_auth_crap(const char *username,
if (flags & WBFLAG_PAM_UNIX_NAME) {
if (pull_utf8_allocate(unix_name, (char *)response.extra_data) == -1) {
+ free_response(&response);
return NT_STATUS_NO_MEMORY;
}
}
+ free_response(&response);
return nt_status;
}
@@ -810,32 +814,34 @@ static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
pstring reply_argument;
if (strlen(buf) < 2) {
+ DEBUG(1, ("SPENGO query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
- if (ntlmssp_state != NULL) {
- DEBUG(1, ("Request for initial SPNEGO request where "
- "we already have a state\n"));
- x_fprintf(x_stdout, "BH\n");
- return;
- }
-
- DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
+ if (strncmp(buf, "YR", 2) == 0) {
+ if (ntlmssp_state)
+ ntlmssp_end(&ntlmssp_state);
+ } else if (strncmp(buf, "KK", 2) == 0) {
+
+ } else {
+ DEBUG(1, ("SPENGO query [%s] invalid", buf));
x_fprintf(x_stdout, "BH\n");
return;
}
- if ( (strlen(buf) == 2) && (strcmp(buf, "YR") == 0) ) {
+ if ( (strlen(buf) == 2)) {
- /* Initial request, get the negTokenInit offering
+ /* no client data, get the negTokenInit offering
mechanisms */
offer_gss_spnego_mechs();
return;
}
- /* All subsequent requests are "KK" (Knock, Knock ;)) and have
- a blob. This might be negTokenInit or negTokenTarg */
+ /* All subsequent requests have a blob. This might be negTokenInit or negTokenTarg */
- if ( (strlen(buf) <= 3) || (strncmp(buf, "KK", 2) != 0) ) {
+ if (strlen(buf) <= 3) {
DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
x_fprintf(x_stdout, "BH\n");
return;
@@ -1147,7 +1153,7 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego)
{
char *principal;
DATA_BLOB tkt, to_server;
- DATA_BLOB session_key_krb5;
+ DATA_BLOB session_key_krb5 = data_blob(NULL, 0);
SPNEGO_DATA reply;
char *reply_base64;
int retval;
@@ -1192,14 +1198,14 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego)
if ((retval = kerberos_kinit_password(user, opt_password,
0, NULL))) {
DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
- x_fprintf(x_stdout, "NA\n");
- return True;
+ return False;
}
retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5);
if (retval) {
DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
+ return False;
}
}
@@ -1588,9 +1594,13 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helpe
/* this is not a typo - x_fgets doesn't work too well under squid */
if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
- DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", ferror(stdin),
- strerror(ferror(stdin))));
- exit(1); /* BIIG buffer */
+ if (ferror(stdin)) {
+ DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", ferror(stdin),
+ strerror(ferror(stdin))));
+
+ exit(1); /* BIIG buffer */
+ }
+ exit(0);
}
c=memchr(buf,'\n',sizeof(buf)-1);
diff --git a/source/utils/smbcacls.c b/source/utils/smbcacls.c
index 5a70d168842..cb82ad831eb 100644
--- a/source/utils/smbcacls.c
+++ b/source/utils/smbcacls.c
@@ -624,11 +624,6 @@ static int cacl_set(struct cli_state *cli, char *filename,
old->dacl->ace[k] = old->dacl->ace[k+1];
}
old->dacl->num_aces--;
- if (old->dacl->num_aces == 0) {
- SAFE_FREE(old->dacl->ace);
- SAFE_FREE(old->dacl);
- old->off_dacl = 0;
- }
found = True;
break;
}