]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
Add by-upn idmapping for Himmelblaud
authorDavid Mulder <dmulder@samba.org>
Tue, 30 Jul 2024 15:53:56 +0000 (09:53 -0600)
committerDavid Mulder <dmulder@samba.org>
Wed, 23 Oct 2024 14:21:33 +0000 (14:21 +0000)
Signed-off-by: David Mulder <dmulder@samba.org>
Reviewed-by: Alexander Bokovoy <ab@samba.org>
38 files changed:
.gitlab-ci-main.yml
bootstrap/config.py
bootstrap/generated-dists/centos9s/bootstrap.sh
bootstrap/generated-dists/centos9s/packages.yml
bootstrap/generated-dists/debian11-32bit/bootstrap.sh
bootstrap/generated-dists/debian11-32bit/packages.yml
bootstrap/generated-dists/debian11/bootstrap.sh
bootstrap/generated-dists/debian11/packages.yml
bootstrap/generated-dists/debian12-32bit/bootstrap.sh
bootstrap/generated-dists/debian12-32bit/packages.yml
bootstrap/generated-dists/debian12/bootstrap.sh
bootstrap/generated-dists/debian12/packages.yml
bootstrap/generated-dists/fedora40/bootstrap.sh
bootstrap/generated-dists/fedora40/packages.yml
bootstrap/generated-dists/opensuse155/bootstrap.sh
bootstrap/generated-dists/opensuse155/packages.yml
bootstrap/generated-dists/rocky8/bootstrap.sh
bootstrap/generated-dists/rocky8/packages.yml
bootstrap/generated-dists/ubuntu1804-32bit/bootstrap.sh
bootstrap/generated-dists/ubuntu1804-32bit/packages.yml
bootstrap/generated-dists/ubuntu1804/bootstrap.sh
bootstrap/generated-dists/ubuntu1804/packages.yml
bootstrap/generated-dists/ubuntu2004/bootstrap.sh
bootstrap/generated-dists/ubuntu2004/packages.yml
bootstrap/generated-dists/ubuntu2204/bootstrap.sh
bootstrap/generated-dists/ubuntu2204/packages.yml
bootstrap/sha1sum.txt
himmelblaud/Cargo.toml
himmelblaud/idmap/Cargo.toml [new file with mode: 0644]
himmelblaud/idmap/build.rs [new file with mode: 0644]
himmelblaud/idmap/src/lib.rs [new file with mode: 0644]
himmelblaud/idmap/src/murmurhash3.c [new file with mode: 0644]
himmelblaud/idmap/src/murmurhash3.h [new file with mode: 0644]
himmelblaud/idmap/src/sss_idmap.c [new file with mode: 0644]
himmelblaud/idmap/src/sss_idmap.h [new file with mode: 0644]
himmelblaud/idmap/src/sss_idmap_conv.c [new file with mode: 0644]
himmelblaud/idmap/src/sss_idmap_private.h [new file with mode: 0644]
himmelblaud/idmap/src/util.h [new file with mode: 0644]

index 52d50f1c58b182a7ad0caead5301a704992ef2ef..263d160a08d2bc6f8122b23fd86cc38320096943 100644 (file)
@@ -47,7 +47,7 @@ variables:
   # Set this to the contents of bootstrap/sha1sum.txt
   # which is generated by bootstrap/template.py --render
   #
-  SAMBA_CI_CONTAINER_TAG: 8845099b492ab9888181df3e094e00ae8916ddb7
+  SAMBA_CI_CONTAINER_TAG: 2a20df752f162f9d1f617af785e463fa39944c6e
   #
   # We use the ubuntu2204 image as default as
   # it matches what we have on atb-devel-224
index 1f0eba24b0b48e322f67812c985f250885e5bc84..d862ef407d2f0e2bb11aff2a4bf99d3c732a4e2c 100644 (file)
@@ -84,6 +84,7 @@ PKGS = [
     ('libcap-dev', 'libcap-devel'),
     ('libacl1-dev', 'libacl-devel'),
     ('libattr1-dev', 'libattr-devel'),
+    ('libutf8proc-dev', 'utf8proc-devel'),
 
     # libNAME1-dev, NAME2-devel
     ('libpopt-dev', 'popt-devel'),
index d4684e9cf472ff892c2c36a6a5553a08cabc3bd3..926a76f5d504701601abd521fa52a79f636431f9 100755 (executable)
@@ -116,6 +116,7 @@ dnf install -y \
     tar \
     tracker-devel \
     tree \
+    utf8proc-devel \
     wget \
     which \
     xfsprogs-devel \
index 22f79700ddf367eded935c5432712914191494a3..c218584e723dcaa9fb978242ed9b999c1e64a90c 100644 (file)
@@ -97,6 +97,7 @@ packages:
   - tar
   - tracker-devel
   - tree
+  - utf8proc-devel
   - wget
   - which
   - xfsprogs-devel
index db982ada06783f31d6fa1432004d14e33e745117..4a4ee8cd706e7b4f1e08dea12c8f1038fffc3778 100755 (executable)
@@ -75,6 +75,7 @@ apt-get -y install \
     libtracker-sparql-2.0-dev \
     libunwind-dev \
     liburing-dev \
+    libutf8proc-dev \
     lmdb-utils \
     locales \
     lsb-release \
index 492344da465c4feaf177518cf74794d80bbbff3e..ef6b863e35e5fe460db111d50e94d15ca19f571f 100644 (file)
@@ -64,6 +64,7 @@ packages:
   - libtracker-sparql-2.0-dev
   - libunwind-dev
   - liburing-dev
+  - libutf8proc-dev
   - lmdb-utils
   - locales
   - lsb-release
index db982ada06783f31d6fa1432004d14e33e745117..4a4ee8cd706e7b4f1e08dea12c8f1038fffc3778 100755 (executable)
@@ -75,6 +75,7 @@ apt-get -y install \
     libtracker-sparql-2.0-dev \
     libunwind-dev \
     liburing-dev \
+    libutf8proc-dev \
     lmdb-utils \
     locales \
     lsb-release \
index 492344da465c4feaf177518cf74794d80bbbff3e..ef6b863e35e5fe460db111d50e94d15ca19f571f 100644 (file)
@@ -64,6 +64,7 @@ packages:
   - libtracker-sparql-2.0-dev
   - libunwind-dev
   - liburing-dev
+  - libutf8proc-dev
   - lmdb-utils
   - locales
   - lsb-release
index e85b15d6692b4b26ce4c18858b7e48fb85aa7063..38b3c4777affb92f28bf65471c2486e0f6249997 100755 (executable)
@@ -74,6 +74,7 @@ apt-get -y install \
     libtasn1-dev \
     libunwind-dev \
     liburing-dev \
+    libutf8proc-dev \
     lmdb-utils \
     locales \
     lsb-release \
index b2a027541f1bf7d7f88fc637e09fc3af111ecc7c..bbc9d814fc741484862ba5acf46122bbf174c648 100644 (file)
@@ -63,6 +63,7 @@ packages:
   - libtasn1-dev
   - libunwind-dev
   - liburing-dev
+  - libutf8proc-dev
   - lmdb-utils
   - locales
   - lsb-release
index e85b15d6692b4b26ce4c18858b7e48fb85aa7063..38b3c4777affb92f28bf65471c2486e0f6249997 100755 (executable)
@@ -74,6 +74,7 @@ apt-get -y install \
     libtasn1-dev \
     libunwind-dev \
     liburing-dev \
+    libutf8proc-dev \
     lmdb-utils \
     locales \
     lsb-release \
index b2a027541f1bf7d7f88fc637e09fc3af111ecc7c..bbc9d814fc741484862ba5acf46122bbf174c648 100644 (file)
@@ -63,6 +63,7 @@ packages:
   - libtasn1-dev
   - libunwind-dev
   - liburing-dev
+  - libutf8proc-dev
   - lmdb-utils
   - locales
   - lsb-release
index 99aad7c8c27c99daaccd413aed3329377f643ac8..d794591986b61558f9950e5f54c28565350a142b 100755 (executable)
@@ -115,6 +115,7 @@ dnf install -y \
     tar \
     tracker-devel \
     tree \
+    utf8proc-devel \
     wget \
     which \
     xfsprogs-devel \
index 7bdb86e11b43ad7e5b3347262010ada8b668445e..2596611c5f3bcf3c8bebcb5bdba51c258d71d9a4 100644 (file)
@@ -104,6 +104,7 @@ packages:
   - tar
   - tracker-devel
   - tree
+  - utf8proc-devel
   - wget
   - which
   - xfsprogs-devel
index 687f30ff7bea4622f09c9946243bcd16d41a0212..adfa86155002e356bb83f30e6196cb50307abcf1 100755 (executable)
@@ -107,6 +107,7 @@ zypper --non-interactive install \
     tar \
     tracker-devel \
     tree \
+    utf8proc-devel \
     wget \
     which \
     xfsprogs-devel \
index ca1a96efebde00ca1303203207cb63ff06b7fe9c..05ebdf739d8fb8366ea3e905b5d3d06467d6a82b 100644 (file)
@@ -95,6 +95,7 @@ packages:
   - tar
   - tracker-devel
   - tree
+  - utf8proc-devel
   - wget
   - which
   - xfsprogs-devel
index 639ab513ecd7c44d9462ab34fc961bbf891eb7b3..39dca1599790f90059773b62bb339771866d881c 100755 (executable)
@@ -116,6 +116,7 @@ yum install -y \
     tar \
     tracker-devel \
     tree \
+    utf8proc-devel \
     wget \
     which \
     xfsprogs-devel \
index bc34825f9acf1afbdf6e8451323b229f6ae16f52..4be310344423c4113c650e6eb6067511debb7773 100644 (file)
@@ -98,6 +98,7 @@ packages:
   - tar
   - tracker-devel
   - tree
+  - utf8proc-devel
   - wget
   - which
   - xfsprogs-devel
index b74a5e0e7e1bdc077d5fa3f3226a16faa4bdd882..607da6b4eaec263ba5cf2f01d2056357c3bf6313 100755 (executable)
@@ -75,6 +75,7 @@ apt-get -y install \
     libtasn1-dev \
     libtracker-sparql-2.0-dev \
     libunwind-dev \
+    libutf8proc-dev \
     lmdb-utils \
     locales \
     lsb-release \
index bca52528f6b69d7ca7a296a6f56ad1a1677165a1..80dd35cc204f59e35ae14bad329f3a108077db29 100644 (file)
@@ -64,6 +64,7 @@ packages:
   - libtasn1-dev
   - libtracker-sparql-2.0-dev
   - libunwind-dev
+  - libutf8proc-dev
   - lmdb-utils
   - locales
   - lsb-release
index b74a5e0e7e1bdc077d5fa3f3226a16faa4bdd882..607da6b4eaec263ba5cf2f01d2056357c3bf6313 100755 (executable)
@@ -75,6 +75,7 @@ apt-get -y install \
     libtasn1-dev \
     libtracker-sparql-2.0-dev \
     libunwind-dev \
+    libutf8proc-dev \
     lmdb-utils \
     locales \
     lsb-release \
index bca52528f6b69d7ca7a296a6f56ad1a1677165a1..80dd35cc204f59e35ae14bad329f3a108077db29 100644 (file)
@@ -64,6 +64,7 @@ packages:
   - libtasn1-dev
   - libtracker-sparql-2.0-dev
   - libunwind-dev
+  - libutf8proc-dev
   - lmdb-utils
   - locales
   - lsb-release
index b74a5e0e7e1bdc077d5fa3f3226a16faa4bdd882..607da6b4eaec263ba5cf2f01d2056357c3bf6313 100755 (executable)
@@ -75,6 +75,7 @@ apt-get -y install \
     libtasn1-dev \
     libtracker-sparql-2.0-dev \
     libunwind-dev \
+    libutf8proc-dev \
     lmdb-utils \
     locales \
     lsb-release \
index bca52528f6b69d7ca7a296a6f56ad1a1677165a1..80dd35cc204f59e35ae14bad329f3a108077db29 100644 (file)
@@ -64,6 +64,7 @@ packages:
   - libtasn1-dev
   - libtracker-sparql-2.0-dev
   - libunwind-dev
+  - libutf8proc-dev
   - lmdb-utils
   - locales
   - lsb-release
index 72802d40cf1d1147b4add2c9abe5cae59ffcb089..fab68e8d7b62e424c0e31ddc274342c5ed29fdb5 100755 (executable)
@@ -75,6 +75,7 @@ apt-get -y install \
     libtasn1-dev \
     libunwind-dev \
     liburing-dev \
+    libutf8proc-dev \
     lmdb-utils \
     locales \
     lsb-release \
index c58b08f917482dcfcddd0989680bcc02a1e538bb..bd8052bbf44ec184e7c1661983641d83f9caae5f 100644 (file)
@@ -64,6 +64,7 @@ packages:
   - libtasn1-dev
   - libunwind-dev
   - liburing-dev
+  - libutf8proc-dev
   - lmdb-utils
   - locales
   - lsb-release
index cdb48c417153bf28567985b5772743744eafe50c..cc706332405fcb1a14dd5c293af1754d99e5456c 100644 (file)
@@ -1 +1 @@
-8845099b492ab9888181df3e094e00ae8916ddb7
+2a20df752f162f9d1f617af785e463fa39944c6e
index 8261b59dea560ed21aa1c901830fd4982cb499fa..4206e498c0f687f69fd7450e0075054dcdcfd8ae 100644 (file)
@@ -16,7 +16,8 @@ dbg = { workspace = true }
 
 [workspace]
 members = [
-  "chelps", "dbg", "ntstatus_gen",
+  "chelps", "dbg", "idmap",
+  "ntstatus_gen",
   "param", "tdb",
 ]
 
@@ -26,3 +27,4 @@ dbg = { path = "dbg" }
 chelps = { path = "chelps" }
 ntstatus_gen = { path = "ntstatus_gen" }
 tdb = { path = "tdb" }
+idmap = { path = "idmap" }
diff --git a/himmelblaud/idmap/Cargo.toml b/himmelblaud/idmap/Cargo.toml
new file mode 100644 (file)
index 0000000..6d81b43
--- /dev/null
@@ -0,0 +1,15 @@
+[package]
+name = "idmap"
+edition.workspace = true
+license.workspace = true
+homepage.workspace = true
+version.workspace = true
+
+[dependencies]
+chelps.workspace = true
+dbg.workspace = true
+libc = "0.2.153"
+
+[build-dependencies]
+cc = "1.0.97"
+bindgen = "0.69.4"
diff --git a/himmelblaud/idmap/build.rs b/himmelblaud/idmap/build.rs
new file mode 100644 (file)
index 0000000..c24090c
--- /dev/null
@@ -0,0 +1,32 @@
+use std::env;
+use std::path::Path;
+use std::path::PathBuf;
+
+fn main() {
+    cc::Build::new()
+        .file("src/sss_idmap.c")
+        .file("src/sss_idmap_conv.c")
+        .file("src/murmurhash3.c")
+        .include(Path::new("../../bin/default/include"))
+        .warnings(false)
+        .compile("sss_idmap");
+
+    let bindings = bindgen::Builder::default()
+        .blocklist_function("qgcvt")
+        .blocklist_function("qgcvt_r")
+        .blocklist_function("qfcvt")
+        .blocklist_function("qfcvt_r")
+        .blocklist_function("qecvt")
+        .blocklist_function("qecvt_r")
+        .blocklist_function("strtold")
+        .header("src/sss_idmap.h")
+        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
+        .generate()
+        .expect("Unable to generate bindings");
+
+    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
+    bindings
+        .write_to_file(out_path.join("bindings.rs"))
+        .expect("Couldn't write bindings!");
+    println!("cargo:rustc-link-lib=utf8proc");
+}
diff --git a/himmelblaud/idmap/src/lib.rs b/himmelblaud/idmap/src/lib.rs
new file mode 100644 (file)
index 0000000..7e9e236
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+   Himmelblaud
+
+   ID-mapping library
+
+   Copyright (C) David Mulder 2024
+
+   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/>.
+*/
+use dbg::DBG_ERR;
+use std::ffi::CString;
+use std::fmt;
+use std::ptr;
+use std::sync::{Arc, Mutex};
+
+mod ffi {
+    #![allow(non_upper_case_globals)]
+    #![allow(non_camel_case_types)]
+    #![allow(non_snake_case)]
+    #![allow(dead_code)]
+    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+}
+
+#[derive(PartialEq, Eq)]
+pub struct IdmapError(u32);
+
+pub const IDMAP_SUCCESS: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_SUCCESS);
+pub const IDMAP_NOT_IMPLEMENTED: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_NOT_IMPLEMENTED);
+pub const IDMAP_ERROR: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_ERROR);
+pub const IDMAP_OUT_OF_MEMORY: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_OUT_OF_MEMORY);
+pub const IDMAP_NO_DOMAIN: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_NO_DOMAIN);
+pub const IDMAP_CONTEXT_INVALID: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_CONTEXT_INVALID);
+pub const IDMAP_SID_INVALID: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_SID_INVALID);
+pub const IDMAP_SID_UNKNOWN: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_SID_UNKNOWN);
+pub const IDMAP_NO_RANGE: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_NO_RANGE);
+pub const IDMAP_BUILTIN_SID: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_BUILTIN_SID);
+pub const IDMAP_OUT_OF_SLICES: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_OUT_OF_SLICES);
+pub const IDMAP_COLLISION: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_COLLISION);
+pub const IDMAP_EXTERNAL: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_EXTERNAL);
+pub const IDMAP_NAME_UNKNOWN: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_NAME_UNKNOWN);
+pub const IDMAP_NO_REVERSE: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_NO_REVERSE);
+pub const IDMAP_ERR_LAST: IdmapError =
+    IdmapError(ffi::idmap_error_code_IDMAP_ERR_LAST);
+
+impl fmt::Display for IdmapError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "IdmapError({:#x})", self.0)
+    }
+}
+
+impl fmt::Debug for IdmapError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "IdmapError({:#x})", self.0)
+    }
+}
+
+impl std::error::Error for IdmapError {}
+
+pub struct Idmap {
+    ctx: Arc<Mutex<*mut ffi::sss_idmap_ctx>>,
+}
+
+impl Idmap {
+    pub fn new() -> Result<Idmap, IdmapError> {
+        let mut ctx = ptr::null_mut();
+        unsafe {
+            match IdmapError(ffi::sss_idmap_init(
+                None,
+                ptr::null_mut(),
+                None,
+                &mut ctx,
+            )) {
+                IDMAP_SUCCESS => Ok(Idmap {
+                    ctx: Arc::new(Mutex::new(ctx)),
+                }),
+                e => Err(e),
+            }
+        }
+    }
+
+    pub fn add_gen_domain(
+        &mut self,
+        domain_name: &str,
+        tenant_id: &str,
+        range: (u32, u32),
+    ) -> Result<(), IdmapError> {
+        let ctx = self.ctx.lock().map_err(|e| {
+            DBG_ERR!("Failed obtaining write lock on sss_idmap_ctx: {}", e);
+            IDMAP_ERROR
+        })?;
+        let domain_name_cstr =
+            CString::new(domain_name).map_err(|_| IDMAP_OUT_OF_MEMORY)?;
+        let tenant_id_cstr =
+            CString::new(tenant_id).map_err(|_| IDMAP_OUT_OF_MEMORY)?;
+        let mut idmap_range = ffi::sss_idmap_range {
+            min: range.0,
+            max: range.1,
+        };
+        unsafe {
+            match IdmapError(ffi::sss_idmap_add_gen_domain_ex(
+                *ctx,
+                domain_name_cstr.as_ptr(),
+                tenant_id_cstr.as_ptr(),
+                &mut idmap_range,
+                ptr::null_mut(),
+                None,
+                None,
+                ptr::null_mut(),
+                0,
+                false,
+            )) {
+                IDMAP_SUCCESS => Ok(()),
+                e => Err(e),
+            }
+        }
+    }
+
+    pub fn gen_to_unix(
+        &self,
+        tenant_id: &str,
+        input: &str,
+    ) -> Result<u32, IdmapError> {
+        let ctx = self.ctx.lock().map_err(|e| {
+            DBG_ERR!("Failed obtaining write lock on sss_idmap_ctx: {}", e);
+            IDMAP_ERROR
+        })?;
+        let tenant_id_cstr =
+            CString::new(tenant_id).map_err(|_| IDMAP_OUT_OF_MEMORY)?;
+        let input_cstr = CString::new(input.to_lowercase())
+            .map_err(|_| IDMAP_OUT_OF_MEMORY)?;
+        unsafe {
+            let mut id: u32 = 0;
+            match IdmapError(ffi::sss_idmap_gen_to_unix(
+                *ctx,
+                tenant_id_cstr.as_ptr(),
+                input_cstr.as_ptr(),
+                &mut id,
+            )) {
+                IDMAP_SUCCESS => Ok(id),
+                e => Err(e),
+            }
+        }
+    }
+}
+
+impl Drop for Idmap {
+    fn drop(&mut self) {
+        match self.ctx.lock() {
+            Ok(ctx) => unsafe {
+                let _ = ffi::sss_idmap_free(*ctx);
+            },
+            Err(e) => {
+                DBG_ERR!(
+                    "Failed obtaining write lock on sss_idmap_ctx during drop: {}",
+                    e
+                );
+            }
+        }
+    }
+}
+
+unsafe impl Send for Idmap {}
+unsafe impl Sync for Idmap {}
+
+#[cfg(test)]
+mod tests {
+    use crate::Idmap;
+    use std::collections::HashMap;
+    pub const DEFAULT_IDMAP_RANGE: (u32, u32) = (200000, 2000200000);
+
+    #[test]
+    fn sssd_idmapping() {
+        let domain = "contoso.onmicrosoft.com";
+        let tenant_id = "d7af6c1b-0497-40fe-9d17-07e6b0f8332e";
+        let mut idmap = Idmap::new().expect("Idmap initialization failed");
+
+        idmap
+            .add_gen_domain(domain, tenant_id, DEFAULT_IDMAP_RANGE)
+            .expect("Failed initializing test domain idmapping");
+
+        // Verify we always get the same mapping for various users
+        let mut usermap: HashMap<String, u32> = HashMap::new();
+        usermap.insert("tux@contoso.onmicrosoft.com".to_string(), 1912749799);
+        usermap.insert("admin@contoso.onmicrosoft.com".to_string(), 297515919);
+        usermap.insert("dave@contoso.onmicrosoft.com".to_string(), 132631922);
+        usermap.insert("joe@contoso.onmicrosoft.com".to_string(), 361591965);
+        usermap.insert("georg@contoso.onmicrosoft.com".to_string(), 866887005);
+
+        for (username, expected_uid) in &usermap {
+            let uid = idmap.gen_to_unix(tenant_id, username).expect(&format!(
+                "Failed converting username {} to uid",
+                username
+            ));
+            assert_eq!(
+                uid, *expected_uid,
+                "Uid for {} did not match",
+                username
+            );
+        }
+    }
+}
diff --git a/himmelblaud/idmap/src/murmurhash3.c b/himmelblaud/idmap/src/murmurhash3.c
new file mode 100644 (file)
index 0000000..f0ccd92
--- /dev/null
@@ -0,0 +1,114 @@
+/* This file is based on the public domain MurmurHash3 from Austin Appleby:
+ * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
+ *
+ * We use only the 32 bit variant because the 2 produce different result while
+ * we need to produce the same result regardless of the architecture as
+ * clients can be both 64 or 32 bit at the same time.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "config.h"
+#include "murmurhash3.h"
+#include "util.h"
+
+static uint32_t rotl(uint32_t x, int8_t r)
+{
+    return (x << r) | (x >> (32 - r));
+}
+
+/* slower than original but is endian neutral and handles platforms that
+ * do only aligned reads */
+__attribute__((always_inline))
+static inline uint32_t getblock(const uint8_t *p, int i)
+{
+    uint32_t r;
+    size_t size = sizeof(uint32_t);
+
+    memcpy(&r, &p[i * size], size);
+
+    return le32toh(r);
+}
+
+/*
+ * Finalization mix - force all bits of a hash block to avalanche
+ */
+
+__attribute__((always_inline))
+static inline uint32_t fmix(uint32_t h)
+{
+    h ^= h >> 16;
+    h *= 0x85ebca6b;
+    h ^= h >> 13;
+    h *= 0xc2b2ae35;
+    h ^= h >> 16;
+
+    return h;
+}
+
+
+uint32_t murmurhash3(const char *key, int len, uint32_t seed)
+{
+    const uint8_t *blocks;
+    const uint8_t *tail;
+    int nblocks;
+    uint32_t h1;
+    uint32_t k1;
+    uint32_t c1;
+    uint32_t c2;
+    int i;
+
+    blocks = (const uint8_t *)key;
+    nblocks = len / 4;
+    h1 = seed;
+    c1 = 0xcc9e2d51;
+    c2 = 0x1b873593;
+
+    /* body */
+
+    for (i = 0; i < nblocks; i++) {
+
+        k1 = getblock(blocks, i);
+
+        k1 *= c1;
+        k1 = rotl(k1, 15);
+        k1 *= c2;
+
+        h1 ^= k1;
+        h1 = rotl(h1, 13);
+        h1 = h1 * 5 + 0xe6546b64;
+    }
+
+    /* tail */
+
+    tail = (const uint8_t *)key + nblocks * 4;
+
+    k1 = 0;
+
+    switch (len & 3) {
+    case 3:
+        k1 ^= tail[2] << 16;
+        SSS_ATTRIBUTE_FALLTHROUGH;
+    case 2:
+        k1 ^= tail[1] << 8;
+        SSS_ATTRIBUTE_FALLTHROUGH;
+    case 1:
+        k1 ^= tail[0];
+        k1 *= c1;
+        k1 = rotl(k1, 15);
+        k1 *= c2;
+        h1 ^= k1;
+        break;
+    default:
+        break;
+    }
+
+    /* finalization */
+
+    h1 ^= len;
+    h1 = fmix(h1);
+
+    return h1;
+}
diff --git a/himmelblaud/idmap/src/murmurhash3.h b/himmelblaud/idmap/src/murmurhash3.h
new file mode 100644 (file)
index 0000000..2767183
--- /dev/null
@@ -0,0 +1,21 @@
+/* This file is based on the public domain MurmurHash3 from Austin Appleby:
+ * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
+ *
+ * We use only the 32 bit variant because the 2 produce different result while
+ * we need to produce the same result regardless of the architecture as
+ * clients can be both 64 or 32 bit at the same time.
+ */
+
+#ifndef _SHARED_MURMURHASH3_H_
+#define _SHARED_MURMURHASH3_H_
+
+/* CAUTION:
+ * This file is also used in sss_client (pam, nss). Therefore it have to be
+ * minimalist and cannot include DEBUG macros or header file util.h.
+ */
+
+#include <stdint.h>
+
+uint32_t murmurhash3(const char *key, int len, uint32_t seed);
+
+#endif /* _SHARED_MURMURHASH3_H_ */
diff --git a/himmelblaud/idmap/src/sss_idmap.c b/himmelblaud/idmap/src/sss_idmap.c
new file mode 100644 (file)
index 0000000..4da1d0d
--- /dev/null
@@ -0,0 +1,1909 @@
+/*
+    SSSD
+
+    ID-mapping library
+
+    Authors:
+        Sumit Bose <sbose@redhat.com>
+
+    Copyright (C) 2012 Red Hat
+
+    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 <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <utf8proc.h>
+
+#include "sss_idmap.h"
+#include "sss_idmap_private.h"
+#include "murmurhash3.h"
+
+#define SID_FMT "%s-%"PRIu32
+#define SID_STR_MAX_LEN 1024
+
+/* Hold all parameters for unix<->sid mapping relevant for
+ * given slice. */
+struct idmap_range_params {
+    uint32_t min_id;
+    uint32_t max_id;
+    char *range_id;
+
+    uint32_t first_rid;
+    struct idmap_range_params *next;
+};
+
+struct idmap_domain_info {
+    char *name;
+    char *sid;
+    struct idmap_range_params range_params;
+    struct idmap_domain_info *next;
+    bool external_mapping;
+
+    struct idmap_range_params *helpers;
+    bool auto_add_ranges;
+    bool helpers_owner;
+
+    idmap_offset_func *offset_func;
+    idmap_rev_offset_func *rev_offset_func;
+    void *offset_func_pvt;
+
+    idmap_store_cb cb;
+    void *pvt;
+};
+
+static void *default_alloc(size_t size, void *pvt)
+{
+    return malloc(size);
+}
+
+static void default_free(void *ptr, void *pvt)
+{
+    free(ptr);
+}
+
+static char *idmap_strdup(struct sss_idmap_ctx *ctx, const char *str)
+{
+    char *new = NULL;
+    size_t len;
+
+    CHECK_IDMAP_CTX(ctx, NULL);
+
+    len = strlen(str) + 1;
+
+    new = ctx->alloc_func(len, ctx->alloc_pvt);
+    if (new == NULL) {
+        return NULL;
+    }
+
+    memcpy(new, str, len);
+
+    return new;
+}
+
+static bool ranges_eq(const struct idmap_range_params *a,
+                      const struct idmap_range_params *b)
+{
+    if (a == NULL || b == NULL) {
+        return false;
+    }
+
+    if (a->first_rid == b->first_rid
+            && a->min_id == b->min_id
+            && a->max_id == b->max_id) {
+        return true;
+    }
+
+    return false;
+}
+
+static enum idmap_error_code
+construct_range(struct sss_idmap_ctx *ctx,
+                const struct idmap_range_params *src,
+                char *id,
+                struct idmap_range_params **_dst)
+{
+    struct idmap_range_params *dst;
+
+    if (src == NULL || id == NULL || _dst == NULL) {
+        return IDMAP_ERROR;
+    }
+
+    dst = ctx->alloc_func(sizeof(struct idmap_range_params), ctx->alloc_pvt);
+    if (dst == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+
+    dst->min_id = src->min_id;
+    dst->max_id = src->max_id;
+    dst->first_rid = src->first_rid;
+    dst->next = NULL;
+    dst->range_id = id;
+
+    *_dst = dst;
+    return IDMAP_SUCCESS;
+}
+
+static bool id_is_in_range(uint32_t id,
+                           struct idmap_range_params *rp,
+                           uint32_t *rid)
+{
+    if (id == 0 || rp == NULL) {
+        return false;
+    }
+
+    if (id >= rp->min_id && id <= rp->max_id) {
+        if (rid != NULL) {
+            *rid = rp->first_rid + (id - rp->min_id);
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+const char *idmap_error_string(enum idmap_error_code err)
+{
+    switch (err) {
+        case IDMAP_SUCCESS:
+            return "IDMAP operation successful";
+            break;
+        case IDMAP_NOT_IMPLEMENTED:
+            return "IDMAP Function is not yet implemented";
+            break;
+        case IDMAP_ERROR:
+            return "IDMAP general error";
+            break;
+        case IDMAP_OUT_OF_MEMORY:
+            return "IDMAP operation ran out of memory";
+            break;
+        case IDMAP_NO_DOMAIN:
+            return "IDMAP domain not found";
+            break;
+        case IDMAP_CONTEXT_INVALID:
+            return "IDMAP context is invalid";
+            break;
+        case IDMAP_SID_INVALID:
+            return "IDMAP SID is invalid";
+            break;
+        case IDMAP_SID_UNKNOWN:
+            return "IDMAP SID not found";
+            break;
+        case IDMAP_NO_RANGE:
+            return "IDMAP range not found";
+            break;
+        case IDMAP_BUILTIN_SID:
+            return "IDMAP SID from BUILTIN domain";
+            break;
+        case IDMAP_OUT_OF_SLICES:
+            return "IDMAP not more free slices";
+            break;
+        case IDMAP_COLLISION:
+            return "IDMAP new range collides with existing one";
+            break;
+        case IDMAP_EXTERNAL:
+            return "IDMAP ID managed externally";
+            break;
+        case IDMAP_NAME_UNKNOWN:
+            return "IDMAP domain with the given name not found";
+            break;
+        case IDMAP_NO_REVERSE:
+            return "IDMAP cannot revert id to original source";
+            break;
+        case IDMAP_UTF8_ERROR:
+            return "IDMAP failed to modify UTF8 string";
+            break;
+        default:
+            return "IDMAP unknown error code";
+    }
+}
+
+bool is_domain_sid(const char *sid)
+{
+    const char *p;
+    long long a;
+    char *endptr;
+    size_t c;
+
+    if (sid == NULL || strncmp(sid, DOM_SID_PREFIX, DOM_SID_PREFIX_LEN) != 0) {
+        return false;
+    }
+
+    p = sid + DOM_SID_PREFIX_LEN;
+    c = 0;
+
+    do {
+        errno = 0;
+        a = strtoull(p, &endptr, 10);
+        if (errno != 0 || a > UINT32_MAX) {
+            return false;
+        }
+
+        if (*endptr == '-') {
+            p = endptr + 1;
+        } else if (*endptr != '\0') {
+            return false;
+        }
+        c++;
+    } while(c < 3 && *endptr != '\0');
+
+    if (c != 3 || *endptr != '\0') {
+        return false;
+    }
+
+    return true;
+}
+
+enum idmap_error_code sss_idmap_init(idmap_alloc_func *alloc_func,
+                                     void *alloc_pvt,
+                                     idmap_free_func *free_func,
+                                     struct sss_idmap_ctx **_ctx)
+{
+    struct sss_idmap_ctx *ctx;
+
+    if (alloc_func == NULL) {
+        alloc_func = default_alloc;
+    }
+
+    ctx = alloc_func(sizeof(struct sss_idmap_ctx), alloc_pvt);
+    if (ctx == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+    memset(ctx, 0, sizeof(struct sss_idmap_ctx));
+
+    ctx->alloc_func = alloc_func;
+    ctx->alloc_pvt = alloc_pvt;
+    ctx->free_func = (free_func == NULL) ? default_free : free_func;
+
+    /* Set default values. */
+    ctx->idmap_opts.autorid_mode = SSS_IDMAP_DEFAULT_AUTORID;
+    ctx->idmap_opts.idmap_lower = SSS_IDMAP_DEFAULT_LOWER;
+    ctx->idmap_opts.idmap_upper = SSS_IDMAP_DEFAULT_UPPER;
+    ctx->idmap_opts.rangesize = SSS_IDMAP_DEFAULT_RANGESIZE;
+    ctx->idmap_opts.extra_slice_init = SSS_IDMAP_DEFAULT_EXTRA_SLICE_INIT;
+
+    *_ctx = ctx;
+
+    return IDMAP_SUCCESS;
+}
+
+static void free_helpers(struct sss_idmap_ctx *ctx,
+                         struct idmap_range_params *helpers,
+                         bool helpers_owner)
+{
+    struct idmap_range_params *it = helpers;
+    struct idmap_range_params *tmp;
+
+    if (helpers_owner == false) {
+        return;
+    }
+
+    while (it != NULL) {
+        tmp = it->next;
+
+        ctx->free_func(it->range_id, ctx->alloc_pvt);
+        ctx->free_func(it, ctx->alloc_pvt);
+
+        it = tmp;
+    }
+}
+
+static struct idmap_range_params*
+get_helper_by_id(struct idmap_range_params *helpers, const char *id)
+{
+    struct idmap_range_params *it;
+
+    for (it = helpers; it != NULL; it = it->next) {
+        if (strcmp(it->range_id, id) == 0) {
+            return it;
+        }
+    }
+
+    return NULL;
+}
+
+static void sss_idmap_free_domain(struct sss_idmap_ctx *ctx,
+                                  struct idmap_domain_info *dom)
+{
+    if (ctx == NULL || dom == NULL) {
+        return;
+    }
+
+    ctx->free_func(dom->range_params.range_id, ctx->alloc_pvt);
+
+    free_helpers(ctx, dom->helpers, dom->helpers_owner);
+
+    ctx->free_func(dom->name, ctx->alloc_pvt);
+    ctx->free_func(dom->sid, ctx->alloc_pvt);
+    ctx->free_func(dom, ctx->alloc_pvt);
+}
+
+enum idmap_error_code sss_idmap_free(struct sss_idmap_ctx *ctx)
+{
+    struct idmap_domain_info *dom;
+    struct idmap_domain_info *next;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    next = ctx->idmap_domain_info;
+    while (next) {
+        dom = next;
+        next = dom->next;
+        sss_idmap_free_domain(ctx, dom);
+    }
+
+    ctx->free_func(ctx, ctx->alloc_pvt);
+
+    return IDMAP_SUCCESS;
+}
+
+static enum idmap_error_code sss_idmap_free_ptr(struct sss_idmap_ctx *ctx,
+                                                void *ptr)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (ptr != NULL) {
+        ctx->free_func(ptr, ctx->alloc_pvt);
+    }
+
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code sss_idmap_free_sid(struct sss_idmap_ctx *ctx,
+                                         char *sid)
+{
+    return sss_idmap_free_ptr(ctx, sid);
+}
+
+enum idmap_error_code sss_idmap_free_dom_sid(struct sss_idmap_ctx *ctx,
+                                             struct sss_dom_sid *dom_sid)
+{
+    return sss_idmap_free_ptr(ctx, dom_sid);
+}
+
+enum idmap_error_code sss_idmap_free_smb_sid(struct sss_idmap_ctx *ctx,
+                                             struct dom_sid *smb_sid)
+{
+    return sss_idmap_free_ptr(ctx, smb_sid);
+}
+
+enum idmap_error_code sss_idmap_free_bin_sid(struct sss_idmap_ctx *ctx,
+                                             uint8_t *bin_sid)
+{
+    return sss_idmap_free_ptr(ctx, bin_sid);
+}
+
+static bool check_overlap(struct idmap_range_params *range,
+                          id_t min, id_t max)
+{
+    return ((range->min_id <= min && range->max_id >= max)
+                || (range->min_id >= min && range->min_id <= max)
+                || (range->max_id >= min && range->max_id <= max));
+}
+
+static bool check_dom_overlap(struct idmap_range_params *prim_range,
+                              /* struct idmap_range_params *sec_ranges, */
+                              id_t min,
+                              id_t max)
+{
+    return check_overlap(prim_range, min, max);
+}
+
+enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
+                                                const char *range_id,
+                                                id_t *slice_num,
+                                                struct sss_idmap_range *_range)
+{
+    id_t max_slices;
+    id_t orig_slice;
+    id_t new_slice = 0;
+    id_t min;
+    id_t max;
+    id_t idmap_lower;
+    id_t idmap_upper;
+    id_t rangesize;
+    bool autorid_mode;
+    uint32_t hash_val;
+    struct idmap_domain_info *dom;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    idmap_lower = ctx->idmap_opts.idmap_lower;
+    idmap_upper = ctx->idmap_opts.idmap_upper;
+    rangesize = ctx->idmap_opts.rangesize;
+    autorid_mode = ctx->idmap_opts.autorid_mode;
+
+    max_slices = (idmap_upper - idmap_lower) / rangesize;
+
+    if (slice_num && *slice_num != -1) {
+        /* The slice is being set explicitly.
+         * This may happen at system startup when we're loading
+         * previously-determined slices. In the future, we may also
+         * permit configuration to select the slice for a domain
+         * explicitly.
+         */
+        new_slice = *slice_num;
+        min = (rangesize * new_slice) + idmap_lower;
+        max = min + rangesize - 1;
+        for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
+                if (check_dom_overlap(&dom->range_params,min, max)) {
+                    /* This range overlaps one already registered
+                     * Fail, because the slice was manually configured
+                     */
+                    return IDMAP_COLLISION;
+                }
+        }
+    } else {
+        /* If slice is -1, we're being asked to pick a new slice */
+
+        if (autorid_mode) {
+            /* In autorid compatibility mode, always start at 0 and find the
+             * first free value.
+             */
+            orig_slice = 0;
+        } else {
+            /* Hash the range identifier string */
+            hash_val = murmurhash3(range_id, strlen(range_id), 0xdeadbeef);
+
+            /* Now get take the modulus of the hash val and the max_slices
+             * to determine its optimal position in the range.
+             */
+            new_slice = hash_val % max_slices;
+            orig_slice = new_slice;
+        }
+
+        min = (rangesize * new_slice) + idmap_lower;
+        max = min + rangesize - 1;
+        /* Verify that this slice is not already in use */
+        do {
+            for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
+
+                if (check_dom_overlap(&dom->range_params,
+                                      min, max)) {
+                    /* This range overlaps one already registered
+                     * We'll try the next available slot
+                     */
+                    new_slice++;
+                    if (new_slice >= max_slices) {
+                        /* loop around to the beginning if necessary */
+                        new_slice = 0;
+                    }
+
+                    min = (rangesize * new_slice) + idmap_lower;
+                    max = min + rangesize - 1;
+                    break;
+                }
+            }
+
+            /* Keep trying until dom is NULL (meaning we got to the end
+             * without matching) or we have run out of slices and gotten
+             * back to the first one we tried.
+             */
+        } while (dom && new_slice != orig_slice);
+
+        if (dom) {
+            /* We looped all the way through and found no empty slots */
+            return IDMAP_OUT_OF_SLICES;
+        }
+    }
+
+    _range->min = (rangesize * new_slice) + idmap_lower;
+    _range->max = _range->min + rangesize - 1;
+
+    if (slice_num) {
+        *slice_num = new_slice;
+    }
+
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code sss_idmap_check_collision_ex(const char *o_name,
+                                                const char *o_sid,
+                                                struct sss_idmap_range *o_range,
+                                                uint32_t o_first_rid,
+                                                const char *o_range_id,
+                                                bool o_external_mapping,
+                                                const char *n_name,
+                                                const char *n_sid,
+                                                struct sss_idmap_range *n_range,
+                                                uint32_t n_first_rid,
+                                                const char *n_range_id,
+                                                bool n_external_mapping)
+{
+    bool names_equal;
+    bool sids_equal;
+
+    /* TODO: if both ranges have the same ID check if an update is
+     * needed. */
+
+    /* Check if ID ranges overlap.
+     * ID ranges with external mapping may overlap. */
+    if ((!n_external_mapping && !o_external_mapping)
+        && ((n_range->min >= o_range->min
+                && n_range->min <= o_range->max)
+            || (n_range->max >= o_range->min
+                && n_range->max <= o_range->max))) {
+        return IDMAP_COLLISION;
+    }
+
+    names_equal = (strcasecmp(n_name, o_name) == 0);
+    sids_equal = ((n_sid == NULL && o_sid == NULL)
+                    || (n_sid != NULL && o_sid != NULL
+                        && strcasecmp(n_sid, o_sid) == 0));
+
+    /* check if domain name and SID are consistent */
+    if ((names_equal && !sids_equal) || (!names_equal && sids_equal)) {
+        return IDMAP_COLLISION;
+    }
+
+    /* check if external_mapping is consistent */
+    if (names_equal && sids_equal
+            && n_external_mapping != o_external_mapping) {
+        return IDMAP_COLLISION;
+    }
+
+    /* check if RID ranges overlap */
+    if (names_equal && sids_equal
+            && n_external_mapping == false
+            && n_first_rid >= o_first_rid
+            && n_first_rid <= o_first_rid + (o_range->max - o_range->min)) {
+        return IDMAP_COLLISION;
+    }
+
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code sss_idmap_check_collision(struct sss_idmap_ctx *ctx,
+                                                char *n_name, char *n_sid,
+                                                struct sss_idmap_range *n_range,
+                                                uint32_t n_first_rid,
+                                                char *n_range_id,
+                                                bool n_external_mapping)
+{
+    struct idmap_domain_info *dom;
+    enum idmap_error_code err;
+    struct sss_idmap_range range;
+
+    for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
+
+        range.min = dom->range_params.min_id;
+        range.max = dom->range_params.max_id;
+
+        err = sss_idmap_check_collision_ex(dom->name, dom->sid,
+                                           &range,
+                                           dom->range_params.first_rid,
+                                           dom->range_params.range_id,
+                                           dom->external_mapping,
+                                           n_name, n_sid, n_range, n_first_rid,
+                                           n_range_id, n_external_mapping);
+        if (err != IDMAP_SUCCESS) {
+            return err;
+        }
+    }
+    return IDMAP_SUCCESS;
+}
+
+static enum
+idmap_error_code dom_check_collision(struct idmap_domain_info *dom_list,
+                                     struct idmap_domain_info *new_dom)
+{
+    struct idmap_domain_info *dom;
+    enum idmap_error_code err;
+    struct sss_idmap_range range;
+    struct sss_idmap_range new_dom_range = { new_dom->range_params.min_id,
+                                             new_dom->range_params.max_id };
+
+    for (dom = dom_list; dom != NULL; dom = dom->next) {
+        range.min = dom->range_params.min_id;
+        range.max = dom->range_params.max_id;
+
+        err = sss_idmap_check_collision_ex(dom->name, dom->sid,
+                                           &range,
+                                           dom->range_params.first_rid,
+                                           dom->range_params.range_id,
+                                           dom->external_mapping,
+                                           new_dom->name, new_dom->sid,
+                                           &new_dom_range,
+                                           new_dom->range_params.first_rid,
+                                           new_dom->range_params.range_id,
+                                           new_dom->external_mapping);
+        if (err != IDMAP_SUCCESS) {
+            return err;
+        }
+    }
+    return IDMAP_SUCCESS;
+}
+
+static char*
+generate_sec_slice_name(struct sss_idmap_ctx *ctx,
+                        const char *domain_sid, uint32_t rid)
+{
+    const char *SEC_SLICE_NAME_FMT = "%s-%"PRIu32;
+    char *slice_name;
+    int len, len2;
+
+    len = snprintf(NULL, 0, SEC_SLICE_NAME_FMT, domain_sid, rid);
+    if (len <= 0) {
+        return NULL;
+    }
+
+    slice_name = ctx->alloc_func(len + 1, ctx->alloc_pvt);
+    if (slice_name == NULL) {
+        return NULL;
+    }
+
+    len2 = snprintf(slice_name, len + 1, SEC_SLICE_NAME_FMT, domain_sid,
+                    rid);
+    if (len != len2) {
+        ctx->free_func(slice_name, ctx->alloc_pvt);
+        return NULL;
+    }
+
+    return slice_name;
+}
+
+static enum idmap_error_code
+generate_slice(struct sss_idmap_ctx *ctx, char *slice_name, uint32_t first_rid,
+               struct idmap_range_params **_slice)
+{
+    struct idmap_range_params *slice;
+    struct sss_idmap_range tmp_range;
+    enum idmap_error_code err;
+
+    slice = ctx->alloc_func(sizeof(struct idmap_range_params), ctx->alloc_pvt);
+    if (slice == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+
+    slice->next = NULL;
+
+    err = sss_idmap_calculate_range(ctx, slice_name, NULL, &tmp_range);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(slice, ctx->alloc_pvt);
+        return err;
+    }
+
+    slice->min_id = tmp_range.min;
+    slice->max_id = tmp_range.max;
+    slice->range_id = slice_name;
+    slice->first_rid = first_rid;
+
+    *_slice = slice;
+    return IDMAP_SUCCESS;
+}
+
+static enum idmap_error_code
+get_helpers(struct sss_idmap_ctx *ctx,
+            const char *domain_sid,
+            uint32_t first_rid,
+            struct idmap_range_params **_sec_slices)
+{
+    struct idmap_range_params *prev = NULL;
+    struct idmap_range_params *sec_slices = NULL;
+    static enum idmap_error_code err;
+    struct idmap_range_params *slice;
+    char *secondary_name;
+
+    for (int i = 0; i < ctx->idmap_opts.extra_slice_init; i++) {
+        secondary_name = generate_sec_slice_name(ctx, domain_sid, first_rid);
+        if (secondary_name == NULL) {
+            err = IDMAP_OUT_OF_MEMORY;
+            goto fail;
+        }
+
+        err = generate_slice(ctx, secondary_name, first_rid, &slice);
+        if (err != IDMAP_SUCCESS) {
+            goto fail;
+        }
+
+        first_rid += ctx->idmap_opts.rangesize;
+
+        if (prev != NULL) {
+            prev->next = slice;
+        }
+
+        if (sec_slices == NULL) {
+            sec_slices = slice;
+        }
+
+        prev = slice;
+    }
+
+    *_sec_slices = sec_slices;
+    return IDMAP_SUCCESS;
+
+fail:
+    ctx->free_func(secondary_name, ctx->alloc_pvt);
+
+    /* Free already generated helpers. */
+    free_helpers(ctx, sec_slices, true);
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_add_gen_domain_ex(struct sss_idmap_ctx *ctx,
+                                                  const char *domain_name,
+                                                  const char *domain_id,
+                                                  struct sss_idmap_range *range,
+                                                  const char *range_id,
+                                                  idmap_offset_func *offset_func,
+                                                  idmap_rev_offset_func *rev_offset_func,
+                                                  void *offset_func_pvt,
+                                                  uint32_t shift,
+                                                  bool external_mapping)
+{
+    struct idmap_domain_info *dom = NULL;
+    enum idmap_error_code err;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (domain_name == NULL || domain_id == NULL) {
+        return IDMAP_NO_DOMAIN;
+    }
+
+    if (range == NULL) {
+        return IDMAP_NO_RANGE;
+    }
+
+    dom = ctx->alloc_func(sizeof(struct idmap_domain_info), ctx->alloc_pvt);
+    if (dom == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+    memset(dom, 0, sizeof(struct idmap_domain_info));
+
+    dom->name = idmap_strdup(ctx, domain_name);
+    if (dom->name == NULL) {
+        err = IDMAP_OUT_OF_MEMORY;
+        goto fail;
+    }
+
+    dom->sid = idmap_strdup(ctx, domain_id);
+    if (dom->sid == NULL) {
+        err = IDMAP_OUT_OF_MEMORY;
+        goto fail;
+    }
+
+    dom->range_params.min_id = range->min;
+    dom->range_params.max_id = range->max;
+
+    if (range_id != NULL) {
+        dom->range_params.range_id = idmap_strdup(ctx, range_id);
+        if (dom->range_params.range_id == NULL) {
+            err = IDMAP_OUT_OF_MEMORY;
+            goto fail;
+        }
+    }
+
+    dom->range_params.first_rid = shift;
+    dom->external_mapping = external_mapping;
+
+    dom->offset_func = offset_func;
+    dom->rev_offset_func = rev_offset_func;
+    dom->offset_func_pvt = offset_func_pvt;
+
+    err = dom_check_collision(ctx->idmap_domain_info, dom);
+    if (err != IDMAP_SUCCESS) {
+        goto fail;
+    }
+
+    dom->next = ctx->idmap_domain_info;
+    ctx->idmap_domain_info = dom;
+
+    return IDMAP_SUCCESS;
+
+fail:
+    sss_idmap_free_domain(ctx, dom);
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
+                                              const char *domain_name,
+                                              const char *domain_sid,
+                                              struct sss_idmap_range *range,
+                                              const char *range_id,
+                                              uint32_t rid,
+                                              bool external_mapping)
+{
+    struct idmap_domain_info *dom = NULL;
+    enum idmap_error_code err;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (domain_name == NULL) {
+        return IDMAP_NO_DOMAIN;
+    }
+
+    if (range == NULL) {
+        return IDMAP_NO_RANGE;
+    }
+
+    /* For algorithmic mapping a valid domain SID is required, for external
+     * mapping it may be NULL, but if set it should be valid. */
+    if ((!external_mapping && !is_domain_sid(domain_sid))
+            || (external_mapping
+                && domain_sid != NULL
+                && !is_domain_sid(domain_sid))) {
+        return IDMAP_SID_INVALID;
+    }
+
+    dom = ctx->alloc_func(sizeof(struct idmap_domain_info), ctx->alloc_pvt);
+    if (dom == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+    memset(dom, 0, sizeof(struct idmap_domain_info));
+
+    dom->name = idmap_strdup(ctx, domain_name);
+    if (dom->name == NULL) {
+        err = IDMAP_OUT_OF_MEMORY;
+        goto fail;
+    }
+
+    if (domain_sid != NULL) {
+        dom->sid = idmap_strdup(ctx, domain_sid);
+        if (dom->sid == NULL) {
+            err = IDMAP_OUT_OF_MEMORY;
+            goto fail;
+        }
+    }
+
+    dom->range_params.min_id = range->min;
+    dom->range_params.max_id = range->max;
+
+    if (range_id != NULL) {
+        dom->range_params.range_id = idmap_strdup(ctx, range_id);
+        if (dom->range_params.range_id == NULL) {
+            err = IDMAP_OUT_OF_MEMORY;
+            goto fail;
+        }
+    }
+
+    dom->range_params.first_rid = rid;
+    dom->external_mapping = external_mapping;
+
+    err = dom_check_collision(ctx->idmap_domain_info, dom);
+    if (err != IDMAP_SUCCESS) {
+        goto fail;
+    }
+
+    dom->next = ctx->idmap_domain_info;
+    ctx->idmap_domain_info = dom;
+
+    return IDMAP_SUCCESS;
+
+fail:
+    sss_idmap_free_domain(ctx, dom);
+
+    return err;
+}
+
+enum idmap_error_code
+sss_idmap_add_auto_domain_ex(struct sss_idmap_ctx *ctx,
+                             const char *domain_name,
+                             const char *domain_sid,
+                             struct sss_idmap_range *range,
+                             const char *range_id,
+                             uint32_t rid,
+                             bool external_mapping,
+                             idmap_store_cb cb,
+                             void *pvt)
+{
+    enum idmap_error_code err;
+
+    err = sss_idmap_add_domain_ex(ctx, domain_name, domain_sid, range,
+                                  range_id, rid, external_mapping);
+    if (err != IDMAP_SUCCESS) {
+        return err;
+    }
+
+    if (external_mapping) {
+        /* There's no point in generating secondary ranges if external_mapping
+           is enabled. */
+        ctx->idmap_domain_info->auto_add_ranges = false;
+        return IDMAP_SUCCESS;
+    }
+
+    if ((range->max - range->min + 1) != ctx->idmap_opts.rangesize) {
+        /* Range of primary slice is not equal to the value of
+           ldap_idmap_range_size option. */
+        return IDMAP_ERROR;
+    }
+
+    /* No additional secondary ranges should be added if no sec ranges are
+       predeclared. */
+    if (ctx->idmap_opts.extra_slice_init == 0) {
+        ctx->idmap_domain_info->auto_add_ranges = false;
+        return IDMAP_SUCCESS;
+    }
+
+    /* Add size of primary slice for first_rid of secondary slices. */
+    rid += ctx->idmap_opts.rangesize;
+    err = get_helpers(ctx, domain_sid, rid,
+                      &ctx->idmap_domain_info->helpers);
+    if (err == IDMAP_SUCCESS) {
+        ctx->idmap_domain_info->auto_add_ranges = true;
+        ctx->idmap_domain_info->helpers_owner = true;
+    } else {
+        /* Running out of slices for secondary mapping is a non-fatal
+         * problem. */
+        if (err == IDMAP_OUT_OF_SLICES) {
+            err = IDMAP_SUCCESS;
+        }
+        ctx->idmap_domain_info->auto_add_ranges = false;
+    }
+
+    ctx->idmap_domain_info->cb = cb;
+    ctx->idmap_domain_info->pvt = pvt;
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
+                                           const char *domain_name,
+                                           const char *domain_sid,
+                                           struct sss_idmap_range *range)
+{
+    return sss_idmap_add_domain_ex(ctx, domain_name, domain_sid, range, NULL,
+                                   0, false);
+}
+
+static bool sss_idmap_sid_is_builtin(const char *sid)
+{
+    if (strncmp(sid, "S-1-5-32-", 9) == 0) {
+        return true;
+    }
+
+    return false;
+}
+
+static bool parse_rid(const char *sid, size_t dom_prefix_len, long long *_rid)
+{
+    long long rid;
+    char *endptr;
+
+    errno = 0;
+    /* Use suffix of sid - part after domain and following '-' */
+    rid = strtoull(sid + dom_prefix_len + 1, &endptr, 10);
+    if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') {
+        return false;
+    }
+
+    *_rid = rid;
+    return true;
+}
+
+static bool is_from_dom(const char *domain_id, const char *id)
+{
+    if (domain_id == NULL) {
+        return false;
+    }
+
+    return strcmp(domain_id, id) == 0;
+}
+
+static bool is_sid_from_dom(const char *dom_sid, const char *sid,
+                            size_t *_dom_sid_len)
+{
+    size_t dom_sid_len;
+
+    if (dom_sid == NULL) {
+        return false;
+    }
+
+    dom_sid_len = strlen(dom_sid);
+    *_dom_sid_len = dom_sid_len;
+
+    if (strlen(sid) < dom_sid_len || sid[dom_sid_len] != '-') {
+        return false;
+    }
+
+    return strncmp(sid, dom_sid, dom_sid_len) == 0;
+}
+
+static bool comp_id(struct idmap_range_params *range_params, long long rid,
+                    uint32_t *_id)
+{
+    uint32_t id;
+
+    if (rid >= range_params->first_rid
+            && ((UINT32_MAX - range_params->min_id) >
+               (rid - range_params->first_rid))) {
+        id = range_params->min_id + (rid - range_params->first_rid);
+        if (id <= range_params->max_id) {
+            *_id = id;
+            return true;
+        }
+    }
+    return false;
+}
+
+static enum idmap_error_code
+get_range(struct sss_idmap_ctx *ctx,
+          struct idmap_range_params *helpers,
+          const char *dom_sid,
+          long long rid,
+          struct idmap_range_params **_range)
+{
+    char *secondary_name = NULL;
+    enum idmap_error_code err;
+    int first_rid;
+    struct idmap_range_params *range;
+    struct idmap_range_params *helper;
+
+    first_rid = (rid / ctx->idmap_opts.rangesize) * ctx->idmap_opts.rangesize;
+
+    secondary_name = generate_sec_slice_name(ctx, dom_sid, first_rid);
+    if (secondary_name == NULL) {
+        err = IDMAP_OUT_OF_MEMORY;
+        goto error;
+    }
+
+    helper = get_helper_by_id(helpers, secondary_name);
+    if (helper != NULL) {
+        /* Utilize helper's range. */
+        err = construct_range(ctx, helper, secondary_name, &range);
+    } else {
+        /* Have to generate a whole new range. */
+        err = generate_slice(ctx, secondary_name, first_rid, &range);
+    }
+
+    if (err != IDMAP_SUCCESS) {
+        goto error;
+    }
+
+    *_range = range;
+    return IDMAP_SUCCESS;
+
+error:
+    ctx->free_func(secondary_name, ctx->alloc_pvt);
+    return err;
+}
+
+static enum idmap_error_code
+spawn_dom(struct sss_idmap_ctx *ctx,
+          struct idmap_domain_info *parent,
+          struct idmap_range_params *range)
+{
+    struct sss_idmap_range tmp;
+    static enum idmap_error_code err;
+    struct idmap_domain_info *it;
+
+    tmp.min = range->min_id;
+    tmp.max = range->max_id;
+
+    err = sss_idmap_add_domain_ex(ctx,
+                                  parent->name,
+                                  parent->sid,
+                                  &tmp, range->range_id,
+                                  range->first_rid, false);
+    if (err != IDMAP_SUCCESS) {
+        return err;
+    }
+
+    it = ctx->idmap_domain_info;
+    while (it != NULL) {
+        /* Find the newly added domain. */
+        if (ranges_eq(&it->range_params, range)) {
+
+            /* Share helpers. */
+            it->helpers = parent->helpers;
+            it->auto_add_ranges = parent->auto_add_ranges;
+
+            /* Share call back for storing domains */
+            it->cb = parent->cb;
+            it->pvt = parent->pvt;
+            break;
+        }
+
+        it = it->next;
+    }
+
+    if (it == NULL) {
+        /* Failed to find just added domain. */
+        return IDMAP_ERROR;
+    }
+
+    /* Store mapping for newly created domain. */
+    if (it->cb != NULL) {
+        err = it->cb(it->name,
+                     it->sid,
+                     it->range_params.range_id,
+                     it->range_params.min_id,
+                     it->range_params.max_id,
+                     it->range_params.first_rid,
+                     it->pvt);
+        if (err != IDMAP_SUCCESS) {
+            return err;
+        }
+    }
+
+    return IDMAP_SUCCESS;
+}
+
+static enum idmap_error_code
+add_dom_for_sid(struct sss_idmap_ctx *ctx,
+                struct idmap_domain_info *matched_dom,
+                const char *sid,
+                uint32_t *_id)
+{
+    enum idmap_error_code err;
+    long long rid;
+    struct idmap_range_params *range = NULL;
+
+    if (parse_rid(sid, strlen(matched_dom->sid), &rid) == false) {
+        err = IDMAP_SID_INVALID;
+        goto done;
+    }
+
+    err = get_range(ctx, matched_dom->helpers, matched_dom->sid, rid, &range);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = spawn_dom(ctx, matched_dom, range);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    if (!comp_id(range, rid, _id)) {
+        err = IDMAP_ERROR;
+        goto done;
+    }
+
+    err =  IDMAP_SUCCESS;
+
+done:
+    if (range != NULL) {
+        ctx->free_func(range->range_id, ctx->alloc_pvt);
+    }
+    ctx->free_func(range, ctx->alloc_pvt);
+    return err;
+}
+
+enum idmap_error_code offset_identity(void *pvt, uint32_t range_size,
+                                      const char *input, long long *offset)
+{
+    long long out;
+    char *endptr;
+
+    if (input == NULL || offset == NULL) {
+        return IDMAP_ERROR;
+    }
+
+    errno = 0;
+    out = strtoull(input, &endptr, 10);
+    if (errno != 0 || out >= range_size || *endptr != '\0'
+                   || endptr == input) {
+        return IDMAP_ERROR;
+    }
+
+    *offset = out;
+
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code rev_offset_identity(struct sss_idmap_ctx *ctx, void *pvt,
+                                          uint32_t id, char **_out)
+{
+    char *out;
+    int len;
+    int ret;
+
+    len = snprintf(NULL, 0, "%"PRIu32, id);
+    if (len <= 0 || len > SID_STR_MAX_LEN) {
+        return IDMAP_ERROR;
+    }
+
+    out = ctx->alloc_func(len + 1, ctx->alloc_pvt);
+    if (out == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+
+    ret = snprintf(out, len + 1, "%"PRIu32, id);
+    if (ret != len) {
+        ctx->free_func(out, ctx->alloc_pvt);
+        return IDMAP_ERROR;
+    }
+
+    *_out = out;
+    return IDMAP_SUCCESS;
+}
+
+static char *normalize_casefold(const char *input, bool normalize,
+                                bool casefold)
+{
+    if (casefold) {
+        return (char *) utf8proc_NFKC_Casefold((const utf8proc_uint8_t *) input);
+    }
+
+    if (normalize) {
+        return (char *) utf8proc_NFKC((const utf8proc_uint8_t *) input);
+    }
+
+    return NULL;
+}
+
+struct offset_murmurhash3_data offset_murmurhash3_data_default =
+                                                          { .seed = 0xdeadbeef,
+                                                            .normalize = true,
+                                                            .casefold = false };
+
+enum idmap_error_code offset_murmurhash3(void *pvt, uint32_t range_size,
+                                         const char *input, long long *offset)
+{
+    struct offset_murmurhash3_data *offset_murmurhash3_data;
+    long long out;
+    char *tmp = NULL;
+    const char *val;
+
+    if (input == NULL || offset == NULL) {
+        return IDMAP_ERROR;
+    }
+
+    if (pvt != NULL) {
+        offset_murmurhash3_data = (struct offset_murmurhash3_data *) pvt;
+    } else {
+        offset_murmurhash3_data = &offset_murmurhash3_data_default;
+    }
+
+    if (offset_murmurhash3_data->normalize || offset_murmurhash3_data->casefold) {
+        tmp = normalize_casefold(input, offset_murmurhash3_data->normalize,
+                                 offset_murmurhash3_data->casefold);
+        if (tmp == NULL) {
+            return IDMAP_UTF8_ERROR;
+        }
+    }
+
+    val = (tmp == NULL) ? input : tmp;
+
+    out = murmurhash3(val, strlen(val), offset_murmurhash3_data->seed);
+    free(tmp);
+
+    out %= range_size;
+
+    *offset = out;
+
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code sss_idmap_gen_to_unix(struct sss_idmap_ctx *ctx,
+                                            const char *domain_id,
+                                            const char *input,
+                                            uint32_t *_id)
+{
+    struct idmap_domain_info *idmap_domain_info;
+    struct idmap_domain_info *matched_dom = NULL;
+    long long offset;
+    uint32_t range_size;
+    enum idmap_error_code err;
+    idmap_offset_func *offset_func = offset_murmurhash3;
+    void *offset_func_pvt = NULL;
+
+    if (domain_id == NULL || input == NULL || _id == NULL) {
+        return IDMAP_ERROR;
+    }
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    idmap_domain_info = ctx->idmap_domain_info;
+
+    if (idmap_domain_info->offset_func != NULL) {
+        offset_func = idmap_domain_info->offset_func;
+        if (idmap_domain_info->offset_func_pvt != NULL) {
+            offset_func_pvt = idmap_domain_info->offset_func_pvt;
+        }
+    }
+
+    /* Try primary slices */
+    while (idmap_domain_info != NULL) {
+
+        if (is_from_dom(idmap_domain_info->sid, domain_id)) {
+
+            if (idmap_domain_info->external_mapping == true) {
+                return IDMAP_EXTERNAL;
+            }
+
+            range_size = 1 + (idmap_domain_info->range_params.max_id - idmap_domain_info->range_params.min_id);
+            err = offset_func(offset_func_pvt, range_size, input, &offset);
+            if (err != IDMAP_SUCCESS) {
+                return err;
+            }
+
+            if (offset >= range_size) {
+                return IDMAP_ERROR;
+            }
+
+            if (comp_id(&idmap_domain_info->range_params, offset, _id)) {
+                return IDMAP_SUCCESS;
+            }
+
+            matched_dom = idmap_domain_info;
+        }
+
+        idmap_domain_info = idmap_domain_info->next;
+    }
+
+    return matched_dom ? IDMAP_NO_RANGE : IDMAP_NO_DOMAIN;
+}
+
+enum idmap_error_code sss_idmap_unix_to_gen(struct sss_idmap_ctx *ctx,
+                                            uint32_t id,
+                                            char **_out)
+{
+    struct idmap_domain_info *idmap_domain_info;
+    uint32_t offset;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    idmap_domain_info = ctx->idmap_domain_info;
+
+    while (idmap_domain_info != NULL) {
+        if (id_is_in_range(id, &idmap_domain_info->range_params, &offset)) {
+
+            if (idmap_domain_info->external_mapping == true
+                    || idmap_domain_info->sid == NULL) {
+                return IDMAP_EXTERNAL;
+            }
+
+            if (idmap_domain_info->rev_offset_func == NULL) {
+                return IDMAP_NO_REVERSE;
+            }
+
+            return idmap_domain_info->rev_offset_func(ctx,
+                                             idmap_domain_info->offset_func_pvt,
+                                             offset, _out);
+        }
+
+        idmap_domain_info = idmap_domain_info->next;
+    }
+
+    return IDMAP_NO_DOMAIN;
+}
+
+enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
+                                            const char *sid,
+                                            uint32_t *_id)
+{
+    struct idmap_domain_info *idmap_domain_info;
+    struct idmap_domain_info *matched_dom = NULL;
+    size_t dom_len;
+    long long rid;
+
+    if (sid == NULL || _id == NULL) {
+        return IDMAP_ERROR;
+    }
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    idmap_domain_info = ctx->idmap_domain_info;
+
+    if (sss_idmap_sid_is_builtin(sid)) {
+        return IDMAP_BUILTIN_SID;
+    }
+
+    /* Try primary slices */
+    while (idmap_domain_info != NULL) {
+
+        if (is_sid_from_dom(idmap_domain_info->sid, sid, &dom_len)) {
+
+            if (idmap_domain_info->external_mapping == true) {
+                return IDMAP_EXTERNAL;
+            }
+
+            if (parse_rid(sid, dom_len, &rid) == false) {
+                return IDMAP_SID_INVALID;
+            }
+
+            if (comp_id(&idmap_domain_info->range_params, rid, _id)) {
+                return IDMAP_SUCCESS;
+            }
+
+            matched_dom = idmap_domain_info;
+        }
+
+        idmap_domain_info = idmap_domain_info->next;
+    }
+
+    if (matched_dom != NULL && matched_dom->auto_add_ranges) {
+        return add_dom_for_sid(ctx, matched_dom, sid, _id);
+    }
+
+    return matched_dom ? IDMAP_NO_RANGE : IDMAP_NO_DOMAIN;
+}
+
+enum idmap_error_code sss_idmap_check_sid_unix(struct sss_idmap_ctx *ctx,
+                                               const char *sid,
+                                               uint32_t id)
+{
+    struct idmap_domain_info *idmap_domain_info;
+    size_t dom_len;
+    bool no_range = false;
+
+    if (sid == NULL) {
+        return IDMAP_ERROR;
+    }
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (ctx->idmap_domain_info == NULL) {
+        return IDMAP_NO_DOMAIN;
+    }
+
+    idmap_domain_info = ctx->idmap_domain_info;
+
+    if (sss_idmap_sid_is_builtin(sid)) {
+        return IDMAP_BUILTIN_SID;
+    }
+
+    while (idmap_domain_info != NULL) {
+        if (idmap_domain_info->sid != NULL) {
+            dom_len = strlen(idmap_domain_info->sid);
+            if (strlen(sid) > dom_len && sid[dom_len] == '-'
+                    && strncmp(sid, idmap_domain_info->sid, dom_len) == 0) {
+
+                if (id >= idmap_domain_info->range_params.min_id
+                    && id <= idmap_domain_info->range_params.max_id) {
+                    return IDMAP_SUCCESS;
+                }
+
+                no_range = true;
+            }
+        }
+
+        idmap_domain_info = idmap_domain_info->next;
+    }
+
+    return no_range ? IDMAP_NO_RANGE : IDMAP_SID_UNKNOWN;
+}
+
+static enum idmap_error_code generate_sid(struct sss_idmap_ctx *ctx,
+                                          const char *dom_sid,
+                                          uint32_t rid,
+                                          char **_sid)
+{
+    char *sid;
+    int len;
+    int ret;
+
+    len = snprintf(NULL, 0, SID_FMT, dom_sid, rid);
+    if (len <= 0 || len > SID_STR_MAX_LEN) {
+        return IDMAP_ERROR;
+    }
+
+    sid = ctx->alloc_func(len + 1, ctx->alloc_pvt);
+    if (sid == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+
+    ret = snprintf(sid, len + 1, SID_FMT, dom_sid, rid);
+    if (ret != len) {
+        ctx->free_func(sid, ctx->alloc_pvt);
+        return IDMAP_ERROR;
+    }
+
+    *_sid = sid;
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
+                                            uint32_t id,
+                                            char **_sid)
+{
+    struct idmap_domain_info *idmap_domain_info;
+    uint32_t rid;
+    enum idmap_error_code err;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    idmap_domain_info = ctx->idmap_domain_info;
+
+    while (idmap_domain_info != NULL) {
+        if (id_is_in_range(id, &idmap_domain_info->range_params, &rid)) {
+
+            if (idmap_domain_info->external_mapping == true
+                    || idmap_domain_info->sid == NULL) {
+                return IDMAP_EXTERNAL;
+            }
+
+            return generate_sid(ctx, idmap_domain_info->sid, rid, _sid);
+        }
+
+        idmap_domain_info = idmap_domain_info->next;
+    }
+
+    /* Check secondary ranges. */
+    idmap_domain_info = ctx->idmap_domain_info;
+    while (idmap_domain_info != NULL) {
+
+        for (struct idmap_range_params *it = idmap_domain_info->helpers;
+             it != NULL;
+             it = it->next) {
+
+            if (idmap_domain_info->helpers_owner == false) {
+                /* Checking helpers on owner is sufficient. */
+                continue;
+            }
+
+            if (id_is_in_range(id, it, &rid)) {
+
+                if (idmap_domain_info->external_mapping == true
+                    || idmap_domain_info->sid == NULL) {
+                    return IDMAP_EXTERNAL;
+                }
+
+                err = spawn_dom(ctx, idmap_domain_info, it);
+                if (err != IDMAP_SUCCESS) {
+                    return err;
+                }
+
+                return generate_sid(ctx, idmap_domain_info->sid, rid, _sid);
+            }
+        }
+
+        idmap_domain_info = idmap_domain_info->next;
+    }
+
+    return IDMAP_NO_DOMAIN;
+}
+
+enum idmap_error_code sss_idmap_dom_sid_to_unix(struct sss_idmap_ctx *ctx,
+                                                struct sss_dom_sid *dom_sid,
+                                                uint32_t *id)
+{
+    enum idmap_error_code err;
+    char *sid;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_sid_to_unix(ctx, sid, id);
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_bin_sid_to_unix(struct sss_idmap_ctx *ctx,
+                                                uint8_t *bin_sid,
+                                                size_t length,
+                                                uint32_t *id)
+{
+    enum idmap_error_code err;
+    char *sid;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_bin_sid_to_sid(ctx, bin_sid, length, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_sid_to_unix(ctx, sid, id);
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_smb_sid_to_unix(struct sss_idmap_ctx *ctx,
+                                                struct dom_sid *smb_sid,
+                                                uint32_t *id)
+{
+    enum idmap_error_code err;
+    char *sid;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_smb_sid_to_sid(ctx, smb_sid, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_sid_to_unix(ctx, sid, id);
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_check_dom_sid_to_unix(struct sss_idmap_ctx *ctx,
+                                                    struct sss_dom_sid *dom_sid,
+                                                    uint32_t id)
+{
+    enum idmap_error_code err;
+    char *sid;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_check_sid_unix(ctx, sid, id);
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_check_bin_sid_unix(struct sss_idmap_ctx *ctx,
+                                                   uint8_t *bin_sid,
+                                                   size_t length,
+                                                   uint32_t id)
+{
+    enum idmap_error_code err;
+    char *sid;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_bin_sid_to_sid(ctx, bin_sid, length, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_check_sid_unix(ctx, sid, id);
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_check_smb_sid_unix(struct sss_idmap_ctx *ctx,
+                                                   struct dom_sid *smb_sid,
+                                                   uint32_t id)
+{
+    enum idmap_error_code err;
+    char *sid;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_smb_sid_to_sid(ctx, smb_sid, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_check_sid_unix(ctx, sid, id);
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+
+    return err;
+}
+enum idmap_error_code sss_idmap_unix_to_dom_sid(struct sss_idmap_ctx *ctx,
+                                                uint32_t id,
+                                                struct sss_dom_sid **_dom_sid)
+{
+    enum idmap_error_code err;
+    char *sid = NULL;
+    struct sss_dom_sid *dom_sid = NULL;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_unix_to_sid(ctx, id, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_sid_to_dom_sid(ctx, sid, &dom_sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    *_dom_sid = dom_sid;
+    err = IDMAP_SUCCESS;
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(dom_sid, ctx->alloc_pvt);
+    }
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_unix_to_bin_sid(struct sss_idmap_ctx *ctx,
+                                                uint32_t id,
+                                                uint8_t **_bin_sid,
+                                                size_t *_length)
+{
+    enum idmap_error_code err;
+    char *sid = NULL;
+    uint8_t *bin_sid = NULL;
+    size_t length;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    err = sss_idmap_unix_to_sid(ctx, id, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_sid_to_bin_sid(ctx, sid, &bin_sid, &length);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    *_bin_sid = bin_sid;
+    *_length = length;
+    err = IDMAP_SUCCESS;
+
+done:
+    ctx->free_func(sid, ctx->alloc_pvt);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(bin_sid, ctx->alloc_pvt);
+    }
+
+    return err;
+
+}
+
+enum idmap_error_code
+sss_idmap_ctx_set_autorid(struct sss_idmap_ctx *ctx, bool use_autorid)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+    ctx->idmap_opts.autorid_mode = use_autorid;
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code
+sss_idmap_ctx_set_lower(struct sss_idmap_ctx *ctx, id_t lower)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+    ctx->idmap_opts.idmap_lower = lower;
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code
+sss_idmap_ctx_set_upper(struct sss_idmap_ctx *ctx, id_t upper)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+    ctx->idmap_opts.idmap_upper = upper;
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code
+sss_idmap_ctx_set_rangesize(struct sss_idmap_ctx *ctx, id_t rangesize)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+    ctx->idmap_opts.rangesize = rangesize;
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code
+sss_idmap_ctx_set_extra_slice_init(struct sss_idmap_ctx *ctx,
+                                  int extra_slice_init)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+    ctx->idmap_opts.extra_slice_init = extra_slice_init;
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code
+sss_idmap_ctx_get_autorid(struct sss_idmap_ctx *ctx, bool *_autorid)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+     *_autorid = ctx->idmap_opts.autorid_mode;
+     return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code
+sss_idmap_ctx_get_lower(struct sss_idmap_ctx *ctx, id_t *_lower)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+    *_lower = ctx->idmap_opts.idmap_lower;
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code
+sss_idmap_ctx_get_upper(struct sss_idmap_ctx *ctx, id_t *_upper)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+    *_upper = ctx->idmap_opts.idmap_upper;
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code
+sss_idmap_ctx_get_rangesize(struct sss_idmap_ctx *ctx, id_t *_rangesize)
+{
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+    *_rangesize =  ctx->idmap_opts.rangesize;
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code
+sss_idmap_domain_has_algorithmic_mapping(struct sss_idmap_ctx *ctx,
+                                         const char *dom_sid,
+                                         bool *has_algorithmic_mapping)
+{
+    struct idmap_domain_info *idmap_domain_info;
+    size_t len;
+    size_t dom_sid_len;
+
+    if (dom_sid == NULL) {
+        return IDMAP_SID_INVALID;
+    }
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (ctx->idmap_domain_info == NULL) {
+        return IDMAP_NO_DOMAIN;
+    }
+
+    idmap_domain_info = ctx->idmap_domain_info;
+
+    while (idmap_domain_info != NULL) {
+        if (idmap_domain_info->sid != NULL) {
+            len = strlen(idmap_domain_info->sid);
+            dom_sid_len = strlen(dom_sid);
+            if (((dom_sid_len > len && dom_sid[len] == '-')
+                        || dom_sid_len == len)
+                    && strncmp(dom_sid, idmap_domain_info->sid, len) == 0) {
+
+                *has_algorithmic_mapping = !idmap_domain_info->external_mapping;
+                return IDMAP_SUCCESS;
+
+            }
+        }
+
+        idmap_domain_info = idmap_domain_info->next;
+    }
+
+    return IDMAP_SID_UNKNOWN;
+}
+
+enum idmap_error_code
+sss_idmap_domain_by_name_has_algorithmic_mapping(struct sss_idmap_ctx *ctx,
+                                                 const char *dom_name,
+                                                 bool *has_algorithmic_mapping)
+{
+    struct idmap_domain_info *idmap_domain_info;
+
+    if (dom_name == NULL) {
+        return IDMAP_ERROR;
+    }
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (ctx->idmap_domain_info == NULL) {
+        return IDMAP_NO_DOMAIN;
+    }
+
+    idmap_domain_info = ctx->idmap_domain_info;
+
+    while (idmap_domain_info != NULL) {
+        if (idmap_domain_info->name != NULL
+                && strcmp(dom_name, idmap_domain_info->name) == 0) {
+
+            *has_algorithmic_mapping = !idmap_domain_info->external_mapping;
+            return IDMAP_SUCCESS;
+        }
+
+        idmap_domain_info = idmap_domain_info->next;
+    }
+
+    return IDMAP_NAME_UNKNOWN;
+}
diff --git a/himmelblaud/idmap/src/sss_idmap.h b/himmelblaud/idmap/src/sss_idmap.h
new file mode 100644 (file)
index 0000000..a94c07f
--- /dev/null
@@ -0,0 +1,1100 @@
+/*
+    SSSD
+
+    ID-mapping library
+
+    Authors:
+        Sumit Bose <sbose@redhat.com>
+
+    Copyright (C) 2012 Red Hat
+
+    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 SSS_IDMAP_H_
+#define SSS_IDMAP_H_
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#define DOM_SID_PREFIX "S-1-5-21-"
+#define DOM_SID_PREFIX_LEN (sizeof(DOM_SID_PREFIX) - 1)
+
+/**
+ * @defgroup sss_idmap Map Unix UIDs and GIDs to SIDs and back
+ * Libsss_idmap provides a mechanism to translate a SID to a UNIX UID or GID
+ * or the other way round.
+ * @{
+ */
+
+/**
+ * Error codes used by libsss_idmap
+ */
+enum idmap_error_code {
+    /** Success */
+    IDMAP_SUCCESS = 0,
+
+    /** Function is not yet implemented */
+    IDMAP_NOT_IMPLEMENTED,
+
+    /** General error */
+    IDMAP_ERROR,
+
+    /** Ran out of memory during processing */
+    IDMAP_OUT_OF_MEMORY,
+
+    /** No domain added */
+    IDMAP_NO_DOMAIN,
+
+    /** The provided idmap context is invalid */
+    IDMAP_CONTEXT_INVALID,
+
+    /** The provided SID is invalid */
+    IDMAP_SID_INVALID,
+
+    /** The provided  SID was not found */
+    IDMAP_SID_UNKNOWN,
+
+    /** The provided UID or GID could not be mapped */
+    IDMAP_NO_RANGE,
+
+    /** The provided SID is a built-in one */
+    IDMAP_BUILTIN_SID,
+
+    /** No more free slices */
+    IDMAP_OUT_OF_SLICES,
+
+    /** New domain collides with existing one */
+    IDMAP_COLLISION,
+
+    /** External source should be consulted for idmapping */
+    IDMAP_EXTERNAL,
+
+    /** The provided  name was not found */
+    IDMAP_NAME_UNKNOWN,
+
+    /** It is not possible to convert an id into the original value the id was
+     *  derived from */
+    IDMAP_NO_REVERSE,
+
+    /** Error during UTF8 operation like normalization or casefolding */
+    IDMAP_UTF8_ERROR,
+
+    /** Sentinel to indicate the end of the error code list, not returned by
+     * any call */
+    IDMAP_ERR_LAST
+};
+
+/**
+ * Typedef for memory allocation functions
+ */
+typedef void *(idmap_alloc_func)(size_t size, void *pvt);
+typedef void (idmap_free_func)(void *ptr, void *pvt);
+
+/**
+ * Typedef for storing mappings of dynamically created domains
+ */
+typedef enum idmap_error_code (*idmap_store_cb)(const char *dom_name,
+                                                const char *dom_sid,
+                                                const char *range_id,
+                                                uint32_t min_id,
+                                                uint32_t max_id,
+                                                uint32_t first_rid,
+                                                void *pvt);
+
+/**
+ * Structure for id ranges
+ * FIXME: this struct might change when it is clear how ranges are handled on
+ * the server side
+ */
+struct sss_idmap_range {
+    uint32_t min;
+    uint32_t max;
+};
+
+/**
+ * Opaque type for SIDs
+ */
+struct sss_dom_sid;
+
+/**
+ * Opaque type for the idmap context
+ */
+struct sss_idmap_ctx;
+
+/**
+ * Placeholder for Samba's struct dom_sid. Consumers of libsss_idmap should
+ * include an appropriate Samba header file to define struct dom_sid. We use
+ * it here to avoid a hard dependency on Samba devel packages.
+ */
+struct dom_sid;
+
+/**
+ * @brief Initialize idmap context
+ *
+ * @param[in] alloc_func Function to allocate memory for the context, if
+ *                       NULL malloc() id used
+ * @param[in] alloc_pvt  Private data for allocation routine
+ * @param[in] free_func  Function to free the memory the context, if
+ *                       NULL free() id used
+ * @param[out] ctx       idmap context
+ *
+ * @return
+ *  - #IDMAP_OUT_OF_MEMORY: Insufficient memory to create the context
+ */
+enum idmap_error_code sss_idmap_init(idmap_alloc_func *alloc_func,
+                                     void *alloc_pvt,
+                                     idmap_free_func *free_func,
+                                     struct sss_idmap_ctx **ctx);
+
+/**
+ * @brief Set/unset autorid compatibility mode
+ *
+ * @param[in] ctx           idmap context
+ * @param[in] use_autorid   If true, autorid compatibility mode will be used
+ */
+enum idmap_error_code
+sss_idmap_ctx_set_autorid(struct sss_idmap_ctx *ctx, bool use_autorid);
+
+/**
+ * @brief Set the lower bound of the range of POSIX IDs
+ *
+ * @param[in] ctx           idmap context
+ * @param[in] lower         lower bound of the range
+ */
+enum idmap_error_code
+sss_idmap_ctx_set_lower(struct sss_idmap_ctx *ctx, id_t lower);
+
+/**
+ * @brief Set the upper bound of the range of POSIX IDs
+ *
+ * @param[in] ctx           idmap context
+ * @param[in] upper         upper bound of the range
+ */
+enum idmap_error_code
+sss_idmap_ctx_set_upper(struct sss_idmap_ctx *ctx, id_t upper);
+
+/**
+ * @brief Set the range size of POSIX IDs available for single domain
+ *
+ * @param[in] ctx           idmap context
+ * @param[in] rangesize     range size of IDs
+ */
+enum idmap_error_code
+sss_idmap_ctx_set_rangesize(struct sss_idmap_ctx *ctx, id_t rangesize);
+
+/**
+ * @brief Set the number of secondary slices available for domain
+ *
+ * @param[in] ctx                  idmap context
+ * @param[in] extra_slice_init     number of secondary slices to be generated
+ *                                 at startup
+ */
+enum idmap_error_code
+sss_idmap_ctx_set_extra_slice_init(struct sss_idmap_ctx *ctx,
+                                  int extra_slice_init);
+
+/**
+ * @brief Check if autorid compatibility mode is set
+ *
+ * @param[in] ctx           idmap context
+ * @param[out] _autorid     true if autorid is used
+ */
+enum idmap_error_code
+sss_idmap_ctx_get_autorid(struct sss_idmap_ctx *ctx, bool *_autorid);
+
+/**
+ * @brief Get the lower bound of the range of POSIX IDs
+ *
+ * @param[in] ctx           idmap context
+ * @param[out] _lower       returned lower bound
+ */
+enum idmap_error_code
+sss_idmap_ctx_get_lower(struct sss_idmap_ctx *ctx, id_t *_lower);
+
+/**
+ * @brief Get the upper bound of the range of POSIX IDs
+ *
+ * @param[in] ctx           idmap context
+ * @param[out] _upper       returned upper bound
+ */
+enum idmap_error_code
+sss_idmap_ctx_get_upper(struct sss_idmap_ctx *ctx, id_t *_upper);
+
+/**
+ * @brief Get the range size of POSIX IDs available for single domain
+ *
+ * @param[in] ctx           idmap context
+ * @param[out] rangesize    returned range size
+ */
+enum idmap_error_code
+sss_idmap_ctx_get_rangesize(struct sss_idmap_ctx *ctx, id_t *rangesize);
+
+/**
+ * @brief Calculate new range of available POSIX IDs
+ *
+ * @param[in] ctx           Idmap context
+ * @param[in] dom_sid       Zero-terminated string representation of the domain
+ *                          SID (S-1-15-.....)
+ * @param[in,out] slice_num Slice number to be used. Set this pointer to NULL or
+ *                          the addressed value to -1 to calculate slice number
+ *                          automatically. The calculated value will be
+ *                          returned in this parameter.
+ * @param[out] range        Structure containing upper and lower bound of the
+ *                          range of POSIX IDs
+ *
+ * @return
+ *  - #IDMAP_OUT_OF_SLICES: Cannot calculate new range because all slices are
+ *                          used.
+ */
+enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
+                                                const char *dom_sid,
+                                                id_t *slice_num,
+                                                struct sss_idmap_range *range);
+
+/**
+ * @brief Add a domain to the idmap context
+ *
+ * @param[in] ctx         Idmap context
+ * @param[in] domain_name Zero-terminated string with the domain name
+ * @param[in] domain_sid  Zero-terminated string representation of the domain
+ *                        SID (S-1-15-.....)
+ * @param[in] range       TBD Some information about the id ranges of this
+ *                        domain
+ *
+ * @return
+ *  - #IDMAP_OUT_OF_MEMORY: Insufficient memory to store the data in the idmap
+ *                          context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_NO_DOMAIN:     No domain domain name given
+ *  - #IDMAP_COLLISION:     New domain collides with existing one
+ */
+enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
+                                           const char *domain_name,
+                                           const char *domain_sid,
+                                           struct sss_idmap_range *range);
+
+/**
+ * @brief Add a domain with the first mappable RID to the idmap context
+ *
+ * @param[in] ctx         Idmap context
+ * @param[in] domain_name Zero-terminated string with the domain name
+ * @param[in] domain_sid  Zero-terminated string representation of the domain
+ *                        SID (S-1-15-.....)
+ * @param[in] range       TBD Some information about the id ranges of this
+ *                        domain
+ * @param[in] range_id    optional unique identifier of a range, it is needed
+ *                        to allow updates at runtime
+ * @param[in] rid         The RID that should be mapped to the first ID of the
+ *                        given range.
+ * @param[in] external_mapping  If set to true the ID will not be mapped
+ *                        algorithmically, but the *_to_unix and *_unix_to_*
+ *                        calls will return IDMAP_EXTERNAL to instruct the
+ *                        caller to check external sources. For a single
+ *                        domain all ranges must be of the same type. It is
+ *                        not possible to mix algorithmic and external
+ *                        mapping.
+ *
+ * @return
+ *  - #IDMAP_OUT_OF_MEMORY: Insufficient memory to store the data in the idmap
+ *                          context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_NO_DOMAIN:     No domain domain name given
+ *  - #IDMAP_COLLISION:     New domain collides with existing one
+ */
+enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
+                                              const char *domain_name,
+                                              const char *domain_sid,
+                                              struct sss_idmap_range *range,
+                                              const char *range_id,
+                                              uint32_t rid,
+                                              bool external_mapping);
+
+/**
+ * @brief Add a domain with the first mappable RID to the idmap context and
+ * generate automatically secondary slices
+ *
+ * @param[in] ctx         Idmap context
+ * @param[in] domain_name Zero-terminated string with the domain name
+ * @param[in] domain_sid  Zero-terminated string representation of the domain
+ *                        SID (S-1-15-.....)
+ * @param[in] range       TBD Some information about the id ranges of this
+ *                        domain
+ * @param[in] range_id    optional unique identifier of a range, it is needed
+ *                        to allow updates at runtime
+ * @param[in] rid         The RID that should be mapped to the first ID of the
+ *                        given range.
+ * @param[in] external_mapping  If set to true the ID will not be mapped
+ *                        algorithmically, but the *_to_unix and *_unix_to_*
+ *                        calls will return IDMAP_EXTERNAL to instruct the
+ *                        caller to check external sources. For a single
+ *                        domain all ranges must be of the same type. It is
+ *                        not possible to mix algorithmic and external
+ *                        mapping.
+ * @param[in] cb          The callback for storing mapping of dynamically
+ *                        created domains.
+ * @param[in] pvt         Private data for callback cb.
+ *
+ * @return
+ *  - #IDMAP_OUT_OF_MEMORY: Insufficient memory to store the data in the idmap
+ *                          context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_NO_DOMAIN:     No domain domain name given
+ *  - #IDMAP_COLLISION:     New domain collides with existing one
+ */
+enum idmap_error_code
+sss_idmap_add_auto_domain_ex(struct sss_idmap_ctx *ctx,
+                             const char *domain_name,
+                             const char *domain_sid,
+                             struct sss_idmap_range *range,
+                             const char *range_id,
+                             uint32_t rid,
+                             bool external_mapping,
+                             idmap_store_cb cb,
+                             void *pvt);
+
+/**
+ * @brief Check if a new range would collide with any existing one
+ *
+ * @param[in] ctx         Idmap context
+ * @param[in] n_name      Zero-terminated string with the domain name the new
+ *                        range should belong to
+ * @param[in] n_sid       Zero-terminated string representation of the domain
+ *                        SID (S-1-15-.....) the new range should belong to
+ * @param[in] n_range     The new id range
+ * @param[in] n_range_id  unique identifier of the new range, it is needed
+ *                        to allow updates at runtime, may be NULL
+ * @param[in] n_first_rid The RID that should be mapped to the first ID of the
+ *                        new range.
+ * @param[in] n_external_mapping Mapping type of the new range
+ *
+ * @return
+ *  - #IDMAP_COLLISION:     New range collides with existing one
+ */
+enum idmap_error_code sss_idmap_check_collision(struct sss_idmap_ctx *ctx,
+                                                char *n_name, char *n_sid,
+                                                struct sss_idmap_range *n_range,
+                                                uint32_t n_first_rid,
+                                                char *n_range_id,
+                                                bool n_external_mapping);
+
+/**
+ * @brief Check if two ranges would collide
+ *
+ * @param[in] o_name      Zero-terminated string with the domain name the
+ *                        first range should belong to
+ * @param[in] o_sid       Zero-terminated string representation of the domain
+ *                        SID (S-1-15-.....) the first range should belong to
+ * @param[in] o_range     The first id range
+ * @param[in] o_range_id  unique identifier of the first range, it is needed
+ *                        to allow updates at runtime, may be NULL
+ * @param[in] o_first_rid The RID that should be mapped to the first ID of the
+ *                        first range.
+ * @param[in] o_external_mapping Mapping type of the first range
+ * @param[in] n_name      Zero-terminated string with the domain name the
+ *                        second range should belong to
+ * @param[in] n_sid       Zero-terminated string representation of the domain
+ *                        SID (S-1-15-.....) the second range should belong to
+ * @param[in] n_range     The second id range
+ * @param[in] n_range_id  unique identifier of the second range, it is needed
+ *                        to allow updates at runtime, may be NULL
+ * @param[in] n_first_rid The RID that should be mapped to the first ID of the
+ *                        second range.
+ * @param[in] n_external_mapping Mapping type of the second range
+ *
+ * @return
+ *  - #IDMAP_COLLISION:     New range collides with existing one
+ */
+enum idmap_error_code sss_idmap_check_collision_ex(const char *o_name,
+                                                const char *o_sid,
+                                                struct sss_idmap_range *o_range,
+                                                uint32_t o_first_rid,
+                                                const char *o_range_id,
+                                                bool o_external_mapping,
+                                                const char *n_name,
+                                                const char *n_sid,
+                                                struct sss_idmap_range *n_range,
+                                                uint32_t n_first_rid,
+                                                const char *n_range_id,
+                                                bool n_external_mapping);
+
+/**
+ * @brief Translate SID to a unix UID or GID
+ *
+ * @param[in] ctx Idmap context
+ * @param[in] sid Zero-terminated string representation of the SID
+ * @param[out] id Returned unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_EXTERNAL:      external source is authoritative for mapping
+ */
+enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
+                                            const char *sid,
+                                            uint32_t *id);
+
+/**
+ * @brief Translate a SID structure to a unix UID or GID
+ *
+ * @param[in] ctx     Idmap context
+ * @param[in] dom_sid SID structure
+ * @param[out] id     Returned unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_EXTERNAL:      external source is authoritative for mapping
+ */
+enum idmap_error_code sss_idmap_dom_sid_to_unix(struct sss_idmap_ctx *ctx,
+                                                struct sss_dom_sid *dom_sid,
+                                                uint32_t *id);
+
+/**
+ * @brief Translate a binary SID to a unix UID or GID
+ *
+ * @param[in] ctx     Idmap context
+ * @param[in] bin_sid Array with the binary SID
+ * @param[in] length  Size of the array containing the binary SID
+ * @param[out] id     Returned unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_EXTERNAL:      external source is authoritative for mapping
+ */
+enum idmap_error_code sss_idmap_bin_sid_to_unix(struct sss_idmap_ctx *ctx,
+                                                uint8_t *bin_sid,
+                                                size_t length,
+                                                uint32_t *id);
+
+/**
+ * @brief Translate a Samba dom_sid structure to a unix UID or GID
+ *
+ * @param[in] ctx     Idmap context
+ * @param[in] smb_sid Samba dom_sid structure
+ * @param[out] id     Returned unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_EXTERNAL:      external source is authoritative for mapping
+ */
+enum idmap_error_code sss_idmap_smb_sid_to_unix(struct sss_idmap_ctx *ctx,
+                                                struct dom_sid *smb_sid,
+                                                uint32_t *id);
+
+/**
+ * @brief Check if a SID and a unix UID or GID belong to the same range
+ *
+ * @param[in] ctx Idmap context
+ * @param[in] sid Zero-terminated string representation of the SID
+ * @param[in] id  Unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_NO_RANGE       No matching ID range found
+ */
+enum idmap_error_code sss_idmap_check_sid_unix(struct sss_idmap_ctx *ctx,
+                                               const char *sid,
+                                               uint32_t id);
+
+/**
+ * @brief Check if a SID structure and a unix UID or GID belong to the same range
+ *
+ * @param[in] ctx     Idmap context
+ * @param[in] dom_sid SID structure
+ * @param[in] id      Unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_NO_RANGE       No matching ID range found
+ */
+enum idmap_error_code sss_idmap_check_dom_sid_unix(struct sss_idmap_ctx *ctx,
+                                                   struct sss_dom_sid *dom_sid,
+                                                   uint32_t id);
+
+/**
+ * @brief Check if a binary SID and a unix UID or GID belong to the same range
+ *
+ * @param[in] ctx     Idmap context
+ * @param[in] bin_sid Array with the binary SID
+ * @param[in] length  Size of the array containing the binary SID
+ * @param[in] id      Unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_NO_RANGE       No matching ID range found
+ */
+enum idmap_error_code sss_idmap_check_bin_sid_unix(struct sss_idmap_ctx *ctx,
+                                                   uint8_t *bin_sid,
+                                                   size_t length,
+                                                   uint32_t id);
+
+/**
+ * @brief Check if a Samba dom_sid structure and a unix UID or GID belong to
+ * the same range
+ *
+ * @param[in] ctx     Idmap context
+ * @param[in] smb_sid Samba dom_sid structure
+ * @param[in] id      Unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domains are added to the idmap context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_SID_UNKNOWN:   SID cannot be found in the domains added to the
+ *                          idmap context
+ *  - #IDMAP_NO_RANGE       No matching ID range found
+ */
+enum idmap_error_code sss_idmap_check_smb_sid_unix(struct sss_idmap_ctx *ctx,
+                                                   struct dom_sid *smb_sid,
+                                                   uint32_t id);
+
+/**
+ * @brief Translate unix UID or GID to a SID
+ *
+ * @param[in] ctx  Idmap context
+ * @param[in] id   unix UID or GID
+ * @param[out] sid Zero-terminated string representation of the SID, must be
+ *                 freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN: No domains are added to the idmap context
+ *  - #IDMAP_NO_RANGE:  The provided ID cannot be found in the domains added
+ *                      to the idmap context
+ *  - #IDMAP_EXTERNAL:  external source is authoritative for mapping
+ */
+enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
+                                            uint32_t id,
+                                            char **sid);
+
+/**
+ * @brief Translate unix UID or GID to a SID structure
+ *
+ * @param[in] ctx      Idmap context
+ * @param[in] id       unix UID or GID
+ * @param[out] dom_sid SID structure, must be freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN: No domains are added to the idmap context
+ *  - #IDMAP_NO_RANGE:  The provided ID cannot be found in the domains added
+ *                      to the idmap context
+ *  - #IDMAP_EXTERNAL:  external source is authoritative for mapping
+ */
+enum idmap_error_code sss_idmap_unix_to_dom_sid(struct sss_idmap_ctx *ctx,
+                                                uint32_t id,
+                                                struct sss_dom_sid **dom_sid);
+
+/**
+ * @brief Translate unix UID or GID to a binary SID
+ *
+ * @param[in] ctx      Idmap context
+ * @param[in] id       unix UID or GID
+ * @param[out] bin_sid Array with the binary SID,
+ *                     must be freed if not needed anymore
+ * @param[out] length  size of the array containing the binary SID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN: No domains are added to the idmap context
+ *  - #IDMAP_NO_RANGE:  The provided ID cannot be found in the domains added
+ *                      to the idmap context
+ *  - #IDMAP_EXTERNAL:  external source is authoritative for mapping
+ */
+enum idmap_error_code sss_idmap_unix_to_bin_sid(struct sss_idmap_ctx *ctx,
+                                                uint32_t id,
+                                                uint8_t **bin_sid,
+                                                size_t *length);
+
+/**
+ * @brief Free all the allocated memory of the idmap context
+ *
+ * @param[in] ctx         Idmap context
+ *
+ * @return
+ *  - #IDMAP_CONTEXT_INVALID: Provided context is invalid
+ */
+enum idmap_error_code sss_idmap_free(struct sss_idmap_ctx *ctx);
+
+/**
+ * @brief Free mapped SID.
+ *
+ * @param[in] ctx         Idmap context
+ * @param[in] sid         SID to be freed.
+ *
+ * @return
+ *  - #IDMAP_CONTEXT_INVALID: Provided context is invalid
+ */
+enum idmap_error_code sss_idmap_free_sid(struct sss_idmap_ctx *ctx,
+                                         char *sid);
+
+/**
+ * @brief Free mapped domain SID.
+ *
+ * @param[in] ctx         Idmap context
+ * @param[in] dom_sid     Domain SID to be freed.
+ *
+ * @return
+ *  - #IDMAP_CONTEXT_INVALID: Provided context is invalid
+ */
+enum idmap_error_code sss_idmap_free_dom_sid(struct sss_idmap_ctx *ctx,
+                                             struct sss_dom_sid *dom_sid);
+
+/**
+ * @brief Free mapped Samba SID.
+ *
+ * @param[in] ctx         Idmap context
+ * @param[in] smb_sid     Samba SID to be freed.
+ *
+ * @return
+ *  - #IDMAP_CONTEXT_INVALID: Provided context is invalid
+ */
+enum idmap_error_code sss_idmap_free_smb_sid(struct sss_idmap_ctx *ctx,
+                                             struct dom_sid *smb_sid);
+
+/**
+ * @brief Free mapped binary SID.
+ *
+ * @param[in] ctx         Idmap context
+ * @param[in] bin_sid     Binary SID to be freed.
+ *
+ * @return
+ *  - #IDMAP_CONTEXT_INVALID: Provided context is invalid
+ */
+enum idmap_error_code sss_idmap_free_bin_sid(struct sss_idmap_ctx *ctx,
+                                             uint8_t *bin_sid);
+
+/**
+ * @brief Translate error code to a string
+ *
+ * @param[in] err  Idmap error code
+ *
+ * @return
+ *  - Error description as a zero-terminated string
+ */
+const char *idmap_error_string(enum idmap_error_code err);
+
+/**
+ * @brief Check if given string can be used as domain SID
+ *
+ * @param[in] str   String to check
+ *
+ * @return
+ *  - true: String can be used as domain SID
+ *  - false: String can not be used as domain SID
+ */
+bool is_domain_sid(const char *str);
+
+/**
+ * @brief Check if a domain is configured with algorithmic mapping
+ *
+ * @param[in] ctx                      Idmap context
+ * @param[in] dom_sid                  SID string, can be either a domain SID
+ *                                     or an object SID
+ * @param[out] has_algorithmic_mapping Boolean value indicating if the given
+ *                                     domain is configured for algorithmic
+ *                                     mapping or not.
+ *
+ * @return
+ *  - #IDMAP_SUCCESS:         Domain for the given SID was found and
+ *                            has_algorithmic_mapping is set accordingly
+ *  - #IDMAP_SID_INVALID:     Provided SID is invalid
+ *  - #IDMAP_CONTEXT_INVALID: Provided idmap context is invalid
+ *  - #IDMAP_NO_DOMAIN:       No domains are available in the idmap context
+ *  - #IDMAP_SID_UNKNOWN:     No domain with the given SID was found in the
+ *                            idmap context
+ */
+enum idmap_error_code
+sss_idmap_domain_has_algorithmic_mapping(struct sss_idmap_ctx *ctx,
+                                         const char *dom_sid,
+                                         bool *has_algorithmic_mapping);
+
+/**
+ * @brief Check if a domain is configured with algorithmic mapping
+ *
+ * @param[in]  ctx                     Idmap context
+ * @param[in]  dom_name                Name of the domain
+ * @param[out] has_algorithmic_mapping Boolean value indicating if the given
+ *                                     domain is configured for algorithmic
+ *                                     mapping or not.
+ *
+ * @return
+ *  - #IDMAP_SUCCESS:         Domain for the given name was found and
+ *                            has_algorithmic_mapping is set accordingly
+ *  - #IDMAP_ERROR:           Provided name is invalid
+ *  - #IDMAP_CONTEXT_INVALID: Provided idmap context is invalid
+ *  - #IDMAP_NO_DOMAIN:       No domains are available in the idmap context
+ *  - #IDMAP_NAME_UNKNOWN:    No domain with the given name was found in the
+ *                            idmap context
+ */
+enum idmap_error_code
+sss_idmap_domain_by_name_has_algorithmic_mapping(struct sss_idmap_ctx *ctx,
+                                                 const char *dom_name,
+                                                 bool *has_algorithmic_mapping);
+
+/**
+ * @brief Convert binary SID to SID structure
+ *
+ * @param[in] ctx      Idmap context
+ * @param[in] bin_sid  Array with the binary SID
+ * @param[in] length   Size of the array containing the binary SID
+ * @param[out] dom_sid SID structure,
+ *                     must be freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_bin_sid_to_dom_sid(struct sss_idmap_ctx *ctx,
+                                                   const uint8_t *bin_sid,
+                                                   size_t length,
+                                                   struct sss_dom_sid **dom_sid);
+
+/**
+ * @brief Convert binary SID to SID string
+ *
+ * @param[in] ctx      Idmap context
+ * @param[in] bin_sid  Array with the binary SID
+ * @param[in] length   Size of the array containing the binary SID
+ * @param[out] sid     Zero-terminated string representation of the SID,
+ *                     must be freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_bin_sid_to_sid(struct sss_idmap_ctx *ctx,
+                                               const uint8_t *bin_sid,
+                                               size_t length,
+                                               char **sid);
+
+/**
+ * @brief Convert SID structure to binary SID
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] dom_sid   SID structure
+ * @param[out] bin_sid  Array with the binary SID,
+ *                      must be freed if not needed anymore
+ * @param[out] length   Size of the array containing the binary SID
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_dom_sid_to_bin_sid(struct sss_idmap_ctx *ctx,
+                                                   struct sss_dom_sid *dom_sid,
+                                                   uint8_t **bin_sid,
+                                                   size_t *length);
+
+/**
+ * @brief Convert SID string to binary SID
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] sid       Zero-terminated string representation of the SID
+ * @param[out] bin_sid  Array with the binary SID,
+ *                      must be freed if not needed anymore
+ * @param[out] length   Size of the array containing the binary SID
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_sid_to_bin_sid(struct sss_idmap_ctx *ctx,
+                                               const char *sid,
+                                               uint8_t **bin_sid,
+                                               size_t *length);
+
+/**
+ * @brief Convert SID structure to SID string
+ *
+ * @param[in] ctx      Idmap context
+ * @param[in] dom_sid  SID structure
+ * @param[out] sid     Zero-terminated string representation of the SID,
+ *                     must be freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_dom_sid_to_sid(struct sss_idmap_ctx *ctx,
+                                               struct sss_dom_sid *dom_sid,
+                                               char **sid);
+
+/**
+ * @brief Convert SID string to SID structure
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] sid       Zero-terminated string representation of the SID
+ * @param[out] dom_sid  SID structure,
+ *                      must be freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_sid_to_dom_sid(struct sss_idmap_ctx *ctx,
+                                               const char *sid,
+                                               struct sss_dom_sid **dom_sid);
+
+/**
+ * @brief Convert SID string to Samba dom_sid structure
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] sid       Zero-terminated string representation of the SID
+ * @param[out] smb_sid  Samba dom_sid structure,
+ *                      must be freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_sid_to_smb_sid(struct sss_idmap_ctx *ctx,
+                                               const char *sid,
+                                               struct dom_sid **smb_sid);
+
+/**
+ * @brief Convert Samba dom_sid structure to SID string
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] smb_sid   Samba dom_sid structure
+ * @param[out] sid      Zero-terminated string representation of the SID,
+ *                      must be freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_smb_sid_to_sid(struct sss_idmap_ctx *ctx,
+                                               struct dom_sid *smb_sid,
+                                               char **sid);
+
+/**
+ * @brief Convert SID structure to Samba dom_sid structure
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] dom_sid   SID structure
+ * @param[out] smb_sid  Samba dom_sid structure,
+ *                      must be freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_dom_sid_to_smb_sid(struct sss_idmap_ctx *ctx,
+                                                   struct sss_dom_sid *dom_sid,
+                                                   struct dom_sid **smb_sid);
+
+/**
+ * @brief Convert Samba dom_sid structure to SID structure
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] smb_sid   Samba dom_sid structure
+ * @param[out] dom_sid  SID structure,
+ *                      must be freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_smb_sid_to_dom_sid(struct sss_idmap_ctx *ctx,
+                                                   struct dom_sid *smb_sid,
+                                                   struct sss_dom_sid **dom_sid);
+
+/**
+ * @brief Convert binary SID to Samba dom_sid structure
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] bin_sid   Array with the binary SID
+ * @param[in] length    Size of the array containing the binary SID
+ * @param[out] smb_sid  Samba dom_sid structure,
+ *                      must be freed if not needed anymore
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_bin_sid_to_smb_sid(struct sss_idmap_ctx *ctx,
+                                                   const uint8_t *bin_sid,
+                                                   size_t length,
+                                                   struct dom_sid **smb_sid);
+
+/**
+ * @brief Convert Samba dom_sid structure to binary SID
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] smb_sid   Samba dom_sid structure
+ * @param[out] bin_sid  Array with the binary SID,
+ *                      must be freed if not needed anymore
+ * @param[out] length   Size of the array containing the binary SID
+ *
+ * @return
+ *  - #IDMAP_SID_INVALID: Given SID is invalid
+ *  - #IDMAP_OUT_OF_MEMORY: Failed to allocate memory for the result
+ */
+enum idmap_error_code sss_idmap_smb_sid_to_bin_sid(struct sss_idmap_ctx *ctx,
+                                                   struct dom_sid *smb_sid,
+                                                   uint8_t **bin_sid,
+                                                   size_t *length);
+
+/**
+ * Typedef for functions to calculate an offset for id-mapping and, if
+ * possible, for the reverse operation.
+ */
+typedef enum idmap_error_code (idmap_offset_func)(void *pvt,
+                                                  uint32_t range_size,
+                                                  const char *input,
+                                                  long long *offset);
+
+typedef enum idmap_error_code (idmap_rev_offset_func)(struct sss_idmap_ctx *ctx,
+                                                      void *pvt,
+                                                      uint32_t offset,
+                                                      char **out);
+
+/**
+ * @brief Add a generic domain to the idmap context
+ *
+ * @param[in] ctx         Idmap context
+ * @param[in] domain_name Zero-terminated string with the domain name
+ * @param[in] domain_id   Zero-terminated string representation of a unique
+ *                        identifier of the domain, e.g. if available a domain
+ *                        UUID or the URI of domain specific service
+ * @param[in] range       Id ranges struct with smallest and largest id of the
+ *                        range
+ * @param[in] range_id    A name for the id range, currently not used, might
+ *                        become important when we allow multiple ranges for a
+ *                        single domain
+ * @param[in] offset_func Function to calculate an offset in a given range
+ *                        from some input given as string, if NULL
+ *                        offset_murmurhash3 will be used.
+ * @param[in] rev_offset_func Function to calculate the original input from a
+ *                        given offset, i.e. the reverse of offset_func, may
+ *                        be NULL
+ * @param[in] offset_func_pvt Private data for offset_func and
+ *                        rev_offset_func, may be NULL
+ * @param[in] shift       Currently not used, might become important when we
+ *                        allow multiple ranges for a single domain
+ * @param[in] external_mapping Indicates that for this domain the mapping
+ *                        should not be done by libsss_idmap, the related
+ *                        calls will return IDMAP_EXTERNAL in this case.
+ *                        Nevertheless it might be important to add the domain
+ *                        to the idmap context so that libsss_idmap will not
+ *                        use the related ranges for mapping.
+ *
+ * @return
+ *  - #IDMAP_OUT_OF_MEMORY: Insufficient memory to store the data in the idmap
+ *                          context
+ *  - #IDMAP_SID_INVALID:   Invalid SID provided
+ *  - #IDMAP_NO_DOMAIN:     No domain domain name given
+ *  - #IDMAP_COLLISION:     New domain collides with existing one
+ */
+enum idmap_error_code sss_idmap_add_gen_domain_ex(struct sss_idmap_ctx *ctx,
+                                                  const char *domain_name,
+                                                  const char *domain_id,
+                                                  struct sss_idmap_range *range,
+                                                  const char *range_id,
+                                                  idmap_offset_func *offset_func,
+                                                  idmap_rev_offset_func *rev_offset_func,
+                                                  void *offset_func_pvt,
+                                                  uint32_t shift,
+                                                  bool external_mapping);
+
+/**
+ * @brief Calculate offset from string containing only numbers
+ */
+enum idmap_error_code offset_identity(void *pvt, uint32_t range_size,
+                                      const char *input, long long *offset);
+
+/**
+ * @brief Reverse of offset_identity, return a string containing only numbers
+ * representing the given offset
+ */
+enum idmap_error_code rev_offset_identity(struct sss_idmap_ctx *ctx, void *pvt,
+                                          uint32_t id, char **_out);
+
+/**
+ * @brief Calculate offset from string with the help of murmurhash3
+ */
+enum idmap_error_code offset_murmurhash3(void *pvt, uint32_t range_size,
+                                         const char *input, long long *offset);
+
+/**
+ * Structure for private data for offset_murmurhash3. If not given 0xdeadbeef
+ * will be used as seed. UTF8 strings will be normalized by default but not
+ * casefolded.
+ */
+struct offset_murmurhash3_data {
+    uint32_t seed;
+    bool normalize;
+    bool casefold;
+};
+
+/**
+ * @brief Translate some input to a unix UID or GID
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] domain_id Zero-terminated string with the domain ID of a known
+ *                      domain
+ * @param[in] input     Zero-terminated string which should be translated into
+ *                      an offset to calculate the unix UID or GID
+ * @param[out] id       Returned unix UID or GID
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domain with domain_id found in ctx
+ *  - #IDMAP_EXTERNAL:      external source is authoritative for mapping
+ */
+enum idmap_error_code sss_idmap_gen_to_unix(struct sss_idmap_ctx *ctx,
+                                            const char *domain_id,
+                                            const char *input,
+                                            uint32_t *_id);
+
+/**
+ * @brief Translate some input to a unix UID or GID
+ *
+ * @param[in] ctx       Idmap context
+ * @param[in] id        UNIX UID or GID
+ *                      an offset to calculate the unix UID or GID
+ * @param[out] out      Original value the UID or GID was derived from
+ *
+ * @return
+ *  - #IDMAP_NO_DOMAIN:     No domain with domain_id found in ctx
+ *  - #IDMAP_EXTERNAL:      external source is authoritative for mapping
+ *  - #IDMAP_NO_REVERSE:    the id cannot be reverted back to the original
+ *                          source
+ */
+enum idmap_error_code sss_idmap_unix_to_gen(struct sss_idmap_ctx *ctx,
+                                            uint32_t id,
+                                            char **out);
+
+/**
+ * @}
+ */
+#endif /* SSS_IDMAP_H_ */
diff --git a/himmelblaud/idmap/src/sss_idmap_conv.c b/himmelblaud/idmap/src/sss_idmap_conv.c
new file mode 100644 (file)
index 0000000..bd3148d
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+    SSSD
+
+    ID-mapping library - conversion utilities
+
+    Authors:
+        Sumit Bose <sbose@redhat.com>
+
+    Copyright (C) 2012 Red Hat
+
+    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 <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "sss_idmap.h"
+#include "sss_idmap_private.h"
+//#include "util/util.h"
+//#include "util/sss_endian.h"
+#include "util.h"
+
+#define SID_ID_AUTHS 6
+#define SID_SUB_AUTHS 15
+struct sss_dom_sid {
+        uint8_t sid_rev_num;
+        int8_t num_auths;                  /* [range(0,15)] */
+        uint8_t id_auth[SID_ID_AUTHS];     /* highest order byte has index 0 */
+        uint32_t sub_auths[SID_SUB_AUTHS]; /* host byte-order */
+};
+
+enum idmap_error_code sss_idmap_bin_sid_to_dom_sid(struct sss_idmap_ctx *ctx,
+                                                   const uint8_t *bin_sid,
+                                                   size_t length,
+                                                   struct sss_dom_sid **_dom_sid)
+{
+    enum idmap_error_code err;
+    struct sss_dom_sid *dom_sid;
+    size_t i = 0;
+    size_t p = 0;
+    uint32_t val;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (length > sizeof(struct sss_dom_sid)) return IDMAP_SID_INVALID;
+
+    dom_sid = ctx->alloc_func(sizeof(struct sss_dom_sid), ctx->alloc_pvt);
+    if (dom_sid == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+    memset(dom_sid, 0, sizeof(struct sss_dom_sid));
+
+    /* Safely copy in the SID revision number */
+    dom_sid->sid_rev_num = (uint8_t) *(bin_sid + p);
+    p++;
+
+    /* Safely copy in the number of sub auth values */
+    dom_sid->num_auths = (uint8_t) *(bin_sid + p);
+    p++;
+
+    /* Make sure we aren't being told to read more bin_sid
+     * than can fit in the structure
+     */
+    if (dom_sid->num_auths > SID_SUB_AUTHS) {
+        err = IDMAP_SID_INVALID;
+        goto done;
+    }
+
+    /* Safely copy in the id_auth values */
+    for (i = 0; i < SID_ID_AUTHS; i++) {
+        dom_sid->id_auth[i] = (uint8_t) *(bin_sid + p);
+        p++;
+    }
+
+    /* Safely copy in the sub_auths values */
+    for (i = 0; i < dom_sid->num_auths; i++) {
+        /* SID sub auth values in Active Directory are stored little-endian,
+         * we store them in host order */
+        SAFEALIGN_COPY_UINT32(&val, bin_sid + p, &p);
+        dom_sid->sub_auths[i] = le32toh(val);
+    }
+
+    *_dom_sid = dom_sid;
+    err = IDMAP_SUCCESS;
+
+done:
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(dom_sid, ctx->alloc_pvt);
+    }
+    return err;
+}
+
+enum idmap_error_code sss_idmap_dom_sid_to_bin_sid(struct sss_idmap_ctx *ctx,
+                                                   struct sss_dom_sid *dom_sid,
+                                                   uint8_t **_bin_sid,
+                                                   size_t *_length)
+{
+    enum idmap_error_code err;
+    uint8_t *bin_sid;
+    size_t length;
+    size_t i = 0;
+    size_t p = 0;
+    uint32_t val;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (dom_sid->num_auths > SID_SUB_AUTHS) {
+        return IDMAP_SID_INVALID;
+    }
+
+    length = 2 + SID_ID_AUTHS + dom_sid->num_auths * 4;
+
+    bin_sid = ctx->alloc_func(length, ctx->alloc_pvt);
+    if (bin_sid == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+
+    bin_sid[p] = dom_sid->sid_rev_num;
+    p++;
+
+    bin_sid[p] = dom_sid->num_auths;
+    p++;
+
+    for (i = 0; i < SID_ID_AUTHS; i++) {
+        bin_sid[p] = dom_sid->id_auth[i];
+        p++;
+    }
+
+    for (i = 0; i < dom_sid->num_auths; i++) {
+        if (p + sizeof(uint32_t) > length) {
+            err = IDMAP_SID_INVALID;
+            goto done;
+        }
+        val = htole32(dom_sid->sub_auths[i]);
+        SAFEALIGN_COPY_UINT32(bin_sid + p, &val, &p);
+    }
+
+    *_bin_sid = bin_sid;
+    *_length = length;
+
+    err = IDMAP_SUCCESS;
+done:
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(bin_sid, ctx->alloc_pvt);
+    }
+    return err;
+}
+
+enum idmap_error_code sss_idmap_dom_sid_to_sid(struct sss_idmap_ctx *ctx,
+                                               struct sss_dom_sid *dom_sid,
+                                               char **_sid)
+{
+    enum idmap_error_code err;
+    char *sid_buf;
+    size_t sid_buf_len;
+    char *p;
+    int nc;
+    int8_t i;
+    uint32_t id_auth_val = 0;
+
+    if (dom_sid->num_auths > SID_SUB_AUTHS) {
+        return IDMAP_SID_INVALID;
+    }
+
+    sid_buf_len = 25 + dom_sid->num_auths * 11;
+    sid_buf = ctx->alloc_func(sid_buf_len, ctx->alloc_pvt);
+    if (sid_buf == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+    memset(sid_buf, 0, sid_buf_len);
+
+    /* Only 32bits are used for the string representation */
+    id_auth_val = (dom_sid->id_auth[2] << 24) +
+                  (dom_sid->id_auth[3] << 16) +
+                  (dom_sid->id_auth[4] << 8) +
+                  (dom_sid->id_auth[5]);
+
+    nc = snprintf(sid_buf, sid_buf_len, "S-%u-%lu", dom_sid->sid_rev_num,
+                                                    (unsigned long) id_auth_val);
+    if (nc < 0 || nc >= sid_buf_len) {
+        err = IDMAP_SID_INVALID;
+        goto done;
+    }
+
+
+    /* Loop through the sub-auths, if any, prepending a hyphen
+     * for each one.
+     */
+    p = sid_buf;
+    for (i = 0; i < dom_sid->num_auths ; i++) {
+        p += nc;
+        sid_buf_len -= nc;
+
+        nc = snprintf(p, sid_buf_len, "-%lu",
+                                      (unsigned long) dom_sid->sub_auths[i]);
+        if (nc < 0 || nc >= sid_buf_len) {
+            err = IDMAP_SID_INVALID;
+            goto done;
+        }
+    }
+
+    *_sid = sid_buf;
+    err = IDMAP_SUCCESS;
+
+done:
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(sid_buf, ctx->alloc_pvt);
+    }
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_sid_to_dom_sid(struct sss_idmap_ctx *ctx,
+                                               const char *sid,
+                                               struct sss_dom_sid **_dom_sid)
+{
+    enum idmap_error_code err;
+    unsigned long ul;
+    char *r;
+    char *end;
+    struct sss_dom_sid *dom_sid;
+
+    CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
+
+    if (sid == NULL || (sid[0] != 'S' && sid[0] != 's') || sid[1] != '-') {
+            return IDMAP_SID_INVALID;
+    }
+
+    dom_sid = ctx->alloc_func(sizeof(struct sss_dom_sid), ctx->alloc_pvt);
+    if (dom_sid == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+    memset(dom_sid, 0, sizeof(struct sss_dom_sid));
+
+
+    if (!isdigit(sid[2])) {
+        err = IDMAP_SID_INVALID;
+        goto done;
+    }
+    errno = 0;
+    ul = strtoul(sid + 2, &r, 10);
+    if (errno != 0 || r == NULL || *r != '-' || ul > UINT8_MAX) {
+        err = IDMAP_SID_INVALID;
+        goto done;
+    }
+    dom_sid->sid_rev_num = (uint8_t) ul;
+    r++;
+
+    if (!isdigit(*r)) {
+        err = IDMAP_SID_INVALID;
+        goto done;
+    }
+    errno = 0;
+    ul = strtoul(r, &r, 10);
+    if (errno != 0 || r == NULL || ul > UINT32_MAX) {
+        err = IDMAP_SID_INVALID;
+        goto done;
+    }
+
+    /* id_auth in the string should always be <2^32 in decimal */
+    /* store values in the same order as the binary representation */
+    dom_sid->id_auth[0] = 0;
+    dom_sid->id_auth[1] = 0;
+    dom_sid->id_auth[2] = (ul & 0xff000000) >> 24;
+    dom_sid->id_auth[3] = (ul & 0x00ff0000) >> 16;
+    dom_sid->id_auth[4] = (ul & 0x0000ff00) >> 8;
+    dom_sid->id_auth[5] = (ul & 0x000000ff);
+
+    if (*r == '\0') {
+        /* no sub auths given */
+        err = IDMAP_SUCCESS;
+        goto done;
+    }
+
+    if (*r != '-') {
+        err = IDMAP_SID_INVALID;
+        goto done;
+    }
+
+    do {
+        if (dom_sid->num_auths >= SID_SUB_AUTHS) {
+            err = IDMAP_SID_INVALID;
+            goto done;
+        }
+
+        r++;
+        if (!isdigit(*r)) {
+            err = IDMAP_SID_INVALID;
+            goto done;
+        }
+
+        errno = 0;
+        ul = strtoul(r, &end, 10);
+        if (errno != 0 || ul > UINT32_MAX || end == NULL ||
+            (*end != '\0' && *end != '-')) {
+            err = IDMAP_SID_INVALID;
+            goto done;
+        }
+
+        dom_sid->sub_auths[dom_sid->num_auths++] = ul;
+
+        r = end;
+    } while (*r != '\0');
+
+    err = IDMAP_SUCCESS;
+
+done:
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(dom_sid, ctx->alloc_pvt);
+    } else {
+        *_dom_sid = dom_sid;
+    }
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_sid_to_bin_sid(struct sss_idmap_ctx *ctx,
+                                               const char *sid,
+                                               uint8_t **_bin_sid,
+                                               size_t *_length)
+{
+    enum idmap_error_code err;
+    struct sss_dom_sid *dom_sid = NULL;
+    size_t length;
+    uint8_t *bin_sid = NULL;
+
+    err = sss_idmap_sid_to_dom_sid(ctx, sid, &dom_sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_dom_sid_to_bin_sid(ctx, dom_sid, &bin_sid, &length);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    *_length = length;
+    *_bin_sid = bin_sid;
+    err = IDMAP_SUCCESS;
+
+done:
+    ctx->free_func(dom_sid, ctx->alloc_pvt);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(bin_sid, ctx->alloc_pvt);
+    }
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_bin_sid_to_sid(struct sss_idmap_ctx *ctx,
+                                               const uint8_t *bin_sid,
+                                               size_t length,
+                                               char **_sid)
+{
+    enum idmap_error_code err;
+    struct sss_dom_sid *dom_sid = NULL;
+    char *sid = NULL;
+
+    err = sss_idmap_bin_sid_to_dom_sid(ctx, bin_sid, length, &dom_sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    *_sid = sid;
+    err = IDMAP_SUCCESS;
+
+done:
+    ctx->free_func(dom_sid, ctx->alloc_pvt);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(sid, ctx->alloc_pvt);
+    }
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_sid_to_smb_sid(struct sss_idmap_ctx *ctx,
+                                               const char *sid,
+                                               struct dom_sid **_smb_sid)
+{
+    enum idmap_error_code err;
+    struct sss_dom_sid *dom_sid = NULL;
+    struct dom_sid *smb_sid = NULL;
+
+    err = sss_idmap_sid_to_dom_sid(ctx, sid, &dom_sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_dom_sid_to_smb_sid(ctx, dom_sid, &smb_sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    *_smb_sid = smb_sid;
+    err = IDMAP_SUCCESS;
+
+done:
+    ctx->free_func(dom_sid, ctx->alloc_pvt);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(smb_sid, ctx->alloc_pvt);
+    }
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_smb_sid_to_sid(struct sss_idmap_ctx *ctx,
+                                               struct dom_sid *smb_sid,
+                                               char **_sid)
+{
+    enum idmap_error_code err;
+    struct sss_dom_sid *dom_sid = NULL;
+    char *sid = NULL;
+
+    err = sss_idmap_smb_sid_to_dom_sid(ctx, smb_sid, &dom_sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    *_sid = sid;
+    err = IDMAP_SUCCESS;
+
+done:
+    ctx->free_func(dom_sid, ctx->alloc_pvt);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(sid, ctx->alloc_pvt);
+    }
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_dom_sid_to_smb_sid(struct sss_idmap_ctx *ctx,
+                                                   struct sss_dom_sid *dom_sid,
+                                                   struct dom_sid **_smb_sid)
+{
+    struct dom_sid *smb_sid;
+    size_t c;
+
+    smb_sid = ctx->alloc_func(sizeof(struct dom_sid), ctx->alloc_pvt);
+    if (smb_sid == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+    memset(smb_sid, 0, sizeof(struct dom_sid));
+
+    smb_sid->sid_rev_num = dom_sid->sid_rev_num;
+    smb_sid->num_auths = dom_sid->num_auths;
+    for (c = 0; c < SID_ID_AUTHS; c++) {
+        smb_sid->id_auth[c] = dom_sid->id_auth[c];
+    }
+    for (c = 0; c < SID_SUB_AUTHS; c++) {
+        smb_sid->sub_auths[c] = dom_sid->sub_auths[c];
+    }
+
+    *_smb_sid = smb_sid;
+
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code sss_idmap_smb_sid_to_dom_sid(struct sss_idmap_ctx *ctx,
+                                                   struct dom_sid *smb_sid,
+                                                   struct sss_dom_sid **_dom_sid)
+{
+    struct sss_dom_sid *dom_sid;
+    size_t c;
+
+    dom_sid = ctx->alloc_func(sizeof(struct sss_dom_sid), ctx->alloc_pvt);
+    if (dom_sid == NULL) {
+        return IDMAP_OUT_OF_MEMORY;
+    }
+    memset(dom_sid, 0, sizeof(struct sss_dom_sid));
+
+    dom_sid->sid_rev_num = smb_sid->sid_rev_num;
+    dom_sid->num_auths = smb_sid->num_auths;
+    for (c = 0; c < SID_ID_AUTHS; c++) {
+        dom_sid->id_auth[c] = smb_sid->id_auth[c];
+    }
+    for (c = 0; c < SID_SUB_AUTHS; c++) {
+        dom_sid->sub_auths[c] = smb_sid->sub_auths[c];
+    }
+
+    *_dom_sid = dom_sid;
+
+    return IDMAP_SUCCESS;
+}
+
+enum idmap_error_code sss_idmap_bin_sid_to_smb_sid(struct sss_idmap_ctx *ctx,
+                                                   const uint8_t *bin_sid,
+                                                   size_t length,
+                                                   struct dom_sid **_smb_sid)
+{
+    enum idmap_error_code err;
+    struct sss_dom_sid *dom_sid = NULL;
+    struct dom_sid *smb_sid = NULL;
+
+    err = sss_idmap_bin_sid_to_dom_sid(ctx, bin_sid, length, &dom_sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_dom_sid_to_smb_sid(ctx, dom_sid, &smb_sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    *_smb_sid = smb_sid;
+    err = IDMAP_SUCCESS;
+
+done:
+    ctx->free_func(dom_sid, ctx->alloc_pvt);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(smb_sid, ctx->alloc_pvt);
+    }
+
+    return err;
+}
+
+enum idmap_error_code sss_idmap_smb_sid_to_bin_sid(struct sss_idmap_ctx *ctx,
+                                                   struct dom_sid *smb_sid,
+                                                   uint8_t **_bin_sid,
+                                                   size_t *_length)
+{
+    enum idmap_error_code err;
+    struct sss_dom_sid *dom_sid = NULL;
+    uint8_t *bin_sid = NULL;
+    size_t length;
+
+    err = sss_idmap_smb_sid_to_dom_sid(ctx, smb_sid, &dom_sid);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    err = sss_idmap_dom_sid_to_bin_sid(ctx, dom_sid, &bin_sid, &length);
+    if (err != IDMAP_SUCCESS) {
+        goto done;
+    }
+
+    *_bin_sid = bin_sid;
+    *_length = length;
+    err = IDMAP_SUCCESS;
+
+done:
+    ctx->free_func(dom_sid, ctx->alloc_pvt);
+    if (err != IDMAP_SUCCESS) {
+        ctx->free_func(bin_sid, ctx->alloc_pvt);
+    }
+
+    return err;
+}
diff --git a/himmelblaud/idmap/src/sss_idmap_private.h b/himmelblaud/idmap/src/sss_idmap_private.h
new file mode 100644 (file)
index 0000000..15300d1
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+    SSSD
+
+    ID-mapping library - private headers
+
+    Authors:
+        Sumit Bose <sbose@redhat.com>
+
+    Copyright (C) 2012 Red Hat
+
+    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 SSS_IDMAP_PRIVATE_H_
+#define SSS_IDMAP_PRIVATE_H_
+
+#define SSS_IDMAP_DEFAULT_LOWER 200000
+#define SSS_IDMAP_DEFAULT_UPPER 2000200000
+#define SSS_IDMAP_DEFAULT_RANGESIZE 200000
+#define SSS_IDMAP_DEFAULT_AUTORID false
+#define SSS_IDMAP_DEFAULT_EXTRA_SLICE_INIT 10
+
+#define CHECK_IDMAP_CTX(ctx, ret) do { \
+    if (ctx == NULL || ctx->alloc_func == NULL || ctx->free_func == NULL) { \
+        return ret; \
+    } \
+} while(0)
+
+struct sss_idmap_opts {
+    /* true if autorid compatibility mode is used */
+    bool autorid_mode;
+
+    /* smallest available id (for all domains) */
+    id_t idmap_lower;
+
+    /* highest available id (for all domains) */
+    id_t idmap_upper;
+
+    /* number of available UIDs (for single domain) */
+    id_t rangesize;
+
+    /* maximal number of secondary slices */
+    int extra_slice_init;
+};
+
+struct sss_idmap_ctx {
+    idmap_alloc_func *alloc_func;
+    void *alloc_pvt;
+    idmap_free_func *free_func;
+    struct sss_idmap_opts idmap_opts;
+    struct idmap_domain_info *idmap_domain_info;
+};
+
+/* This is a copy of the definition in the samba gen_ndr/security.h header
+ * file. We use it here to be able to offer conversions form struct dom_sid to
+ * string or binary representation since those are not made available by
+ * public samba libraries.
+ *
+ * If the definition ever changes on the samba side we have to adopt the
+ * change. But chances are very low that this will ever happen since e.g. this
+ * struct is also defined in public documentation from Microsoft. See e.g.
+ * section 2.4.2.3 of "[MS-DTYP]: Windows Data Types"
+ * http://msdn.microsoft.com/en-us/library/cc230364(v=prot.10)
+ */
+
+struct dom_sid {
+        uint8_t sid_rev_num;
+        int8_t num_auths;
+        uint8_t id_auth[6];
+        uint32_t sub_auths[15];
+};
+
+#endif /* SSS_IDMAP_PRIVATE_H_ */
diff --git a/himmelblaud/idmap/src/util.h b/himmelblaud/idmap/src/util.h
new file mode 100644 (file)
index 0000000..12d4cf9
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+   Himmelblaud
+
+   ID-mapping library utils
+
+   Copyright (C) David Mulder 2024
+
+   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 _UTILS_H
+#define _UTILS_H
+
+#include <string.h>
+#include <stdint.h>
+
+static inline void
+safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter)
+{
+    memcpy(dest, src, n);
+    if (counter) {
+        *counter += n;
+    }
+}
+
+#define SAFEALIGN_COPY_UINT32(dest, src, pctr) \
+    safealign_memcpy(dest, src, sizeof(uint32_t), pctr)
+
+#if defined(__GNUC__) && __GNUC__ >= 7
+ #define SSS_ATTRIBUTE_FALLTHROUGH __attribute__ ((fallthrough))
+#else
+ #define SSS_ATTRIBUTE_FALLTHROUGH
+#endif
+
+#endif /* _UTILS_H */