[PATCH] Cleanups and parallel idmap_script

Volker Lendecke Volker.Lendecke at SerNet.DE
Tue Feb 23 14:14:34 UTC 2016


Hi!

Attached find a patchset that holds a few cleanups plus idmap_script
parallelized. Greatly boosts performance for many groups at login
time.

Review appreciated!

Thanks, Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From 9b261b14760addb930c09dbe146d3590f7a7da7d Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 13 Jan 2016 11:15:36 +0100
Subject: [PATCH 01/12] py_xattr: Fix a "ignoring return value" warning

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/librpc/ndr/py_xattr.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/source4/librpc/ndr/py_xattr.c b/source4/librpc/ndr/py_xattr.c
index fcf2e66..4ebf135 100644
--- a/source4/librpc/ndr/py_xattr.c
+++ b/source4/librpc/ndr/py_xattr.c
@@ -43,12 +43,16 @@ static void ntacl_print_debug_helper(struct ndr_print *ndr, const char *format,
 {
         va_list ap;
         char *s = NULL;
-        int i;
+        int i, ret;
 
         va_start(ap, format);
-        vasprintf(&s, format, ap);
+        ret = vasprintf(&s, format, ap);
         va_end(ap);
 
+	if (ret == -1) {
+		return;
+	}
+
         for (i=0;i<ndr->depth;i++) {
                 printf("    ");
         }
-- 
2.1.4


From 860a04fcc683fed0ebe3d73598cb36207eb3ec10 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 14 Jan 2016 11:51:39 +0100
Subject: [PATCH 02/12] smbd: Fix line length & whitespace in write_file

No code change intended. This file just looked to hard to read.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/fileio.c | 117 ++++++++++++++++++++++++++++++--------------------
 1 file changed, 71 insertions(+), 46 deletions(-)

diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
index 156c139..ec6333e 100644
--- a/source3/smbd/fileio.c
+++ b/source3/smbd/fileio.c
@@ -1,20 +1,20 @@
-/* 
+/*
    Unix SMB/Netbios implementation.
    Version 1.9.
    read/write to a files_struct
    Copyright (C) Andrew Tridgell 1992-1998
    Copyright (C) Jeremy Allison 2000-2002. - write cache.
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
 */
@@ -411,9 +411,9 @@ ssize_t write_file(struct smb_request *req,
 		wcp->file_size = pos + 1;
 		ret = SMB_VFS_FTRUNCATE(fsp, wcp->file_size);
 		if (ret == -1) {
-			DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f"
-				 "error %s\n", fsp_str_dbg(fsp),
-				 (double)wcp->file_size, strerror(errno)));
+			DEBUG(0, ("wcp_file_size_change (%s): ftruncate of "
+				  "size %.0f error %s\n", fsp_str_dbg(fsp),
+				  (double)wcp->file_size, strerror(errno)));
 			return -1;
 		}
 		return 1;
@@ -428,8 +428,9 @@ ssize_t write_file(struct smb_request *req,
 	if (wcp->data_size) {
 		bool cache_flush_needed = False;
 
-		if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) {
-      
+		if ((pos >= wcp->offset) &&
+		    (pos <= wcp->offset + wcp->data_size)) {
+
 			/* ASCII art.... JRA.
 
       +--------------+-----
@@ -446,9 +447,13 @@ ssize_t write_file(struct smb_request *req,
 			 * Start of write overlaps or abutts the existing data.
 			 */
 
-			size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n);
+			size_t data_used;
+
+			data_used = MIN((wcp->alloc_size - (pos - wcp->offset)),
+					n);
 
-			memcpy(wcp->data + (pos - wcp->offset), data, data_used);
+			memcpy(wcp->data + (pos - wcp->offset), data,
+			       data_used);
 
 			/*
 			 * Update the current buffer size with the new data.
@@ -492,8 +497,9 @@ ssize_t write_file(struct smb_request *req,
 
 			write_path = 1;
 
-		} else if ((pos < wcp->offset) && (pos + n > wcp->offset) && 
-					(pos + n <= wcp->offset + wcp->alloc_size)) {
+		} else if ((pos < wcp->offset) &&
+			   (pos + n > wcp->offset) &&
+			   (pos + n <= wcp->offset + wcp->alloc_size)) {
 
 			/* ASCII art.... JRA.
 
@@ -551,10 +557,10 @@ ssize_t write_file(struct smb_request *req,
 
 			write_path = 2;
 
-		} else if ( (pos >= wcp->file_size) && 
-					(wcp->offset + wcp->data_size == wcp->file_size) &&
-					(pos > wcp->offset + wcp->data_size) && 
-					(pos < wcp->offset + wcp->alloc_size) ) {
+		} else if ((pos >= wcp->file_size) &&
+			   (wcp->offset + wcp->data_size == wcp->file_size) &&
+			   (pos > wcp->offset + wcp->data_size) &&
+			   (pos < wcp->offset + wcp->alloc_size) ) {
 
 			/* ASCII art.... JRA.
 
@@ -582,7 +588,7 @@ ssize_t write_file(struct smb_request *req,
 			if(pos + n <= wcp->offset + wcp->alloc_size) {
 				data_used = n;
 			} else {
-				data_used = wcp->offset + wcp->alloc_size - pos;
+				data_used = wcp->offset+wcp->alloc_size-pos;
 			}
 
 			/*
@@ -592,7 +598,8 @@ ssize_t write_file(struct smb_request *req,
 			memset(wcp->data + wcp->data_size, '\0',
 				pos - (wcp->offset + wcp->data_size) );
 
-			memcpy(wcp->data + (pos - wcp->offset), data, data_used);
+			memcpy(wcp->data + (pos - wcp->offset), data,
+			       data_used);
 
 			/*
 			 * Update the current buffer size with the new data.
@@ -656,8 +663,9 @@ ssize_t write_file(struct smb_request *req,
                                                          | 1 Byte |
                                                          +--------+
 
-			MS-Office seems to do this a lot to determine if there's enough
-			space on the filesystem to write a new file.
+			MS-Office seems to do this a lot to determine if
+			there's enough space on the filesystem to write a new
+			file.
 
 			Change to :
 
@@ -695,9 +703,9 @@ ssize_t write_file(struct smb_request *req,
                         | Cached data   | Cache buffer  |
                         +---------------+---------------+
 
-                                                              +-------------------+
-                                                              | Data to write     |
-                                                              +-------------------+
+                                                              +---------------+
+                                                              | Data to write |
+                                                              +---------------+
 
    Case 2).
 
@@ -722,35 +730,46 @@ ssize_t write_file(struct smb_request *req,
 		  */
 
  			/*
-			 * Write is bigger than buffer, or there is no overlap on the
-			 * low or high ends.
+			 * Write is bigger than buffer, or there is no
+			 * overlap on the low or high ends.
 			 */
 
-			DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \
-len = %u\n",fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
+			DEBUG(9,("write_file: non cacheable write : fd = %d, "
+				 "pos = %.0f, len = %u, "
+				 "current cache pos = %.0f len = %u\n",
+				 fsp->fh->fd, (double)pos, (unsigned int)n,
+				 (double)wcp->offset,
+				 (unsigned int)wcp->data_size ));
 
 			/*
-			 * If write would fit in the cache, and is larger than
-			 * the data already in the cache, flush the cache and
-			 * preferentially copy the data new data into it. Otherwise
-			 * just write the data directly.
+			 * If write would fit in the cache, and is
+			 * larger than the data already in the cache,
+			 * flush the cache and preferentially copy the
+			 * data new data into it. Otherwise just write
+			 * the data directly.
 			 */
 
 			if ( n <= wcp->alloc_size && n > wcp->data_size) {
 				cache_flush_needed = True;
 			} else {
-				ssize_t ret = real_write_file(NULL,fsp, data, pos, n);
+				ssize_t ret = real_write_file(NULL, fsp, data,
+							      pos, n);
 
 				/*
-				 * If the write overlaps the entire cache, then
-				 * discard the current contents of the cache.
-				 * Fix from Rasmus Borup Hansen rbh at math.ku.dk.
+				 * If the write overlaps the entire
+				 * cache, then discard the current
+				 * contents of the cache.  Fix from
+				 * Rasmus Borup Hansen rbh at math.ku.dk.
 				 */
 
 				if ((pos <= wcp->offset) &&
-						(pos + n >= wcp->offset + wcp->data_size) ) {
-					DEBUG(9,("write_file: discarding overwritten write \
-cache: fd = %d, off=%.0f, size=%u\n", fsp->fh->fd, (double)wcp->offset, (unsigned int)wcp->data_size ));
+				    (pos + n >= wcp->offset+wcp->data_size)) {
+					DEBUG(9,("write_file: discarding "
+						 "overwritten write cache: "
+						 "fd = %d, off=%.0f, "
+						 "size=%u\n", fsp->fh->fd,
+						 (double)wcp->offset,
+						 (unsigned)wcp->data_size));
 					wcp->data_size = 0;
 				}
 
@@ -771,10 +790,14 @@ cache: fd = %d, off=%.0f, size=%u\n", fsp->fh->fd, (double)wcp->offset, (unsigne
 		}
 
 		if (cache_flush_needed) {
-			DEBUG(3,("SAMBA_WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
-n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
-				write_path, fsp->fh->fd, (double)wcp->file_size, (double)pos, (unsigned int)n,
-				(double)wcp->offset, (unsigned int)wcp->data_size ));
+			DEBUG(3, ("SAMBA_WRITE_FLUSH:%d: due to noncontinuous "
+				  "write: fd = %d, size = %.0f, pos = %.0f, "
+				  "n = %u, wcp->offset=%.0f, "
+				  "wcp->data_size=%u\n",
+				  write_path, fsp->fh->fd,
+				  (double)wcp->file_size, (double)pos,
+				  (unsigned int)n, (double)wcp->offset,
+				  (unsigned int)wcp->data_size ));
 
 			flush_write_cache(fsp, SAMBA_WRITE_FLUSH);
 		}
@@ -845,13 +868,15 @@ n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
 				return -1;
 			}
 		}
-		DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n",
-			(double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n));
+		DEBUG(9, ("wcp->offset = %.0f wcp->data_size = %u cache "
+			  "return %u\n",
+			  (double)wcp->offset, (unsigned int)wcp->data_size,
+			  (unsigned int)n));
 
 		total_written += n;
 		return total_written; /* .... that's a write :) */
 	}
-  
+
 	return total_written;
 }
 
-- 
2.1.4


From 38f56ed0ebda3a1bd9fb1aa53b3a3e2ca4f61952 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 20 Feb 2016 10:07:11 +0100
Subject: [PATCH 03/12] lib: Move data_blob_list_item to source4

It's only used in dcesrv_call_state.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/util/data_blob.h               | 5 -----
 source4/rpc_server/dcerpc_server.h | 5 +++++
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/util/data_blob.h b/lib/util/data_blob.h
index 94af767..799e953 100644
--- a/lib/util/data_blob.h
+++ b/lib/util/data_blob.h
@@ -40,11 +40,6 @@ typedef struct datablob {
 	size_t length;
 } DATA_BLOB;
 
-struct data_blob_list_item {
-	struct data_blob_list_item *prev,*next;
-	DATA_BLOB blob;
-};
-
 /* by making struct ldb_val and DATA_BLOB the same, we can simplify
    a fair bit of code */
 #define ldb_val datablob
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index 9a697ce..9f5cfab 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -76,6 +76,11 @@ enum dcesrv_call_list {
 	DCESRV_LIST_PENDING_CALL_LIST
 };
 
+struct data_blob_list_item {
+	struct data_blob_list_item *prev,*next;
+	DATA_BLOB blob;
+};
+
 /* the state of an ongoing dcerpc call */
 struct dcesrv_call_state {
 	struct dcesrv_call_state *next, *prev;
-- 
2.1.4


From b8bc5ea030a58cfce440ac8926e4fc98101be6e8 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 16 Feb 2016 14:59:53 +0100
Subject: [PATCH 04/12] lib: Fix whitespace

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/util_file.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/source3/lib/util_file.c b/source3/lib/util_file.c
index 5584d91..b11da71 100644
--- a/source3/lib/util_file.c
+++ b/source3/lib/util_file.c
@@ -2,17 +2,17 @@
  * Unix SMB/CIFS implementation.
  * SMB parameters and setup
  * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
- * 
+ *
  * 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 3 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, see <http://www.gnu.org/licenses/>.
  */
-- 
2.1.4


From 09b8a4ecc7387c28f87f062b715def100c252f4f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 16 Feb 2016 15:46:06 +0100
Subject: [PATCH 05/12] lib: Remove sys_waitpid

We have waitpid in libreplace

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/proto.h                      |  1 -
 source3/lib/server_prefork.c                 |  2 +-
 source3/lib/smbrun.c                         |  4 ++--
 source3/lib/system.c                         | 15 +--------------
 source3/lib/tdb_validate.c                   |  2 +-
 source3/printing/queue_process.c             |  2 +-
 source3/printing/spoolssd.c                  |  2 +-
 source3/rpc_server/samr/srv_samr_chgpasswd.c |  2 +-
 source3/smbd/server.c                        |  2 +-
 source3/winbindd/winbindd.c                  |  2 +-
 tests/fcntl_lock_thread.c                    |  5 -----
 11 files changed, 10 insertions(+), 29 deletions(-)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 09e9915..aaa5aee 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -243,7 +243,6 @@ int sys_fallocate(int fd, uint32_t mode, off_t offset, off_t len);
 void kernel_flock(int fd, uint32_t share_mode, uint32_t access_mask);
 DIR *sys_fdopendir(int fd);
 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev);
-int sys_waitpid(pid_t pid,int *status,int options);
 char *sys_getwd(void);
 void set_effective_capability(enum smbd_capability capability);
 void drop_effective_capability(enum smbd_capability capability);
diff --git a/source3/lib/server_prefork.c b/source3/lib/server_prefork.c
index c725607..1d64db2 100644
--- a/source3/lib/server_prefork.c
+++ b/source3/lib/server_prefork.c
@@ -329,7 +329,7 @@ static void prefork_cleanup_loop(struct prefork_pool *pfp)
 			continue;
 		}
 
-		pid = sys_waitpid(pfp->pool[i].pid, &status, WNOHANG);
+		pid = waitpid(pfp->pool[i].pid, &status, WNOHANG);
 		if (pid > 0) {
 
 			if (pfp->pool[i].status != PF_WORKER_EXITING) {
diff --git a/source3/lib/smbrun.c b/source3/lib/smbrun.c
index 55f7a87..63b0323 100644
--- a/source3/lib/smbrun.c
+++ b/source3/lib/smbrun.c
@@ -116,7 +116,7 @@ static int smbrun_internal(const char *cmd, int *outfd, bool sanitize)
 
 		
 		/* the parent just waits for the child to exit */
-		while((wpid = sys_waitpid(pid,&status,0)) < 0) {
+		while((wpid = waitpid(pid,&status,0)) < 0) {
 			if(errno == EINTR) {
 				errno = 0;
 				continue;
@@ -287,7 +287,7 @@ int smbrunsecret(const char *cmd, const char *secret)
 		close(ifd[1]);
 
 		/* the parent just waits for the child to exit */
-		while((wpid = sys_waitpid(pid, &status, 0)) < 0) {
+		while((wpid = waitpid(pid, &status, 0)) < 0) {
 			if(errno == EINTR) {
 				errno = 0;
 				continue;
diff --git a/source3/lib/system.c b/source3/lib/system.c
index 0351e37..acc121d 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -572,19 +572,6 @@ int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
 }
 
 /*******************************************************************
-The wait() calls vary between systems
-********************************************************************/
-
-int sys_waitpid(pid_t pid,int *status,int options)
-{
-#ifdef HAVE_WAITPID
-	return waitpid(pid,status,options);
-#else /* HAVE_WAITPID */
-	return wait4(pid, status, options, NULL);
-#endif /* HAVE_WAITPID */
-}
-
-/*******************************************************************
  System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
  on error (malloc fail usually).
 ********************************************************************/
@@ -1200,7 +1187,7 @@ int sys_pclose(int fd)
 	 */
 
 	do {
-		wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
+		wait_pid = waitpid (entry->child_pid, &wstatus, 0);
 	} while (wait_pid == -1 && errno == EINTR);
 
 	SAFE_FREE(entry);
diff --git a/source3/lib/tdb_validate.c b/source3/lib/tdb_validate.c
index 2592402..9db182f 100644
--- a/source3/lib/tdb_validate.c
+++ b/source3/lib/tdb_validate.c
@@ -135,7 +135,7 @@ int tdb_validate(struct tdb_context *tdb, tdb_validate_data_func validate_fn)
 		(unsigned int)child_pid));
 
 	DEBUG(10, ("tdb_validate: waiting for child to finish...\n"));
-	while  ((wait_pid = sys_waitpid(child_pid, &child_status, 0)) < 0) {
+	while  ((wait_pid = waitpid(child_pid, &child_status, 0)) < 0) {
 		if (errno == EINTR) {
 			DEBUG(10, ("tdb_validate: got signal during waitpid, "
 				   "retrying\n"));
diff --git a/source3/printing/queue_process.c b/source3/printing/queue_process.c
index 6e31ee4..c9e5522 100644
--- a/source3/printing/queue_process.c
+++ b/source3/printing/queue_process.c
@@ -269,7 +269,7 @@ static void bq_sig_chld_handler(struct tevent_context *ev_ctx,
 	int status;
 	pid_t pid;
 
-	pid = sys_waitpid(-1, &status, WNOHANG);
+	pid = waitpid(-1, &status, WNOHANG);
 	if (WIFEXITED(status)) {
 		DEBUG(6, ("Bq child process %d terminated with %d\n",
 			  (int)pid, WEXITSTATUS(status)));
diff --git a/source3/printing/spoolssd.c b/source3/printing/spoolssd.c
index 51d10b6..48a914e 100644
--- a/source3/printing/spoolssd.c
+++ b/source3/printing/spoolssd.c
@@ -478,7 +478,7 @@ static void check_updater_child(struct tevent_context *ev_ctx,
 		return;
 	}
 
-	pid = sys_waitpid(background_lpq_updater_pid, &status, WNOHANG);
+	pid = waitpid(background_lpq_updater_pid, &status, WNOHANG);
 	if (pid > 0) {
 		DEBUG(2, ("The background queue child died... Restarting!\n"));
 		pid = start_background_queue(ev_ctx, msg_ctx, bq_logfile);
diff --git a/source3/rpc_server/samr/srv_samr_chgpasswd.c b/source3/rpc_server/samr/srv_samr_chgpasswd.c
index bfb7af6..ad4eaa7 100644
--- a/source3/rpc_server/samr/srv_samr_chgpasswd.c
+++ b/source3/rpc_server/samr/srv_samr_chgpasswd.c
@@ -430,7 +430,7 @@ static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
 			kill(pid, SIGKILL);	/* be sure to end this process */
 		}
 
-		while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
+		while ((wpid = waitpid(pid, &wstat, 0)) < 0) {
 			if (errno == EINTR) {
 				errno = 0;
 				continue;
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 42fcad6..d68615e 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -630,7 +630,7 @@ static void smbd_sig_chld_handler(struct tevent_context *ev,
 		talloc_get_type_abort(private_data,
 		struct smbd_parent_context);
 
-	while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
+	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
 		bool unclean_shutdown = False;
 
 		/* If the child terminated normally, assume
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index 78df632..002ba3f 100644
--- a/source3/winbindd/winbindd.c
+++ b/source3/winbindd/winbindd.c
@@ -432,7 +432,7 @@ static void winbindd_sig_chld_handler(struct tevent_context *ev,
 {
 	pid_t pid;
 
-	while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
+	while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
 		winbind_child_died(pid);
 	}
 }
diff --git a/tests/fcntl_lock_thread.c b/tests/fcntl_lock_thread.c
index f311056..e341514 100644
--- a/tests/fcntl_lock_thread.c
+++ b/tests/fcntl_lock_thread.c
@@ -15,11 +15,6 @@
 #include <errno.h>
 #include <pthread.h>
 
-static int sys_waitpid(pid_t pid,int *status,int options)
-{
-  return waitpid(pid,status,options);
-}
-
 #define DATA "conftest.fcntl"
 
 #define SEEK_SET 0
-- 
2.1.4


From 695ad1daad376dde6e4656b88dae9571795a7106 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 16 Feb 2016 15:58:52 +0100
Subject: [PATCH 06/12] lib: Extract sys_popen()

This was added by Jeremy with 3cf31a194f5, do the (C) accordingly

sys_popen is a pretty isolated functionality, and I'd like to use it
soon without "includes.h", needed by "proto.h"

Except for one malloc->talloc this is supposed to be a 1:1 copy

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/proto.h |   2 -
 source3/lib/sys_popen.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++++
 source3/lib/sys_popen.h |  26 +++++
 source3/lib/system.c    | 231 -------------------------------------------
 source3/lib/util_file.c |   1 +
 source3/wscript_build   |   1 +
 6 files changed, 281 insertions(+), 233 deletions(-)
 create mode 100644 source3/lib/sys_popen.c
 create mode 100644 source3/lib/sys_popen.h

diff --git a/source3/include/proto.h b/source3/include/proto.h
index aaa5aee..00ff9f2 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -251,8 +251,6 @@ void sys_srandom(unsigned int seed);
 int groups_max(void);
 int sys_getgroups(int setlen, gid_t *gidset);
 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset);
-int sys_popen(const char *command);
-int sys_pclose(int fd);
 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size);
 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size);
 ssize_t sys_listxattr (const char *path, char *list, size_t size);
diff --git a/source3/lib/sys_popen.c b/source3/lib/sys_popen.c
new file mode 100644
index 0000000..8380789
--- /dev/null
+++ b/source3/lib/sys_popen.c
@@ -0,0 +1,253 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *  Samba system utilities
+ * Copyright (C) Jeremy Allison  2000
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/wait.h"
+#include <talloc.h>
+#include "lib/sys_popen.h"
+#include "lib/util/debug.h"
+
+/**************************************************************************
+ Extract a command into an arg list.
+****************************************************************************/
+
+static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
+{
+	char *trunc_cmd;
+	char *saveptr;
+	char *ptr;
+	int argcl;
+	char **argl = NULL;
+	int i;
+
+	if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
+		DEBUG(0, ("talloc failed\n"));
+		goto nomem;
+	}
+
+	if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
+		TALLOC_FREE(trunc_cmd);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/*
+	 * Count the args.
+	 */
+
+	for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
+		argcl++;
+
+	TALLOC_FREE(trunc_cmd);
+
+	if (!(argl = talloc_array(mem_ctx, char *, argcl + 1))) {
+		goto nomem;
+	}
+
+	/*
+	 * Now do the extraction.
+	 */
+
+	if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
+		goto nomem;
+	}
+
+	ptr = strtok_r(trunc_cmd, " \t", &saveptr);
+	i = 0;
+
+	if (!(argl[i++] = talloc_strdup(argl, ptr))) {
+		goto nomem;
+	}
+
+	while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
+
+		if (!(argl[i++] = talloc_strdup(argl, ptr))) {
+			goto nomem;
+		}
+	}
+
+	argl[i++] = NULL;
+	TALLOC_FREE(trunc_cmd);
+	return argl;
+
+ nomem:
+	DEBUG(0, ("talloc failed\n"));
+	TALLOC_FREE(trunc_cmd);
+	TALLOC_FREE(argl);
+	errno = ENOMEM;
+	return NULL;
+}
+
+/**************************************************************************
+ Wrapper for popen. Safer as it doesn't search a path.
+ Modified from the glibc sources.
+ modified by tridge to return a file descriptor. We must kick our FILE* habit
+****************************************************************************/
+
+typedef struct _popen_list
+{
+	int fd;
+	pid_t child_pid;
+	struct _popen_list *next;
+} popen_list;
+
+static popen_list *popen_chain;
+
+int sys_popen(const char *command)
+{
+	int parent_end, child_end;
+	int pipe_fds[2];
+	popen_list *entry = NULL;
+	char **argl = NULL;
+	int ret;
+
+	if (!*command) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	ret = pipe(pipe_fds);
+	if (ret < 0) {
+		DEBUG(0, ("sys_popen: error opening pipe: %s\n",
+			  strerror(errno)));
+		return -1;
+	}
+
+	parent_end = pipe_fds[0];
+	child_end = pipe_fds[1];
+
+	entry = talloc_zero(NULL, popen_list);
+	if (entry == NULL) {
+		DEBUG(0, ("sys_popen: malloc failed\n"));
+		goto err_exit;
+	}
+
+	/*
+	 * Extract the command and args into a NULL terminated array.
+	 */
+
+	argl = extract_args(NULL, command);
+	if (argl == NULL) {
+		DEBUG(0, ("sys_popen: extract_args() failed: %s\n", strerror(errno)));
+		goto err_exit;
+	}
+
+	entry->child_pid = fork();
+
+	if (entry->child_pid == -1) {
+		DEBUG(0, ("sys_popen: fork failed: %s\n", strerror(errno)));
+		goto err_exit;
+	}
+
+	if (entry->child_pid == 0) {
+
+		/*
+		 * Child !
+		 */
+
+		int child_std_end = STDOUT_FILENO;
+		popen_list *p;
+
+		close(parent_end);
+		if (child_end != child_std_end) {
+			dup2 (child_end, child_std_end);
+			close (child_end);
+		}
+
+		/*
+		 * POSIX.2:  "popen() shall ensure that any streams from previous
+		 * popen() calls that remain open in the parent process are closed
+		 * in the new child process."
+		 */
+
+		for (p = popen_chain; p; p = p->next)
+			close(p->fd);
+
+		ret = execv(argl[0], argl);
+		if (ret == -1) {
+			DEBUG(0, ("sys_popen: ERROR executing command "
+				  "'%s': %s\n", command, strerror(errno)));
+		}
+		_exit (127);
+	}
+
+	/*
+	 * Parent.
+	 */
+
+	close (child_end);
+	TALLOC_FREE(argl);
+
+	/* Link into popen_chain. */
+	entry->next = popen_chain;
+	popen_chain = entry;
+	entry->fd = parent_end;
+
+	return entry->fd;
+
+err_exit:
+
+	TALLOC_FREE(entry);
+	TALLOC_FREE(argl);
+	close(pipe_fds[0]);
+	close(pipe_fds[1]);
+	return -1;
+}
+
+/**************************************************************************
+ Wrapper for pclose. Modified from the glibc sources.
+****************************************************************************/
+
+int sys_pclose(int fd)
+{
+	int wstatus;
+	popen_list **ptr = &popen_chain;
+	popen_list *entry = NULL;
+	pid_t wait_pid;
+	int status = -1;
+
+	/* Unlink from popen_chain. */
+	for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
+		if ((*ptr)->fd == fd) {
+			entry = *ptr;
+			*ptr = (*ptr)->next;
+			status = 0;
+			break;
+		}
+	}
+
+	if (status < 0 || close(entry->fd) < 0)
+		return -1;
+
+	/*
+	 * As Samba is catching and eating child process
+	 * exits we don't really care about the child exit
+	 * code, a -1 with errno = ECHILD will do fine for us.
+	 */
+
+	do {
+		wait_pid = waitpid (entry->child_pid, &wstatus, 0);
+	} while (wait_pid == -1 && errno == EINTR);
+
+	TALLOC_FREE(entry);
+
+	if (wait_pid == -1)
+		return -1;
+	return wstatus;
+}
diff --git a/source3/lib/sys_popen.h b/source3/lib/sys_popen.h
new file mode 100644
index 0000000..6807d3c
--- /dev/null
+++ b/source3/lib/sys_popen.h
@@ -0,0 +1,26 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *  Samba system utilities
+ * Copyright (C) Jeremy Allison  2000
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_SYS_POPEN_H__
+#define __LIB_SYS_POPEN_H__
+
+int sys_popen(const char *command);
+int sys_pclose(int fd);
+
+#endif
diff --git a/source3/lib/system.c b/source3/lib/system.c
index acc121d..3d3eeed 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -966,237 +966,6 @@ int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
 #endif
 }
 
-/**************************************************************************
- Extract a command into an arg list.
-****************************************************************************/
-
-static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
-{
-	char *trunc_cmd;
-	char *saveptr;
-	char *ptr;
-	int argcl;
-	char **argl = NULL;
-	int i;
-
-	if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
-		DEBUG(0, ("talloc failed\n"));
-		goto nomem;
-	}
-
-	if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
-		TALLOC_FREE(trunc_cmd);
-		errno = EINVAL;
-		return NULL;
-	}
-
-	/*
-	 * Count the args.
-	 */
-
-	for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
-		argcl++;
-
-	TALLOC_FREE(trunc_cmd);
-
-	if (!(argl = talloc_array(mem_ctx, char *, argcl + 1))) {
-		goto nomem;
-	}
-
-	/*
-	 * Now do the extraction.
-	 */
-
-	if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
-		goto nomem;
-	}
-
-	ptr = strtok_r(trunc_cmd, " \t", &saveptr);
-	i = 0;
-
-	if (!(argl[i++] = talloc_strdup(argl, ptr))) {
-		goto nomem;
-	}
-
-	while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
-
-		if (!(argl[i++] = talloc_strdup(argl, ptr))) {
-			goto nomem;
-		}
-	}
-
-	argl[i++] = NULL;
-	TALLOC_FREE(trunc_cmd);
-	return argl;
-
- nomem:
-	DEBUG(0, ("talloc failed\n"));
-	TALLOC_FREE(trunc_cmd);
-	TALLOC_FREE(argl);
-	errno = ENOMEM;
-	return NULL;
-}
-
-/**************************************************************************
- Wrapper for popen. Safer as it doesn't search a path.
- Modified from the glibc sources.
- modified by tridge to return a file descriptor. We must kick our FILE* habit
-****************************************************************************/
-
-typedef struct _popen_list
-{
-	int fd;
-	pid_t child_pid;
-	struct _popen_list *next;
-} popen_list;
-
-static popen_list *popen_chain;
-
-int sys_popen(const char *command)
-{
-	int parent_end, child_end;
-	int pipe_fds[2];
-	popen_list *entry = NULL;
-	char **argl = NULL;
-	int ret;
-
-	if (!*command) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	ret = pipe(pipe_fds);
-	if (ret < 0) {
-		DEBUG(0, ("sys_popen: error opening pipe: %s\n",
-			  strerror(errno)));
-		return -1;
-	}
-
-	parent_end = pipe_fds[0];
-	child_end = pipe_fds[1];
-
-	entry = SMB_MALLOC_P(popen_list);
-	if (entry == NULL) {
-		DEBUG(0, ("sys_popen: malloc failed\n"));
-		goto err_exit;
-	}
-
-	ZERO_STRUCTP(entry);
-
-	/*
-	 * Extract the command and args into a NULL terminated array.
-	 */
-
-	argl = extract_args(NULL, command);
-	if (argl == NULL) {
-		DEBUG(0, ("sys_popen: extract_args() failed: %s\n", strerror(errno)));
-		goto err_exit;
-	}
-
-	entry->child_pid = fork();
-
-	if (entry->child_pid == -1) {
-		DEBUG(0, ("sys_popen: fork failed: %s\n", strerror(errno)));
-		goto err_exit;
-	}
-
-	if (entry->child_pid == 0) {
-
-		/*
-		 * Child !
-		 */
-
-		int child_std_end = STDOUT_FILENO;
-		popen_list *p;
-
-		close(parent_end);
-		if (child_end != child_std_end) {
-			dup2 (child_end, child_std_end);
-			close (child_end);
-		}
-
-		/*
-		 * POSIX.2:  "popen() shall ensure that any streams from previous
-		 * popen() calls that remain open in the parent process are closed
-		 * in the new child process."
-		 */
-
-		for (p = popen_chain; p; p = p->next)
-			close(p->fd);
-
-		ret = execv(argl[0], argl);
-		if (ret == -1) {
-			DEBUG(0, ("sys_popen: ERROR executing command "
-				  "'%s': %s\n", command, strerror(errno)));
-		}
-		_exit (127);
-	}
-
-	/*
-	 * Parent.
-	 */
-
-	close (child_end);
-	TALLOC_FREE(argl);
-
-	/* Link into popen_chain. */
-	entry->next = popen_chain;
-	popen_chain = entry;
-	entry->fd = parent_end;
-
-	return entry->fd;
-
-err_exit:
-
-	SAFE_FREE(entry);
-	TALLOC_FREE(argl);
-	close(pipe_fds[0]);
-	close(pipe_fds[1]);
-	return -1;
-}
-
-/**************************************************************************
- Wrapper for pclose. Modified from the glibc sources.
-****************************************************************************/
-
-int sys_pclose(int fd)
-{
-	int wstatus;
-	popen_list **ptr = &popen_chain;
-	popen_list *entry = NULL;
-	pid_t wait_pid;
-	int status = -1;
-
-	/* Unlink from popen_chain. */
-	for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
-		if ((*ptr)->fd == fd) {
-			entry = *ptr;
-			*ptr = (*ptr)->next;
-			status = 0;
-			break;
-		}
-	}
-
-	if (status < 0 || close(entry->fd) < 0)
-		return -1;
-
-	/*
-	 * As Samba is catching and eating child process
-	 * exits we don't really care about the child exit
-	 * code, a -1 with errno = ECHILD will do fine for us.
-	 */
-
-	do {
-		wait_pid = waitpid (entry->child_pid, &wstatus, 0);
-	} while (wait_pid == -1 && errno == EINTR);
-
-	SAFE_FREE(entry);
-
-	if (wait_pid == -1)
-		return -1;
-	return wstatus;
-}
-
 /****************************************************************************
  Return the major devicenumber for UNIX extensions.
 ****************************************************************************/
diff --git a/source3/lib/util_file.c b/source3/lib/util_file.c
index b11da71..533680b 100644
--- a/source3/lib/util_file.c
+++ b/source3/lib/util_file.c
@@ -19,6 +19,7 @@
 
 #include "includes.h"
 #include "lib/util/sys_rw.h"
+#include "lib/sys_popen.h"
 
 /**
  Load from a pipe into memory.
diff --git a/source3/wscript_build b/source3/wscript_build
index 9ec11f9..1a7e05e 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -261,6 +261,7 @@ bld.SAMBA3_SUBSYSTEM('samba3util',
                    lib/util_sock.c
                    lib/util_tsock.c
                    lib/util_transfer_file.c
+                   lib/sys_popen.c
                    lib/sock_exec.c''',
                    deps='ndr LIBTSOCKET samba-security NDR_SECURITY samba-util util_tdb sys_rw iov_buf')
 
-- 
2.1.4


From 3b71c815df05d3feb37a47a7b7abc0a34a27f4a8 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 16 Feb 2016 16:24:29 +0100
Subject: [PATCH 07/12] lib: Remove an unimplemented prototype

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/proto.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 00ff9f2..244c32e 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -452,7 +452,6 @@ bool sid_check_is_wellknown_builtin(const struct dom_sid *sid);
 /* The following definitions come from lib/util_file.c  */
 
 char **file_lines_pload(const char *syscmd, int *numlines);
-void file_lines_free(char **lines);
 
 /* The following definitions come from lib/util_nscd.c  */
 
-- 
2.1.4


From b016c62e5c99e8b2e1de452a8bd3a6b6aa96acfb Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 16 Feb 2016 16:29:01 +0100
Subject: [PATCH 08/12] lib: Add "mem_ctx" to file_lines_pload

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/proto.h         | 3 ++-
 source3/lib/sysquotas.c         | 4 ++--
 source3/lib/util_file.c         | 5 +++--
 source3/printing/print_svid.c   | 4 ++--
 source3/smbd/dfree.c            | 2 +-
 source3/winbindd/idmap_script.c | 2 +-
 6 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 244c32e..5fcea9d 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -451,7 +451,8 @@ bool sid_check_is_wellknown_builtin(const struct dom_sid *sid);
 
 /* The following definitions come from lib/util_file.c  */
 
-char **file_lines_pload(const char *syscmd, int *numlines);
+char **file_lines_pload(TALLOC_CTX *mem_ctx, const char *syscmd,
+			int *numlines);
 
 /* The following definitions come from lib/util_nscd.c  */
 
diff --git a/source3/lib/sysquotas.c b/source3/lib/sysquotas.c
index bacc4b2..95051a5 100644
--- a/source3/lib/sysquotas.c
+++ b/source3/lib/sysquotas.c
@@ -268,7 +268,7 @@ static int command_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t
 
 		DEBUG (3, ("get_quota: Running command %s\n", syscmd));
 
-		lines = file_lines_pload(syscmd, NULL);
+		lines = file_lines_pload(talloc_tos(), syscmd, NULL);
 		SAFE_FREE(syscmd);
 
 		if (lines) {
@@ -416,7 +416,7 @@ static int command_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t
 
 		DEBUG (3, ("get_quota: Running command %s\n", syscmd));
 
-		lines = file_lines_pload(syscmd, NULL);
+		lines = file_lines_pload(talloc_tos(), syscmd, NULL);
 		SAFE_FREE(syscmd);
 		if (lines) {
 			char *line = lines[0];
diff --git a/source3/lib/util_file.c b/source3/lib/util_file.c
index 533680b..3016c9b 100644
--- a/source3/lib/util_file.c
+++ b/source3/lib/util_file.c
@@ -74,7 +74,8 @@ static char *file_pload(const char *syscmd, size_t *size)
  must be freed with TALLOC_FREE.
 **/
 
-char **file_lines_pload(const char *syscmd, int *numlines)
+char **file_lines_pload(TALLOC_CTX *mem_ctx, const char *syscmd,
+			int *numlines)
 {
 	char *p;
 	size_t size;
@@ -84,5 +85,5 @@ char **file_lines_pload(const char *syscmd, int *numlines)
 		return NULL;
 	}
 
-	return file_lines_parse(p, size, numlines, NULL);
+	return file_lines_parse(p, size, numlines, mem_ctx);
 }
diff --git a/source3/printing/print_svid.c b/source3/printing/print_svid.c
index 879661b..3b95539 100644
--- a/source3/printing/print_svid.c
+++ b/source3/printing/print_svid.c
@@ -47,8 +47,8 @@ bool sysv_cache_reload(struct pcap_cache **_pcache)
 	DEBUG(5, ("reloading sysv printcap cache\n"));
 #endif
 
-	if ((lines = file_lines_pload("/usr/bin/lpstat -v", NULL)) == NULL)
-	{
+	lines = file_lines_pload(talloc_tos(), "/usr/bin/lpstat -v", NULL);
+	if (lines == NULL) {
 #if defined(HPUX)
       
        	       /*
diff --git a/source3/smbd/dfree.c b/source3/smbd/dfree.c
index 765fbe6..188faa2 100644
--- a/source3/smbd/dfree.c
+++ b/source3/smbd/dfree.c
@@ -83,7 +83,7 @@ uint64_t sys_disk_free(connection_struct *conn, const char *path,
 
 		DEBUG (3, ("disk_free: Running command '%s'\n", syscmd));
 
-		lines = file_lines_pload(syscmd, NULL);
+		lines = file_lines_pload(talloc_tos(), syscmd, NULL);
 		if (lines != NULL) {
 			char *line = lines[0];
 
diff --git a/source3/winbindd/idmap_script.c b/source3/winbindd/idmap_script.c
index e758b4e..fbde6c5 100644
--- a/source3/winbindd/idmap_script.c
+++ b/source3/winbindd/idmap_script.c
@@ -81,7 +81,7 @@ static NTSTATUS idmap_script_script(struct idmap_script_context *ctx,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	lines = file_lines_pload(cmd, &numlines);
+	lines = file_lines_pload(talloc_tos(), cmd, &numlines);
 	talloc_free(cmd);
 	if (!lines) {
 		return NT_STATUS_NONE_MAPPED;
-- 
2.1.4


From b438f4ac62d1c82a70af326ee16544e425c9533f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 16 Feb 2016 17:01:04 +0100
Subject: [PATCH 09/12] lib: Add file_pload_send/recv

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/proto.h |   6 +++
 source3/lib/util_file.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 133 insertions(+)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 5fcea9d..362a462 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -451,6 +451,12 @@ bool sid_check_is_wellknown_builtin(const struct dom_sid *sid);
 
 /* The following definitions come from lib/util_file.c  */
 
+struct tevent_req *file_pload_send(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   const char *syscmd, size_t maxsize);
+int file_pload_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+		    uint8_t **buf);
+
 char **file_lines_pload(TALLOC_CTX *mem_ctx, const char *syscmd,
 			int *numlines);
 
diff --git a/source3/lib/util_file.c b/source3/lib/util_file.c
index 3016c9b..e8e9b27 100644
--- a/source3/lib/util_file.c
+++ b/source3/lib/util_file.c
@@ -20,6 +20,133 @@
 #include "includes.h"
 #include "lib/util/sys_rw.h"
 #include "lib/sys_popen.h"
+#include "lib/async_req/async_sock.h"
+#include "lib/util/tevent_unix.h"
+
+struct file_pload_state {
+	struct tevent_context *ev;
+	size_t maxsize;
+	int fd;
+	uint8_t *buf;
+};
+
+static int file_pload_state_destructor(struct file_pload_state *s);
+static void file_pload_readable(struct tevent_req *subreq);
+
+struct tevent_req *file_pload_send(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   const char *syscmd, size_t maxsize)
+{
+	struct tevent_req *req, *subreq;
+	struct file_pload_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct file_pload_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->maxsize = maxsize;
+
+	state->fd = sys_popen(syscmd);
+	if (state->fd == -1) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+	talloc_set_destructor(state, file_pload_state_destructor);
+
+	subreq = wait_for_read_send(state, state->ev, state->fd, false);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, file_pload_readable, req);
+	return req;
+}
+
+static int file_pload_state_destructor(struct file_pload_state *s)
+{
+	if (s->fd != -1) {
+		sys_pclose(s->fd);
+		s->fd = -1;
+	}
+	return 0;
+}
+
+static void file_pload_readable(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct file_pload_state *state = tevent_req_data(
+		req, struct file_pload_state);
+	uint8_t buf[1024];
+	uint8_t *tmp;
+	ssize_t nread;
+	size_t bufsize;
+	int err;
+	bool ok;
+
+	ok = wait_for_read_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	if (!ok) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	nread = sys_read(state->fd, buf, sizeof(buf));
+	if (nread == -1) {
+		tevent_req_error(req, errno);
+		return;
+	}
+	if (nread == 0) {
+		tevent_req_done(req);
+		return;
+	}
+
+	bufsize = talloc_get_size(state->buf);
+
+	if (((bufsize + nread) < bufsize) ||
+	    ((bufsize + nread + 1) < bufsize)) {
+		/* overflow */
+		tevent_req_error(req, EMSGSIZE);
+		return;
+	}
+
+	if ((state->maxsize != 0) && ((bufsize + nread) > state->maxsize)) {
+		tevent_req_error(req, EMSGSIZE);
+		return;
+	}
+
+	tmp = talloc_realloc(state, state->buf, uint8_t, bufsize + nread + 1);
+	if (tevent_req_nomem(tmp, req)) {
+		return;
+	}
+	state->buf = tmp;
+
+	memcpy(state->buf + bufsize, buf, nread);
+	state->buf[bufsize+nread] = '\0';
+
+	subreq = wait_for_read_send(state, state->ev, state->fd, false);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, file_pload_readable, req);
+}
+
+int file_pload_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+		    uint8_t **buf)
+{
+	struct file_pload_state *state = tevent_req_data(
+		req, struct file_pload_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		return err;
+	}
+	*buf = talloc_move(mem_ctx, &state->buf);
+
+	tevent_req_received(req);
+
+	return 0;
+}
 
 /**
  Load from a pipe into memory.
-- 
2.1.4


From db08acd1f1a76aa37e7e5099ed3676de8fd6f191 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 16 Feb 2016 17:09:43 +0100
Subject: [PATCH 10/12] lib: Remove "includes.h" from util_file.c

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/proto.h         | 11 -----------
 source3/lib/sysquotas.c         |  1 +
 source3/lib/util_file.c         |  5 ++++-
 source3/lib/util_file.h         | 35 +++++++++++++++++++++++++++++++++++
 source3/printing/print_svid.c   |  1 +
 source3/smbd/dfree.c            |  1 +
 source3/winbindd/idmap_script.c |  1 +
 7 files changed, 43 insertions(+), 12 deletions(-)
 create mode 100644 source3/lib/util_file.h

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 362a462..0c15f96 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -449,17 +449,6 @@ bool sid_check_is_builtin(const struct dom_sid *sid);
 bool sid_check_is_in_builtin(const struct dom_sid *sid);
 bool sid_check_is_wellknown_builtin(const struct dom_sid *sid);
 
-/* The following definitions come from lib/util_file.c  */
-
-struct tevent_req *file_pload_send(TALLOC_CTX *mem_ctx,
-				   struct tevent_context *ev,
-				   const char *syscmd, size_t maxsize);
-int file_pload_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-		    uint8_t **buf);
-
-char **file_lines_pload(TALLOC_CTX *mem_ctx, const char *syscmd,
-			int *numlines);
-
 /* The following definitions come from lib/util_nscd.c  */
 
 void smb_nscd_flush_user_cache(void);
diff --git a/source3/lib/sysquotas.c b/source3/lib/sysquotas.c
index 95051a5..102e458 100644
--- a/source3/lib/sysquotas.c
+++ b/source3/lib/sysquotas.c
@@ -19,6 +19,7 @@
 
 
 #include "includes.h"
+#include "lib/util_file.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_QUOTA
diff --git a/source3/lib/util_file.c b/source3/lib/util_file.c
index e8e9b27..d3139e5 100644
--- a/source3/lib/util_file.c
+++ b/source3/lib/util_file.c
@@ -17,7 +17,10 @@
  * this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "includes.h"
+#include "replace.h"
+#include "lib/util_file.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
 #include "lib/util/sys_rw.h"
 #include "lib/sys_popen.h"
 #include "lib/async_req/async_sock.h"
diff --git a/source3/lib/util_file.h b/source3/lib/util_file.h
new file mode 100644
index 0000000..9175ed0
--- /dev/null
+++ b/source3/lib/util_file.h
@@ -0,0 +1,35 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_UTIL_FILE_H__
+#define __LIB_UTIL_FILE_H__
+
+#include "replace.h"
+#include <tevent.h>
+
+struct tevent_req *file_pload_send(TALLOC_CTX *mem_ctx,
+				   struct tevent_context *ev,
+				   const char *syscmd, size_t maxsize);
+int file_pload_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+		    uint8_t **buf);
+
+char **file_lines_pload(TALLOC_CTX *mem_ctx, const char *syscmd,
+			int *numlines);
+
+#endif
diff --git a/source3/printing/print_svid.c b/source3/printing/print_svid.c
index 3b95539..f041ef4 100644
--- a/source3/printing/print_svid.c
+++ b/source3/printing/print_svid.c
@@ -33,6 +33,7 @@
 
 #include "includes.h"
 #include "printing/pcap.h"
+#include "lib/util_file.h"
 
 #if defined(SYSV) || defined(HPUX)
 bool sysv_cache_reload(struct pcap_cache **_pcache)
diff --git a/source3/smbd/dfree.c b/source3/smbd/dfree.c
index 188faa2..fc52e51 100644
--- a/source3/smbd/dfree.c
+++ b/source3/smbd/dfree.c
@@ -20,6 +20,7 @@
 #include "includes.h"
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
+#include "lib/util_file.h"
 
 /****************************************************************************
  Normalise for DOS usage.
diff --git a/source3/winbindd/idmap_script.c b/source3/winbindd/idmap_script.c
index fbde6c5..a929d6e 100644
--- a/source3/winbindd/idmap_script.c
+++ b/source3/winbindd/idmap_script.c
@@ -35,6 +35,7 @@
 #include "idmap.h"
 #include "idmap_rw.h"
 #include "../libcli/security/dom_sid.h"
+#include "lib/util_file.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_IDMAP
-- 
2.1.4


From b9359c91a1176875d7d95e49b34343e83a7e97ad Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 22 Feb 2016 11:59:52 +0100
Subject: [PATCH 11/12] lib: Avoid an unnecessary cast

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index 30c5f52..346c1ed 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -99,7 +99,7 @@ static bool g_lock_parse(TALLOC_CTX *mem_ctx, TDB_DATA data,
 	struct g_lock_rec *locks;
 
 	if ((data.dsize % sizeof(struct g_lock_rec)) != 0) {
-		DEBUG(1, ("invalid lock record length %d\n", (int)data.dsize));
+		DEBUG(1, ("invalid lock record length %zu\n", data.dsize));
 		return false;
 	}
 	num_locks = data.dsize / sizeof(struct g_lock_rec);
-- 
2.1.4


From d83087478a8353b504c7164122278cf7d0679e1d Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 17 Feb 2016 14:01:47 +0100
Subject: [PATCH 12/12] idmap_script: Parallelize script calls

Fixes a case I've seen where a user with 200 group memberships timed out and
can now log in.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/idmap_script.c | 622 ++++++++++++++++++++++++++++------------
 1 file changed, 434 insertions(+), 188 deletions(-)

diff --git a/source3/winbindd/idmap_script.c b/source3/winbindd/idmap_script.c
index a929d6e..81603eb 100644
--- a/source3/winbindd/idmap_script.c
+++ b/source3/winbindd/idmap_script.c
@@ -36,6 +36,7 @@
 #include "idmap_rw.h"
 #include "../libcli/security/dom_sid.h"
 #include "lib/util_file.h"
+#include "lib/util/tevent_unix.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_IDMAP
@@ -60,273 +61,518 @@ struct idmap_script_context {
 
   TODO: Needs more validation ... like that we got a UID when we asked for one.
  */
-static NTSTATUS idmap_script_script(struct idmap_script_context *ctx,
-				    struct id_map *map, const char *fmt, ...)
-{
-	va_list ap;
-	char *cmd, **lines;
-	int numlines = 0;
-	unsigned long v;
 
-	cmd = talloc_asprintf(ctx, "%s ", ctx->script);
-	if (!cmd) {
-		DEBUG(10, ("Unable to allocate memory for the script command!\n"));
-		return NT_STATUS_NO_MEMORY;
-	}
+struct idmap_script_xid2sid_state {
+	const char *syscmd;
+	size_t idx;
+	uint8_t *out;
+};
 
-	va_start(ap, fmt);
-	cmd = talloc_vasprintf_append(cmd, fmt, ap);
-	va_end(ap);
-	if (!cmd) {
-		DEBUG(10, ("Unable to allocate memory for the script command!\n"));
-		return NT_STATUS_NO_MEMORY;
+static void idmap_script_xid2sid_done(struct tevent_req *subreq);
+
+static struct tevent_req *idmap_script_xid2sid_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct unixid xid, const char *script, size_t idx)
+{
+	struct tevent_req *req, *subreq;
+	struct idmap_script_xid2sid_state *state;
+	char key;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct idmap_script_xid2sid_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->idx = idx;
+
+	switch (xid.type) {
+	    case ID_TYPE_UID:
+		    key = 'U';
+		    break;
+	    case ID_TYPE_GID:
+		    key = 'G';
+		    break;
+	    case ID_TYPE_BOTH:
+		    key = 'X';
+		    break;
+	    default:
+		    DBG_WARNING("INVALID unix ID type: 0x02%x\n", xid.type);
+		    tevent_req_error(req, EINVAL);
+		    return tevent_req_post(req, ev);
 	}
 
-	lines = file_lines_pload(talloc_tos(), cmd, &numlines);
-	talloc_free(cmd);
-	if (!lines) {
-		return NT_STATUS_NONE_MAPPED;
+	state->syscmd = talloc_asprintf(state, "%s %cID %lu", script, key,
+					(unsigned long)xid.id);
+	if (tevent_req_nomem(state->syscmd, req)) {
+		return tevent_req_post(req, ev);
 	}
 
-	DEBUG(10,("idmap script gave %d lines, first: %s\n", numlines,
-		lines[0]));
-
-	if (sscanf(lines[0], "XID:%lu", &v) == 1) {
-		map->xid.id   = v;
-		map->xid.type = ID_TYPE_BOTH;
-	} else if (sscanf(lines[0], "UID:%lu", &v) == 1) {
-		map->xid.id   = v;
-		map->xid.type = ID_TYPE_UID;
-	} else if (sscanf(lines[0], "GID:%lu", &v) == 1) {
-		map->xid.id   = v;
-		map->xid.type = ID_TYPE_GID;
-	} else if (strncmp(lines[0], "SID:S-", 6) == 0) {
-		if (!string_to_sid(map->sid, &lines[0][4])) {
-			DEBUG(0,("Bad SID in '%s' from idmap script %s\n",
-				 lines[0], ctx->script));
-			talloc_free(lines);
-			return NT_STATUS_NONE_MAPPED;
-		}
-	} else {
-		DEBUG(0,("Bad reply '%s' from idmap script %s\n",
-			 lines[0], ctx->script));
-		talloc_free(lines);
-		return NT_STATUS_NONE_MAPPED;
+	subreq = file_pload_send(state, ev, state->syscmd, 1024);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
 	}
+	tevent_req_set_callback(subreq, idmap_script_xid2sid_done, req);
+	return req;
+}
 
-	talloc_free(lines);
-	return NT_STATUS_OK;
+static void idmap_script_xid2sid_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct idmap_script_xid2sid_state *state = tevent_req_data(
+		req, struct idmap_script_xid2sid_state);
+	int ret;
+
+	ret = file_pload_recv(subreq, state, &state->out);
+	TALLOC_FREE(subreq);
+	if (tevent_req_error(req, ret)) {
+		return;
+	}
+	tevent_req_done(req);
 }
 
-/*
-  Single id to sid lookup function.
-*/
-static NTSTATUS idmap_script_id_to_sid(struct idmap_domain *dom,
-				       struct id_map *map)
+static int idmap_script_xid2sid_recv(struct tevent_req *req, size_t *idx,
+				     enum id_mapping *status,
+				     struct dom_sid *sid)
 {
-	NTSTATUS ret;
-	char *keystr;
-	char *sidstr;
-	struct idmap_script_context *ctx = dom->private_data;
+	struct idmap_script_xid2sid_state *state = tevent_req_data(
+		req, struct idmap_script_xid2sid_state);
+	char *out = (char *)state->out;
+	size_t out_size = talloc_get_size(out);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		return err;
+	}
 
-	if (!dom || !map) {
-		return NT_STATUS_INVALID_PARAMETER;
+	if (out_size == 0) {
+		goto unmapped;
+	}
+	if (state->out[out_size-1] != '\0') {
+		goto unmapped;
 	}
 
-	/* apply filters before checking */
-	if (!idmap_unix_id_is_in_range(map->xid.id, dom)) {
-		DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
-				map->xid.id, dom->low_id, dom->high_id));
-		return NT_STATUS_NONE_MAPPED;
+	*idx = state->idx;
+
+	if ((strncmp(out, "SID:S-", 6) != 0) ||
+	    !dom_sid_parse(out+4, sid)) {
+		DBG_WARNING("Bad sid from script: %s\n", out);
+		goto unmapped;
 	}
 
-	switch (map->xid.type) {
+	*status = ID_MAPPED;
+	return 0;
 
-	case ID_TYPE_UID:
-		keystr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
-		break;
+unmapped:
+	*sid = (struct dom_sid) {0};
+	*status = ID_UNMAPPED;
+	return 0;
+}
 
-	case ID_TYPE_GID:
-		keystr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
-		break;
+struct idmap_script_xids2sids_state {
+	struct id_map **ids;
+	size_t num_ids;
+	size_t num_done;
+};
 
-	case ID_TYPE_BOTH:
-		keystr = talloc_asprintf(ctx, "XID %lu", (unsigned long)map->xid.id);
-		break;
+static void idmap_script_xids2sids_done(struct tevent_req *subreq);
 
-	default:
-		DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
-		return NT_STATUS_INVALID_PARAMETER;
+static struct tevent_req *idmap_script_xids2sids_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct id_map **ids, size_t num_ids, const char *script)
+{
+	struct tevent_req *req;
+	struct idmap_script_xids2sids_state *state;
+	size_t i;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct idmap_script_xids2sids_state);
+	if (req == NULL) {
+		return NULL;
 	}
+	state->ids = ids;
+	state->num_ids = num_ids;
 
-	if (keystr == NULL) {
-		DEBUG(0, ("Out of memory!\n"));
-		ret = NT_STATUS_NO_MEMORY;
-		goto done;
+	if (state->num_ids == 0) {
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
 	}
 
-	DEBUG(10,("Running script to fetch mapping %s\n", keystr));
-
-	ret = idmap_script_script(ctx, map, "IDTOSID %s", keystr);
-	if (!NT_STATUS_IS_OK(ret)) {
-		goto done;
-	}
+	for (i=0; i<num_ids; i++) {
+		struct tevent_req *subreq;
 
-	sidstr = sid_string_talloc(keystr, map->sid);
-	if (!sidstr) {
-		ret = NT_STATUS_NO_MEMORY;
-		goto done;
+		subreq = idmap_script_xid2sid_send(
+			state, ev, ids[i]->xid, script, i);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(subreq, idmap_script_xids2sids_done,
+					req);
 	}
 
-	DEBUG(10,("Found id %s:%d -> %s\n", keystr, map->xid.id,
-		  (const char *)sidstr));
-	ret = NT_STATUS_OK;
-
-done:
-	talloc_free(keystr);
-	return ret;
+	return req;
 }
 
-/*
- Single sid to id lookup function.
-*/
-static NTSTATUS idmap_script_sid_to_id(struct idmap_domain *dom,
-				       struct id_map *map)
+static void idmap_script_xids2sids_done(struct tevent_req *subreq)
 {
-	NTSTATUS ret;
-	char *keystr;
-	struct idmap_script_context *ctx = dom->private_data;
-	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct idmap_script_xids2sids_state *state = tevent_req_data(
+		req, struct idmap_script_xids2sids_state);
+	size_t idx = 0;
+	enum id_mapping status = ID_UNKNOWN;
+	struct dom_sid sid = {0};
+	int ret;
+
+	ret = idmap_script_xid2sid_recv(subreq, &idx, &status, &sid);
+	TALLOC_FREE(subreq);
+	if (tevent_req_error(req, ret)) {
+		return;
+	}
 
-	keystr = sid_string_talloc(tmp_ctx, map->sid);
-	if (keystr == NULL) {
-		DEBUG(0, ("Out of memory!\n"));
-		ret = NT_STATUS_NO_MEMORY;
-		goto done;
+	if (idx >= state->num_ids) {
+		tevent_req_error(req, EINVAL);
+		return;
 	}
 
-	DEBUG(10,("Fetching record %s\n", keystr));
+	state->ids[idx]->status = status;
 
-	if (ctx->script == NULL) {
-		ret = NT_STATUS_NONE_MAPPED;
-		goto done;
+	state->ids[idx]->sid = dom_sid_dup(state->ids, &sid);
+	if (tevent_req_nomem(state->ids[idx]->sid, req)) {
+		return;
 	}
 
-	ret = idmap_script_script(ctx, map, "SIDTOID %s", keystr);
-	if (!NT_STATUS_IS_OK(ret)) {
-		goto done;
-	}
+	state->num_done += 1;
 
-	/* apply filters before returning result */
-	if (!idmap_unix_id_is_in_range(map->xid.id, dom)) {
-		DEBUG(5, ("Script returned id (%u) out of range (%u - %u)."
-			  " Filtered!\n",
-			  map->xid.id, dom->low_id, dom->high_id));
-		ret = NT_STATUS_NONE_MAPPED;
-		goto done;
+	if (state->num_done >= state->num_ids) {
+		tevent_req_done(req);
 	}
+}
+
+static int idmap_script_xids2sids_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_unix(req);
+}
 
-done:
-	talloc_free(tmp_ctx);
+static int idmap_script_xids2sids(struct id_map **ids, size_t num_ids,
+				  const char *script)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct tevent_context *ev;
+	struct tevent_req *req;
+	int ret = ENOMEM;
+
+	ev = samba_tevent_context_init(frame);
+	if (ev == NULL) {
+		goto fail;
+	}
+	req = idmap_script_xids2sids_send(frame, ev, ids, num_ids, script);
+	if (req == NULL) {
+		goto fail;
+	}
+	if (!tevent_req_poll(req, ev)) {
+		ret = errno;
+		goto fail;
+	}
+	ret = idmap_script_xids2sids_recv(req);
+fail:
+	TALLOC_FREE(frame);
 	return ret;
 }
 
 static NTSTATUS idmap_script_unixids_to_sids(struct idmap_domain *dom,
-				      struct id_map **ids)
+					     struct id_map **ids)
 {
-	NTSTATUS ret;
-	int i, num_mapped = 0;
+	struct idmap_script_context *ctx = talloc_get_type_abort(
+		dom->private_data, struct idmap_script_context);
+	int ret;
+	size_t i, num_ids, num_mapped;
 
 	DEBUG(10, ("%s called ...\n", __func__));
 	/* Init status to avoid surprise ... */
 	for (i = 0; ids[i]; i++) {
 		ids[i]->status = ID_UNKNOWN;
 	}
+	num_ids = i;
+
+	ret = idmap_script_xids2sids(ids, num_ids, ctx->script);
+	if (ret != 0) {
+		DBG_DEBUG("idmap_script_sids2xids returned %s\n",
+			  strerror(ret));
+		return map_nt_error_from_unix(ret);
+	}
+
+	num_mapped = 0;
 
 	for (i = 0; ids[i]; i++) {
-		ret = idmap_script_id_to_sid(dom, ids[i]);
-		if (!NT_STATUS_IS_OK(ret)) {
-			if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
-				ids[i]->status = ID_UNMAPPED;
-				continue;
-			}
-
-			/*
-			 * We cannot keep going if it is other than mapping
-			 * failed.
-			 */
-			goto done;
+		if (ids[i]->status == ID_MAPPED) {
+			num_mapped += 1;
 		}
+	}
+
+	if (num_mapped == 0) {
+		return NT_STATUS_NONE_MAPPED;
+	}
+	if (num_mapped < num_ids) {
+		return STATUS_SOME_UNMAPPED;
+	}
+	return NT_STATUS_OK;
+}
+
+struct idmap_script_sid2xid_state {
+	const char *syscmd;
+	size_t idx;
+	uint8_t *out;
+};
+
+static void idmap_script_sid2xid_done(struct tevent_req *subreq);
 
-		ids[i]->status = ID_MAPPED;
-		num_mapped++;
+static struct tevent_req *idmap_script_sid2xid_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	const struct dom_sid *sid, const char *script, size_t idx)
+{
+	struct tevent_req *req, *subreq;
+	struct idmap_script_sid2xid_state *state;
+	char sidbuf[DOM_SID_STR_BUFLEN];
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct idmap_script_sid2xid_state);
+	if (req == NULL) {
+		return NULL;
 	}
+	state->idx = idx;
 
-	ret = NT_STATUS_OK;
+	dom_sid_string_buf(sid, sidbuf, sizeof(sidbuf));
 
-done:
-	if (NT_STATUS_IS_OK(ret)) {
-		if (i == 0 || num_mapped == 0) {
-			ret = NT_STATUS_NONE_MAPPED;
-		}
-		else if (num_mapped < i) {
-			ret = STATUS_SOME_UNMAPPED;
-		} else {
-			DEBUG(10, ("Returning NT_STATUS_OK\n"));
-			ret = NT_STATUS_OK;
+	state->syscmd = talloc_asprintf(state, "%s SIDTOID %s",
+					script, sidbuf);
+	if (tevent_req_nomem(state->syscmd, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	subreq = file_pload_send(state, ev, state->syscmd, 1024);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, idmap_script_sid2xid_done, req);
+	return req;
+}
+
+static void idmap_script_sid2xid_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct idmap_script_sid2xid_state *state = tevent_req_data(
+		req, struct idmap_script_sid2xid_state);
+	int ret;
+
+	ret = file_pload_recv(subreq, state, &state->out);
+	TALLOC_FREE(subreq);
+	if (tevent_req_error(req, ret)) {
+		return;
+	}
+	tevent_req_done(req);
+}
+
+static int idmap_script_sid2xid_recv(struct tevent_req *req,
+				     size_t *idx, enum id_mapping *status,
+				     struct unixid *xid)
+{
+	struct idmap_script_sid2xid_state *state = tevent_req_data(
+		req, struct idmap_script_sid2xid_state);
+	char *out = (char *)state->out;
+	size_t out_size = talloc_get_size(out);
+	unsigned long v;
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		return err;
+	}
+
+	if (out_size == 0) {
+		goto unmapped;
+	}
+	if (state->out[out_size-1] != '\0') {
+		goto unmapped;
+	}
+
+	*idx = state->idx;
+
+	if (sscanf(out, "XID:%lu\n", &v) == 1) {
+		*xid = (struct unixid) { .id = v, .type = ID_TYPE_BOTH };
+	} else if (sscanf(out, "UID:%lu\n", &v) == 1) {
+		*xid = (struct unixid) { .id = v, .type = ID_TYPE_UID };
+	} else if (sscanf(out, "GID:%lu\n", &v) == 1) {
+		*xid = (struct unixid) { .id = v, .type = ID_TYPE_GID };
+	} else {
+		goto unmapped;
+	}
+
+	*status = ID_MAPPED;
+	return 0;
+
+unmapped:
+	*xid = (struct unixid) { .id = UINT32_MAX,
+				 .type = ID_TYPE_NOT_SPECIFIED };
+	*status = ID_UNMAPPED;
+	return 0;
+}
+
+struct idmap_script_sids2xids_state {
+	struct id_map **ids;
+	size_t num_ids;
+	size_t num_done;
+};
+
+static void idmap_script_sids2xids_done(struct tevent_req *subreq);
+
+static struct tevent_req *idmap_script_sids2xids_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct id_map **ids, size_t num_ids, const char *script)
+{
+	struct tevent_req *req;
+	struct idmap_script_sids2xids_state *state;
+	size_t i;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct idmap_script_sids2xids_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ids = ids;
+	state->num_ids = num_ids;
+
+	if (state->num_ids == 0) {
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	for (i=0; i<num_ids; i++) {
+		struct tevent_req *subreq;
+
+		subreq = idmap_script_sid2xid_send(
+			state, ev, ids[i]->sid, script, i);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
 		}
+		tevent_req_set_callback(subreq, idmap_script_sids2xids_done,
+					req);
+	}
+
+	return req;
+}
+
+static void idmap_script_sids2xids_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct idmap_script_sids2xids_state *state = tevent_req_data(
+		req, struct idmap_script_sids2xids_state);
+	size_t idx = 0;
+	enum id_mapping status = ID_UNKNOWN;
+	struct unixid xid = { .id = UINT32_MAX,
+			      .type = ID_TYPE_NOT_SPECIFIED };
+	int ret;
+
+	ret = idmap_script_sid2xid_recv(subreq, &idx, &status, &xid);
+	TALLOC_FREE(subreq);
+	if (tevent_req_error(req, ret)) {
+		return;
+	}
+
+	if (idx >= state->num_ids) {
+		tevent_req_error(req, EINVAL);
+		return;
 	}
 
+	state->ids[idx]->status = status;
+	state->ids[idx]->xid = xid;
+
+	state->num_done += 1;
+
+	if (state->num_done >= state->num_ids) {
+		tevent_req_done(req);
+	}
+}
+
+static int idmap_script_sids2xids_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_unix(req);
+}
+
+static int idmap_script_sids2xids(struct id_map **ids, size_t num_ids,
+				  const char *script)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct tevent_context *ev;
+	struct tevent_req *req;
+	int ret = ENOMEM;
+
+	ev = samba_tevent_context_init(frame);
+	if (ev == NULL) {
+		goto fail;
+	}
+	req = idmap_script_sids2xids_send(frame, ev, ids, num_ids, script);
+	if (req == NULL) {
+		goto fail;
+	}
+	if (!tevent_req_poll(req, ev)) {
+		ret = errno;
+		goto fail;
+	}
+	ret = idmap_script_sids2xids_recv(req);
+fail:
+	TALLOC_FREE(frame);
 	return ret;
 }
 
 static NTSTATUS idmap_script_sids_to_unixids(struct idmap_domain *dom,
-				      struct id_map **ids)
+					     struct id_map **ids)
 {
-	NTSTATUS ret;
-	int i, num_mapped = 0;
+	struct idmap_script_context *ctx = talloc_get_type_abort(
+		dom->private_data, struct idmap_script_context);
+	int ret;
+	size_t i, num_ids, num_mapped;
 
 	DEBUG(10, ("%s called ...\n", __func__));
 	/* Init status to avoid surprise ... */
 	for (i = 0; ids[i]; i++) {
 		ids[i]->status = ID_UNKNOWN;
 	}
+	num_ids = i;
 
-	for (i = 0; ids[i]; i++) {
-		ret = idmap_script_sid_to_id(dom, ids[i]);
-		if (!NT_STATUS_IS_OK(ret)) {
-			if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
-				ids[i]->status = ID_UNMAPPED;
-				continue;
-			}
-
-			/*
-			 * We cannot keep going if it is other than mapping
-			 * failed.
-			 */
-			goto done;
-		}
-
-		ids[i]->status = ID_MAPPED;
-		num_mapped++;
+	ret = idmap_script_sids2xids(ids, num_ids, ctx->script);
+	if (ret != 0) {
+		DBG_DEBUG("idmap_script_sids2xids returned %s\n",
+			  strerror(ret));
+		return map_nt_error_from_unix(ret);
 	}
 
-	ret = NT_STATUS_OK;
+	num_mapped = 0;
 
-done:
-	if (NT_STATUS_IS_OK(ret)) {
-		if (i == 0 || num_mapped == 0) {
-			ret = NT_STATUS_NONE_MAPPED;
+	for (i=0; i<num_ids; i++) {
+		struct id_map *map = ids[i];
+
+		if ((map->status == ID_MAPPED) &&
+		    !idmap_unix_id_is_in_range(map->xid.id, dom)) {
+			DBG_INFO("Script returned id (%u) out of range "
+				 "(%u - %u). Filtered!\n",
+				 map->xid.id, dom->low_id, dom->high_id);
+			map->status = ID_UNMAPPED;
 		}
-		else if (num_mapped < i) {
-			ret = STATUS_SOME_UNMAPPED;
-		} else {
-			DEBUG(10, ("Returning NT_STATUS_OK\n"));
-			ret = NT_STATUS_OK;
+
+		if (map->status == ID_MAPPED) {
+			num_mapped += 1;
 		}
 	}
 
-	return ret;
+	if (num_mapped == 0) {
+		return NT_STATUS_NONE_MAPPED;
+	}
+	if (num_mapped < num_ids) {
+		return STATUS_SOME_UNMAPPED;
+	}
+	return NT_STATUS_OK;
 }
 
 /*
-- 
2.1.4



More information about the samba-technical mailing list