[SCM] Samba Shared Repository - branch master updated

Volker Lendecke vlendec at samba.org
Thu Jun 15 15:33:02 UTC 2017


The branch, master has been updated
       via  a4d9438 libcli:smb2: Gracefully handle not supported for FSCTL_VALIDATE_NEGOTIATE_INFO
       via  b9f32b2 g_lock: open with LOCK_ORDER_3
       via  2693227 smbd: Claim version in g_lock
       via  2c200dd torture3: Test heuristic cleanup
       via  d19e770 g_lock: Heuristically check for server existence
       via  27eb93c torture3: Test lock conflict and cleanup
       via  2a29c54 torture3: Test lock upgrade/downgrade
       via  4b282664 g_lock: Allow lock upgrade/downgrade
       via  8f1cf7b torture3: Test g_lock_write_data
       via  90d7784 g_lock: Make g_lock_dump return a complete list of locks
       via  4478cd5 g_lock: Add g_lock_write_data
       via  c400e2b g_lock: Make g_lock_record_store also store userdata
       via  4d404f2 g_lock: Reformat to allow userdata
       via  4422124 g_lock: Move parsing routines together
       via  636137a g_lock: unparse->put
       via  fadc877 g_lock: parse->get
       via  4d1f9ff g_lock: Remove a pointless "else"
       via  6358901 g_lock: Remove unused g_lock_get
       via  49a80e5 g_lock: Make it endian-neutral
       via  9677101 g_lock: More correct error msg
       via  c2cdf57 torture3: Initial test g_lock
       via  90e2bf5 g_lock: Fix two typos
      from  52bd61d s4:ldap_server: implement async BindSASL

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit a4d9438ecf92614a0915b9cf61f905ea8170043a
Author: Andreas Schneider <asn at samba.org>
Date:   Tue May 30 16:30:33 2017 +0200

    libcli:smb2: Gracefully handle not supported for FSCTL_VALIDATE_NEGOTIATE_INFO
    
    If FSCTL_VALIDATE_NEGOTIATE_INFO is not implemented, e.g. in a SMB2 only
    server then gracefully handle NT_STATUS_NOT_SUPPORTED too.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12808
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Guenther Deschner <gd at samba.org>
    Pair-Programmed-With: Guenther Deschner <gd at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Volker Lendecke <vl at samba.org>
    Autobuild-Date(master): Thu Jun 15 17:32:45 CEST 2017 on sn-devel-144

commit b9f32b2ea623a6ce976eb571232cdabeff160447
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Jun 14 13:57:56 2017 +0200

    g_lock: open with LOCK_ORDER_3
    
    xattr_tdb needs g_lock in a clustered environment. Nobody else
    uses LOCK_ORDER_3 at this moment, so this looks safe.
    
    The last one to use this was dbwrap_watch.tdb, and that's gone. The only
    other one was notify_index.tdb, and that's gone too.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 26932271a85a08a755c81df0138d770b6a3bc3a3
Author: Volker Lendecke <vl at samba.org>
Date:   Mon May 22 16:00:08 2017 +0200

    smbd: Claim version in g_lock
    
    Protect smbd against version incompatibilities in a cluster.
    
    At first startup smbd locks "samba_version_string" and writes its version
    string. It then downgrades the lock to a read lock. Subsequent smbds check
    against the version string and also keep the read lock around. If the version
    does not match, we try to write our own version. But as there's a read lock,
    the lock upgrade to write lock will fail due the read lock being around. So as
    long as there's one smbd with this read lock, no other version of smbd will be
    able to start.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 2c200dd00d8a3969e5dbbdb0598b5073fd3cf65e
Author: Volker Lendecke <vl at samba.org>
Date:   Thu May 25 10:48:15 2017 +0200

    torture3: Test heuristic cleanup
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit d19e7709d9b6666f53ccfec47a86f0f0cab70925
Author: Volker Lendecke <vl at samba.org>
Date:   Mon May 22 17:05:57 2017 +0200

    g_lock: Heuristically check for server existence
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 27eb93c04e03f9a7afb75f88c199889b3001a061
Author: Volker Lendecke <vl at samba.org>
Date:   Sun May 21 08:56:01 2017 +0200

    torture3: Test lock conflict and cleanup
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 2a29c5442d1e62ccd7a05474a3f061c2d10f3c74
Author: Volker Lendecke <vl at samba.org>
Date:   Fri May 19 17:02:08 2017 +0200

    torture3: Test lock upgrade/downgrade
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 4b2826646bbcd9f84fe6e29417bd403f9e856ffc
Author: Volker Lendecke <vl at samba.org>
Date:   Fri May 19 16:57:00 2017 +0200

    g_lock: Allow lock upgrade/downgrade
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 8f1cf7b4309cddc55feaceaff76db15305265567
Author: Volker Lendecke <vl at samba.org>
Date:   Fri May 19 16:59:06 2017 +0200

    torture3: Test g_lock_write_data
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 90d7784d45d2a43f5e8a68596c793e7ba8a5b350
Author: Volker Lendecke <vl at samba.org>
Date:   Thu May 18 15:27:46 2017 +0200

    g_lock: Make g_lock_dump return a complete list of locks
    
    To be honest, it did not really make sense to just pass in
    lock holders individually. You could argue that it made sense
    with in reality only G_LOCK_WRITE around, but soon we will have
    G_LOCK_READ and thus multiple lock holders on a single lock.
    
    Now that we also have userdata, change the g_lock_dump API
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 4478cd59ad1689f8719c031766b981ae37c24212
Author: Volker Lendecke <vl at samba.org>
Date:   Tue May 23 12:32:24 2017 +0200

    g_lock: Add g_lock_write_data
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit c400e2b54ed763d7d294368320aa339530da5852
Author: Volker Lendecke <vl at samba.org>
Date:   Thu May 18 16:22:15 2017 +0200

    g_lock: Make g_lock_record_store also store userdata
    
    Sequel to the previous commit changing the get/put routines for
    the on-disk format
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 4d404f23c9dff8bafd408b2d9566e179afef74bc
Author: Volker Lendecke <vl at samba.org>
Date:   Thu May 18 13:59:20 2017 +0200

    g_lock: Reformat to allow userdata
    
    The next patches will make g_locks carry data. This
    prepares the on-disk format.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 4422124e096a80da3d585d831fee136149c36b0d
Author: Volker Lendecke <vl at samba.org>
Date:   Thu May 18 10:37:30 2017 +0200

    g_lock: Move parsing routines together
    
    No code change, just shuffling around:
    
    Before this patchset, g_lock_parse was somewhere in the middle. This carries no
    real logic, put it on top.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 636137a30a9fdcb5ff61830f1f8324b97b5cb6c9
Author: Volker Lendecke <vl at samba.org>
Date:   Wed May 17 16:53:14 2017 +0200

    g_lock: unparse->put
    
    Make it more in line with server_id_get/put
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit fadc877c597538ddc9dd7cc9426fc15030e02509
Author: Volker Lendecke <vl at samba.org>
Date:   Wed May 17 16:53:14 2017 +0200

    g_lock: parse->get
    
    Make it more in line with server_id_get/put
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 4d1f9ff1b8e0e9af99c5a7f5c4f34fecef1001c0
Author: Volker Lendecke <vl at samba.org>
Date:   Wed May 17 16:43:01 2017 +0200

    g_lock: Remove a pointless "else"
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 6358901f152e72cad5e7718e01e79551fa6195a6
Author: Volker Lendecke <vl at samba.org>
Date:   Wed May 17 16:40:45 2017 +0200

    g_lock: Remove unused g_lock_get
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 49a80e5a0c1b6ec4ff5529587e068121e045dbc7
Author: Volker Lendecke <vl at samba.org>
Date:   Wed May 17 05:52:56 2017 +0200

    g_lock: Make it endian-neutral
    
    Add explicit parsing
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 96771018509a9f61467e64a920b00775e31177c4
Author: Volker Lendecke <vl at samba.org>
Date:   Wed May 17 05:54:36 2017 +0200

    g_lock: More correct error msg
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit c2cdf579fc0ee98c3414d1a5920b7c72017f6deb
Author: Volker Lendecke <vl at samba.org>
Date:   Tue May 16 15:05:49 2017 +0200

    torture3: Initial test g_lock
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 90e2bf50c7eea7f6df52646f613197d397c9bc01
Author: Volker Lendecke <vl at samba.org>
Date:   Wed May 24 13:27:18 2017 +0200

    g_lock: Fix two typos
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 .../smbdotconf/misc/allowunsafeclusterupgrade.xml  |  16 +
 libcli/smb/smbXcli_base.c                          |  15 +
 source3/include/g_lock.h                           |  18 +-
 source3/lib/g_lock.c                               | 393 +++++++++----
 source3/selftest/tests.py                          |   5 +
 source3/smbd/server.c                              | 114 ++++
 source3/torture/proto.h                            |   5 +
 source3/torture/test_g_lock.c                      | 644 +++++++++++++++++++++
 source3/torture/torture.c                          |   5 +
 source3/utils/net_g_lock.c                         |  19 +-
 source3/wscript_build                              |   1 +
 11 files changed, 1120 insertions(+), 115 deletions(-)
 create mode 100644 docs-xml/smbdotconf/misc/allowunsafeclusterupgrade.xml
 create mode 100644 source3/torture/test_g_lock.c


Changeset truncated at 500 lines:

diff --git a/docs-xml/smbdotconf/misc/allowunsafeclusterupgrade.xml b/docs-xml/smbdotconf/misc/allowunsafeclusterupgrade.xml
new file mode 100644
index 0000000..02398ff
--- /dev/null
+++ b/docs-xml/smbdotconf/misc/allowunsafeclusterupgrade.xml
@@ -0,0 +1,16 @@
+<samba:parameter name="allow unsafe cluster upgrade"
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+	<para>If set to no (the default), smbd checks at startup if
+	other smbd versions are running in the cluster and refuses to
+	start if so. This is done to protect data corruption in
+	internal data structures due to incompatible Samba versions
+	running concurrently in the same cluster. Setting this
+	parameter to <value type="example">yes</value> disables this
+	safety check.
+	</para>
+</description>
+<value type="default">no</value>
+</samba:parameter>
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index 1ec11a9..74a602d 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -5317,6 +5317,21 @@ static void smb2cli_validate_negotiate_info_done(struct tevent_req *subreq)
 		tevent_req_done(req);
 		return;
 	}
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+		/*
+		 * The response was signed, but not supported
+		 *
+		 * This might be returned by older Windows versions or by
+		 * NetApp SMB server implementations.
+		 *
+		 * See
+		 *
+		 * https://blogs.msdn.microsoft.com/openspecification/2012/06/28/smb3-secure-dialect-negotiation/
+		 *
+		 */
+		tevent_req_done(req);
+		return;
+	}
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
diff --git a/source3/include/g_lock.h b/source3/include/g_lock.h
index f513349..e6d4de1 100644
--- a/source3/include/g_lock.h
+++ b/source3/include/g_lock.h
@@ -30,6 +30,11 @@ enum g_lock_type {
 	G_LOCK_WRITE = 1,
 };
 
+struct g_lock_rec {
+	enum g_lock_type lock_type;
+	struct server_id pid;
+};
+
 struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
 				   struct messaging_context *msg);
 
@@ -42,8 +47,9 @@ NTSTATUS g_lock_lock_recv(struct tevent_req *req);
 NTSTATUS g_lock_lock(struct g_lock_ctx *ctx, const char *name,
 		     enum g_lock_type lock_type, struct timeval timeout);
 NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name);
-NTSTATUS g_lock_get(struct g_lock_ctx *ctx, const char *name,
-		struct server_id *pid);
+
+NTSTATUS g_lock_write_data(struct g_lock_ctx *ctx, const char *name,
+			   const uint8_t *buf, size_t buflen);
 
 NTSTATUS g_lock_do(const char *name, enum g_lock_type lock_type,
 		   struct timeval timeout,
@@ -53,9 +59,11 @@ int g_lock_locks(struct g_lock_ctx *ctx,
 		 int (*fn)(const char *name, void *private_data),
 		 void *private_data);
 NTSTATUS g_lock_dump(struct g_lock_ctx *ctx, const char *name,
-		     int (*fn)(struct server_id pid,
-			       enum g_lock_type lock_type,
-			       void *private_data),
+		     void (*fn)(const struct g_lock_rec *locks,
+				size_t num_locks,
+				const uint8_t *data,
+				size_t datalen,
+				void *private_data),
 		     void *private_data);
 
 #endif
diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index 1815796..198fe56 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -40,10 +40,136 @@ struct g_lock_ctx {
  * structures.
  */
 
-struct g_lock_rec {
-	enum g_lock_type lock_type;
-	struct server_id pid;
-};
+#define G_LOCK_REC_LENGTH (SERVER_ID_BUF_LENGTH+1)
+
+static void g_lock_rec_put(uint8_t buf[G_LOCK_REC_LENGTH],
+			   const struct g_lock_rec rec)
+{
+	SCVAL(buf, 0, rec.lock_type);
+	server_id_put(buf+1, rec.pid);
+}
+
+static void g_lock_rec_get(struct g_lock_rec *rec,
+			   const uint8_t buf[G_LOCK_REC_LENGTH])
+{
+	rec->lock_type = CVAL(buf, 0);
+	server_id_get(&rec->pid, buf+1);
+}
+
+static ssize_t g_lock_put(uint8_t *buf, size_t buflen,
+			  const struct g_lock_rec *locks,
+			  size_t num_locks,
+			  const uint8_t *data, size_t datalen)
+{
+	size_t i, len, ofs;
+
+	if (num_locks > UINT32_MAX/G_LOCK_REC_LENGTH) {
+		return -1;
+	}
+
+	len = num_locks * G_LOCK_REC_LENGTH;
+
+	len += sizeof(uint32_t);
+	if (len < sizeof(uint32_t)) {
+		return -1;
+	}
+
+	len += datalen;
+	if (len < datalen) {
+		return -1;
+	}
+
+	if (len > buflen) {
+		return len;
+	}
+
+	ofs = 0;
+	SIVAL(buf, ofs, num_locks);
+	ofs += sizeof(uint32_t);
+
+	for (i=0; i<num_locks; i++) {
+		g_lock_rec_put(buf+ofs, locks[i]);
+		ofs += G_LOCK_REC_LENGTH;
+	}
+
+	if ((data != NULL) && (datalen != 0)) {
+		memcpy(buf+ofs, data, datalen);
+	}
+
+	return len;
+}
+
+static ssize_t g_lock_get(TDB_DATA recval,
+			  struct g_lock_rec *locks, size_t num_locks,
+			  uint8_t **data, size_t *datalen)
+{
+	size_t found_locks;
+
+	if (recval.dsize < sizeof(uint32_t)) {
+		/* Fresh or invalid record */
+		found_locks = 0;
+		goto done;
+	}
+
+	found_locks = IVAL(recval.dptr, 0);
+	recval.dptr += sizeof(uint32_t);
+	recval.dsize -= sizeof(uint32_t);
+
+	if (found_locks > recval.dsize/G_LOCK_REC_LENGTH) {
+		/* Invalid record */
+		return 0;
+	}
+
+	if (found_locks <= num_locks) {
+		size_t i;
+
+		for (i=0; i<found_locks; i++) {
+			g_lock_rec_get(&locks[i], recval.dptr);
+			recval.dptr += G_LOCK_REC_LENGTH;
+			recval.dsize -= G_LOCK_REC_LENGTH;
+		}
+	} else {
+		/*
+		 * Not enough space passed in by the caller, don't
+		 * parse the locks.
+		 */
+		recval.dptr += found_locks * G_LOCK_REC_LENGTH;
+		recval.dsize -= found_locks * G_LOCK_REC_LENGTH;
+	}
+
+done:
+	if (data != NULL) {
+		*data = recval.dptr;
+	}
+	if (datalen != NULL) {
+		*datalen = recval.dsize;
+	}
+	return found_locks;
+}
+
+static NTSTATUS g_lock_get_talloc(TALLOC_CTX *mem_ctx, TDB_DATA recval,
+				  struct g_lock_rec **plocks,
+				  size_t *pnum_locks,
+				  uint8_t **data, size_t *datalen)
+{
+	struct g_lock_rec *locks;
+	ssize_t num_locks;
+
+	num_locks = g_lock_get(recval, NULL, 0, NULL, NULL);
+	if (num_locks == -1) {
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+	locks = talloc_array(mem_ctx, struct g_lock_rec, num_locks);
+	if (locks == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	g_lock_get(recval, locks, num_locks, data, datalen);
+
+	*plocks = locks;
+	*pnum_locks = num_locks;
+
+	return NT_STATUS_OK;
+}
 
 struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
 				   struct messaging_context *msg)
@@ -67,7 +193,7 @@ struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
 	backend = db_open(result, db_path, 0,
 			  TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
 			  O_RDWR|O_CREAT, 0600,
-			  DBWRAP_LOCK_ORDER_2,
+			  DBWRAP_LOCK_ORDER_3,
 			  DBWRAP_FLAG_NONE);
 	TALLOC_FREE(db_path);
 	if (backend == NULL) {
@@ -97,48 +223,90 @@ static bool g_lock_conflicts(enum g_lock_type l1, enum g_lock_type l2)
 	return true;
 }
 
-static bool g_lock_parse(TALLOC_CTX *mem_ctx, TDB_DATA data,
-			 unsigned *pnum_locks, struct g_lock_rec **plocks)
+static NTSTATUS g_lock_record_store(struct db_record *rec,
+				    const struct g_lock_rec *locks,
+				    size_t num_locks,
+				    const uint8_t *data, size_t datalen)
 {
-	unsigned num_locks;
-	struct g_lock_rec *locks;
+	ssize_t len;
+	uint8_t *buf;
+	NTSTATUS status;
 
-	if ((data.dsize % sizeof(struct g_lock_rec)) != 0) {
-		DEBUG(1, ("invalid lock record length %zu\n", data.dsize));
-		return false;
+	len = g_lock_put(NULL, 0, locks, num_locks, data, datalen);
+	if (len == -1) {
+		return NT_STATUS_BUFFER_TOO_SMALL;
 	}
-	num_locks = data.dsize / sizeof(struct g_lock_rec);
-	locks = talloc_memdup(mem_ctx, data.dptr, data.dsize);
-	if (locks == NULL) {
-		DEBUG(1, ("talloc_memdup failed\n"));
-		return false;
+
+	buf = talloc_array(rec, uint8_t, len);
+	if (buf == NULL) {
+		return NT_STATUS_NO_MEMORY;
 	}
-	*plocks = locks;
-	*pnum_locks = num_locks;
-	return true;
+
+	g_lock_put(buf, len, locks, num_locks, data, datalen);
+
+	status = dbwrap_record_store(
+		rec, (TDB_DATA) { .dptr = buf, .dsize = len }, 0);
+
+	TALLOC_FREE(buf);
+
+	return status;
 }
 
 static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 			       enum g_lock_type type,
 			       struct server_id *blocker)
 {
-	TDB_DATA data;
-	unsigned i, num_locks;
+	TDB_DATA data, userdata;
+	size_t i, num_locks, my_lock;
 	struct g_lock_rec *locks, *tmp;
 	NTSTATUS status;
 	bool modified = false;
 
 	data = dbwrap_record_get_value(rec);
 
-	if (!g_lock_parse(talloc_tos(), data, &num_locks, &locks)) {
-		return NT_STATUS_INTERNAL_ERROR;
+	status = g_lock_get_talloc(talloc_tos(), data, &locks, &num_locks,
+				   &userdata.dptr, &userdata.dsize);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	my_lock = num_locks;	/* doesn't exist yet */
+
+	if ((type == G_LOCK_READ) && (num_locks > 0)) {
+		/*
+		 * Read locks can stay around forever if the process
+		 * dies. Do a heuristic check for process existence:
+		 * Check one random process for existence. Hopefully
+		 * this will keep runaway read locks under control.
+		 */
+		i = generate_random() % num_locks;
+
+		if (!serverid_exists(&locks[i].pid)) {
+			locks[i] = locks[num_locks-1];
+			num_locks -=1;
+			modified = true;
+		}
 	}
 
 	for (i=0; i<num_locks; i++) {
-		if (serverid_equal(&self, &locks[i].pid)) {
-			status = NT_STATUS_INTERNAL_ERROR;
-			goto done;
+		struct g_lock_rec *lock = &locks[i];
+
+		if (serverid_equal(&self, &lock->pid)) {
+			if (lock->lock_type == type) {
+				status = NT_STATUS_WAS_LOCKED;
+				goto done;
+			}
+			my_lock = i;
+			break;
 		}
+	}
+
+	for (i=0; i<num_locks; i++) {
+
+		if (i == my_lock) {
+			continue;
+		}
+
 		if (g_lock_conflicts(type, locks[i].lock_type)) {
 			struct server_id pid = locks[i].pid;
 
@@ -164,30 +332,30 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 		}
 	}
 
-	tmp = talloc_realloc(talloc_tos(), locks, struct g_lock_rec,
-			     num_locks+1);
-	if (tmp == NULL) {
-		status = NT_STATUS_NO_MEMORY;
-		goto done;
+	if (my_lock >= num_locks) {
+		tmp = talloc_realloc(talloc_tos(), locks, struct g_lock_rec,
+				     num_locks+1);
+		if (tmp == NULL) {
+			status = NT_STATUS_NO_MEMORY;
+			goto done;
+		}
+		locks = tmp;
+		my_lock = num_locks;
+		num_locks += 1;
 	}
-	locks = tmp;
 
-	ZERO_STRUCT(locks[num_locks]);
-	locks[num_locks].pid = self;
-	locks[num_locks].lock_type = type;
-	num_locks += 1;
+	locks[my_lock] = (struct g_lock_rec){ .pid = self, .lock_type = type };
 	modified = true;
 
 	status = NT_STATUS_OK;
 done:
 	if (modified) {
 		NTSTATUS store_status;
-
-		data = make_tdb_data((uint8_t *)locks, num_locks * sizeof(*locks));
-		store_status = dbwrap_record_store(rec, data, 0);
+		store_status = g_lock_record_store(
+			rec, locks, num_locks, userdata.dptr, userdata.dsize);
 		if (!NT_STATUS_IS_OK(store_status)) {
-			DEBUG(1, ("rec->store failed: %s\n",
-				  nt_errstr(store_status)));
+			DBG_WARNING("g_lock_record_store failed: %s\n",
+				    nt_errstr(store_status));
 			status = store_status;
 		}
 	}
@@ -357,9 +525,9 @@ NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
 	struct server_id self = messaging_server_id(ctx->msg);
 	struct db_record *rec = NULL;
 	struct g_lock_rec *locks = NULL;
-	unsigned i, num_locks;
+	size_t i, num_locks;
 	NTSTATUS status;
-	TDB_DATA value;
+	TDB_DATA value, userdata;
 
 	rec = dbwrap_fetch_locked(ctx->db, talloc_tos(),
 				  string_term_tdb_data(name));
@@ -371,8 +539,11 @@ NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
 
 	value = dbwrap_record_get_value(rec);
 
-	if (!g_lock_parse(talloc_tos(), value, &num_locks, &locks)) {
-		DEBUG(10, ("g_lock_parse for %s failed\n", name));
+	status = g_lock_get_talloc(talloc_tos(), value, &locks, &num_locks,
+				   &userdata.dptr, &userdata.dsize);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("g_lock_get for %s failed: %s\n", name,
+			  nt_errstr(status));
 		status = NT_STATUS_FILE_INVALID;
 		goto done;
 	}
@@ -382,7 +553,7 @@ NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
 		}
 	}
 	if (i == num_locks) {
-		DEBUG(10, ("g_lock_force_unlock: Lock not found\n"));
+		DBG_DEBUG("Lock not found, num_locks=%zu\n", num_locks);
 		status = NT_STATUS_NOT_FOUND;
 		goto done;
 	}
@@ -390,17 +561,14 @@ NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
 	locks[i] = locks[num_locks-1];
 	num_locks -= 1;
 
-	if (num_locks == 0) {
+	if ((num_locks == 0) && (userdata.dsize == 0)) {
 		status = dbwrap_record_delete(rec);
 	} else {
-		TDB_DATA data;
-		data = make_tdb_data((uint8_t *)locks,
-				     sizeof(struct g_lock_rec) * num_locks);
-		status = dbwrap_record_store(rec, data, 0);
+		status = g_lock_record_store(
+			rec, locks, num_locks, userdata.dptr, userdata.dsize);
 	}
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(1, ("g_lock_force_unlock: Could not store record: %s\n",
-			  nt_errstr(status)));
+		DBG_WARNING("Could not store record: %s\n", nt_errstr(status));
 		goto done;
 	}
 
@@ -411,6 +579,55 @@ done:
 	return status;
 }
 
+NTSTATUS g_lock_write_data(struct g_lock_ctx *ctx, const char *name,
+			   const uint8_t *buf, size_t buflen)
+{
+	struct server_id self = messaging_server_id(ctx->msg);
+	struct db_record *rec = NULL;
+	struct g_lock_rec *locks = NULL;
+	size_t i, num_locks;
+	NTSTATUS status;
+	TDB_DATA value;
+
+	rec = dbwrap_fetch_locked(ctx->db, talloc_tos(),
+				  string_term_tdb_data(name));
+	if (rec == NULL) {
+		DEBUG(10, ("fetch_locked(\"%s\") failed\n", name));
+		status = NT_STATUS_INTERNAL_ERROR;
+		goto done;
+	}
+
+	value = dbwrap_record_get_value(rec);
+
+	status = g_lock_get_talloc(talloc_tos(), value, &locks, &num_locks,
+				   NULL, NULL);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("g_lock_get for %s failed: %s\n", name,
+			  nt_errstr(status));
+		status = NT_STATUS_FILE_INVALID;
+		goto done;
+	}
+
+	for (i=0; i<num_locks; i++) {
+		if (server_id_equal(&self, &locks[i].pid) &&
+		    (locks[i].lock_type == G_LOCK_WRITE)) {
+			break;
+		}
+	}


-- 
Samba Shared Repository



More information about the samba-cvs mailing list