diff --git a/.gitlab-ci-main.yml b/.gitlab-ci-main.yml
index 52d50f1c58b..263d160a08d 100644
--- a/.gitlab-ci-main.yml
+++ b/.gitlab-ci-main.yml
@@ -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
diff --git a/bootstrap/config.py b/bootstrap/config.py
index 1f0eba24b0b..d862ef407d2 100644
--- a/bootstrap/config.py
+++ b/bootstrap/config.py
@@ -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'),
diff --git a/bootstrap/generated-dists/centos9s/bootstrap.sh b/bootstrap/generated-dists/centos9s/bootstrap.sh
index d4684e9cf47..926a76f5d50 100755
--- a/bootstrap/generated-dists/centos9s/bootstrap.sh
+++ b/bootstrap/generated-dists/centos9s/bootstrap.sh
@@ -116,6 +116,7 @@ dnf install -y \
tar \
tracker-devel \
tree \
+ utf8proc-devel \
wget \
which \
xfsprogs-devel \
diff --git a/bootstrap/generated-dists/centos9s/packages.yml b/bootstrap/generated-dists/centos9s/packages.yml
index 22f79700ddf..c218584e723 100644
--- a/bootstrap/generated-dists/centos9s/packages.yml
+++ b/bootstrap/generated-dists/centos9s/packages.yml
@@ -97,6 +97,7 @@ packages:
- tar
- tracker-devel
- tree
+ - utf8proc-devel
- wget
- which
- xfsprogs-devel
diff --git a/bootstrap/generated-dists/debian11-32bit/bootstrap.sh b/bootstrap/generated-dists/debian11-32bit/bootstrap.sh
index db982ada067..4a4ee8cd706 100755
--- a/bootstrap/generated-dists/debian11-32bit/bootstrap.sh
+++ b/bootstrap/generated-dists/debian11-32bit/bootstrap.sh
@@ -75,6 +75,7 @@ apt-get -y install \
libtracker-sparql-2.0-dev \
libunwind-dev \
liburing-dev \
+ libutf8proc-dev \
lmdb-utils \
locales \
lsb-release \
diff --git a/bootstrap/generated-dists/debian11-32bit/packages.yml b/bootstrap/generated-dists/debian11-32bit/packages.yml
index 492344da465..ef6b863e35e 100644
--- a/bootstrap/generated-dists/debian11-32bit/packages.yml
+++ b/bootstrap/generated-dists/debian11-32bit/packages.yml
@@ -64,6 +64,7 @@ packages:
- libtracker-sparql-2.0-dev
- libunwind-dev
- liburing-dev
+ - libutf8proc-dev
- lmdb-utils
- locales
- lsb-release
diff --git a/bootstrap/generated-dists/debian11/bootstrap.sh b/bootstrap/generated-dists/debian11/bootstrap.sh
index db982ada067..4a4ee8cd706 100755
--- a/bootstrap/generated-dists/debian11/bootstrap.sh
+++ b/bootstrap/generated-dists/debian11/bootstrap.sh
@@ -75,6 +75,7 @@ apt-get -y install \
libtracker-sparql-2.0-dev \
libunwind-dev \
liburing-dev \
+ libutf8proc-dev \
lmdb-utils \
locales \
lsb-release \
diff --git a/bootstrap/generated-dists/debian11/packages.yml b/bootstrap/generated-dists/debian11/packages.yml
index 492344da465..ef6b863e35e 100644
--- a/bootstrap/generated-dists/debian11/packages.yml
+++ b/bootstrap/generated-dists/debian11/packages.yml
@@ -64,6 +64,7 @@ packages:
- libtracker-sparql-2.0-dev
- libunwind-dev
- liburing-dev
+ - libutf8proc-dev
- lmdb-utils
- locales
- lsb-release
diff --git a/bootstrap/generated-dists/debian12-32bit/bootstrap.sh b/bootstrap/generated-dists/debian12-32bit/bootstrap.sh
index e85b15d6692..38b3c4777af 100755
--- a/bootstrap/generated-dists/debian12-32bit/bootstrap.sh
+++ b/bootstrap/generated-dists/debian12-32bit/bootstrap.sh
@@ -74,6 +74,7 @@ apt-get -y install \
libtasn1-dev \
libunwind-dev \
liburing-dev \
+ libutf8proc-dev \
lmdb-utils \
locales \
lsb-release \
diff --git a/bootstrap/generated-dists/debian12-32bit/packages.yml b/bootstrap/generated-dists/debian12-32bit/packages.yml
index b2a027541f1..bbc9d814fc7 100644
--- a/bootstrap/generated-dists/debian12-32bit/packages.yml
+++ b/bootstrap/generated-dists/debian12-32bit/packages.yml
@@ -63,6 +63,7 @@ packages:
- libtasn1-dev
- libunwind-dev
- liburing-dev
+ - libutf8proc-dev
- lmdb-utils
- locales
- lsb-release
diff --git a/bootstrap/generated-dists/debian12/bootstrap.sh b/bootstrap/generated-dists/debian12/bootstrap.sh
index e85b15d6692..38b3c4777af 100755
--- a/bootstrap/generated-dists/debian12/bootstrap.sh
+++ b/bootstrap/generated-dists/debian12/bootstrap.sh
@@ -74,6 +74,7 @@ apt-get -y install \
libtasn1-dev \
libunwind-dev \
liburing-dev \
+ libutf8proc-dev \
lmdb-utils \
locales \
lsb-release \
diff --git a/bootstrap/generated-dists/debian12/packages.yml b/bootstrap/generated-dists/debian12/packages.yml
index b2a027541f1..bbc9d814fc7 100644
--- a/bootstrap/generated-dists/debian12/packages.yml
+++ b/bootstrap/generated-dists/debian12/packages.yml
@@ -63,6 +63,7 @@ packages:
- libtasn1-dev
- libunwind-dev
- liburing-dev
+ - libutf8proc-dev
- lmdb-utils
- locales
- lsb-release
diff --git a/bootstrap/generated-dists/fedora40/bootstrap.sh b/bootstrap/generated-dists/fedora40/bootstrap.sh
index 99aad7c8c27..d794591986b 100755
--- a/bootstrap/generated-dists/fedora40/bootstrap.sh
+++ b/bootstrap/generated-dists/fedora40/bootstrap.sh
@@ -115,6 +115,7 @@ dnf install -y \
tar \
tracker-devel \
tree \
+ utf8proc-devel \
wget \
which \
xfsprogs-devel \
diff --git a/bootstrap/generated-dists/fedora40/packages.yml b/bootstrap/generated-dists/fedora40/packages.yml
index 7bdb86e11b4..2596611c5f3 100644
--- a/bootstrap/generated-dists/fedora40/packages.yml
+++ b/bootstrap/generated-dists/fedora40/packages.yml
@@ -104,6 +104,7 @@ packages:
- tar
- tracker-devel
- tree
+ - utf8proc-devel
- wget
- which
- xfsprogs-devel
diff --git a/bootstrap/generated-dists/opensuse155/bootstrap.sh b/bootstrap/generated-dists/opensuse155/bootstrap.sh
index 687f30ff7be..adfa8615500 100755
--- a/bootstrap/generated-dists/opensuse155/bootstrap.sh
+++ b/bootstrap/generated-dists/opensuse155/bootstrap.sh
@@ -107,6 +107,7 @@ zypper --non-interactive install \
tar \
tracker-devel \
tree \
+ utf8proc-devel \
wget \
which \
xfsprogs-devel \
diff --git a/bootstrap/generated-dists/opensuse155/packages.yml b/bootstrap/generated-dists/opensuse155/packages.yml
index ca1a96efebd..05ebdf739d8 100644
--- a/bootstrap/generated-dists/opensuse155/packages.yml
+++ b/bootstrap/generated-dists/opensuse155/packages.yml
@@ -95,6 +95,7 @@ packages:
- tar
- tracker-devel
- tree
+ - utf8proc-devel
- wget
- which
- xfsprogs-devel
diff --git a/bootstrap/generated-dists/rocky8/bootstrap.sh b/bootstrap/generated-dists/rocky8/bootstrap.sh
index 639ab513ecd..39dca159979 100755
--- a/bootstrap/generated-dists/rocky8/bootstrap.sh
+++ b/bootstrap/generated-dists/rocky8/bootstrap.sh
@@ -116,6 +116,7 @@ yum install -y \
tar \
tracker-devel \
tree \
+ utf8proc-devel \
wget \
which \
xfsprogs-devel \
diff --git a/bootstrap/generated-dists/rocky8/packages.yml b/bootstrap/generated-dists/rocky8/packages.yml
index bc34825f9ac..4be31034442 100644
--- a/bootstrap/generated-dists/rocky8/packages.yml
+++ b/bootstrap/generated-dists/rocky8/packages.yml
@@ -98,6 +98,7 @@ packages:
- tar
- tracker-devel
- tree
+ - utf8proc-devel
- wget
- which
- xfsprogs-devel
diff --git a/bootstrap/generated-dists/ubuntu1804-32bit/bootstrap.sh b/bootstrap/generated-dists/ubuntu1804-32bit/bootstrap.sh
index b74a5e0e7e1..607da6b4eae 100755
--- a/bootstrap/generated-dists/ubuntu1804-32bit/bootstrap.sh
+++ b/bootstrap/generated-dists/ubuntu1804-32bit/bootstrap.sh
@@ -75,6 +75,7 @@ apt-get -y install \
libtasn1-dev \
libtracker-sparql-2.0-dev \
libunwind-dev \
+ libutf8proc-dev \
lmdb-utils \
locales \
lsb-release \
diff --git a/bootstrap/generated-dists/ubuntu1804-32bit/packages.yml b/bootstrap/generated-dists/ubuntu1804-32bit/packages.yml
index bca52528f6b..80dd35cc204 100644
--- a/bootstrap/generated-dists/ubuntu1804-32bit/packages.yml
+++ b/bootstrap/generated-dists/ubuntu1804-32bit/packages.yml
@@ -64,6 +64,7 @@ packages:
- libtasn1-dev
- libtracker-sparql-2.0-dev
- libunwind-dev
+ - libutf8proc-dev
- lmdb-utils
- locales
- lsb-release
diff --git a/bootstrap/generated-dists/ubuntu1804/bootstrap.sh b/bootstrap/generated-dists/ubuntu1804/bootstrap.sh
index b74a5e0e7e1..607da6b4eae 100755
--- a/bootstrap/generated-dists/ubuntu1804/bootstrap.sh
+++ b/bootstrap/generated-dists/ubuntu1804/bootstrap.sh
@@ -75,6 +75,7 @@ apt-get -y install \
libtasn1-dev \
libtracker-sparql-2.0-dev \
libunwind-dev \
+ libutf8proc-dev \
lmdb-utils \
locales \
lsb-release \
diff --git a/bootstrap/generated-dists/ubuntu1804/packages.yml b/bootstrap/generated-dists/ubuntu1804/packages.yml
index bca52528f6b..80dd35cc204 100644
--- a/bootstrap/generated-dists/ubuntu1804/packages.yml
+++ b/bootstrap/generated-dists/ubuntu1804/packages.yml
@@ -64,6 +64,7 @@ packages:
- libtasn1-dev
- libtracker-sparql-2.0-dev
- libunwind-dev
+ - libutf8proc-dev
- lmdb-utils
- locales
- lsb-release
diff --git a/bootstrap/generated-dists/ubuntu2004/bootstrap.sh b/bootstrap/generated-dists/ubuntu2004/bootstrap.sh
index b74a5e0e7e1..607da6b4eae 100755
--- a/bootstrap/generated-dists/ubuntu2004/bootstrap.sh
+++ b/bootstrap/generated-dists/ubuntu2004/bootstrap.sh
@@ -75,6 +75,7 @@ apt-get -y install \
libtasn1-dev \
libtracker-sparql-2.0-dev \
libunwind-dev \
+ libutf8proc-dev \
lmdb-utils \
locales \
lsb-release \
diff --git a/bootstrap/generated-dists/ubuntu2004/packages.yml b/bootstrap/generated-dists/ubuntu2004/packages.yml
index bca52528f6b..80dd35cc204 100644
--- a/bootstrap/generated-dists/ubuntu2004/packages.yml
+++ b/bootstrap/generated-dists/ubuntu2004/packages.yml
@@ -64,6 +64,7 @@ packages:
- libtasn1-dev
- libtracker-sparql-2.0-dev
- libunwind-dev
+ - libutf8proc-dev
- lmdb-utils
- locales
- lsb-release
diff --git a/bootstrap/generated-dists/ubuntu2204/bootstrap.sh b/bootstrap/generated-dists/ubuntu2204/bootstrap.sh
index 72802d40cf1..fab68e8d7b6 100755
--- a/bootstrap/generated-dists/ubuntu2204/bootstrap.sh
+++ b/bootstrap/generated-dists/ubuntu2204/bootstrap.sh
@@ -75,6 +75,7 @@ apt-get -y install \
libtasn1-dev \
libunwind-dev \
liburing-dev \
+ libutf8proc-dev \
lmdb-utils \
locales \
lsb-release \
diff --git a/bootstrap/generated-dists/ubuntu2204/packages.yml b/bootstrap/generated-dists/ubuntu2204/packages.yml
index c58b08f9174..bd8052bbf44 100644
--- a/bootstrap/generated-dists/ubuntu2204/packages.yml
+++ b/bootstrap/generated-dists/ubuntu2204/packages.yml
@@ -64,6 +64,7 @@ packages:
- libtasn1-dev
- libunwind-dev
- liburing-dev
+ - libutf8proc-dev
- lmdb-utils
- locales
- lsb-release
diff --git a/bootstrap/sha1sum.txt b/bootstrap/sha1sum.txt
index cdb48c41715..cc706332405 100644
--- a/bootstrap/sha1sum.txt
+++ b/bootstrap/sha1sum.txt
@@ -1 +1 @@
-8845099b492ab9888181df3e094e00ae8916ddb7
+2a20df752f162f9d1f617af785e463fa39944c6e
diff --git a/himmelblaud/Cargo.toml b/himmelblaud/Cargo.toml
index 8261b59dea5..4206e498c0f 100644
--- a/himmelblaud/Cargo.toml
+++ b/himmelblaud/Cargo.toml
@@ -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
index 00000000000..6d81b43b308
--- /dev/null
+++ b/himmelblaud/idmap/Cargo.toml
@@ -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
index 00000000000..c24090c3a54
--- /dev/null
+++ b/himmelblaud/idmap/build.rs
@@ -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
index 00000000000..7e9e236649a
--- /dev/null
+++ b/himmelblaud/idmap/src/lib.rs
@@ -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 .
+*/
+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>,
+}
+
+impl Idmap {
+ pub fn new() -> Result {
+ 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 {
+ 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 = 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
index 00000000000..f0ccd929627
--- /dev/null
+++ b/himmelblaud/idmap/src/murmurhash3.c
@@ -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
+#include
+#include
+
+#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
index 00000000000..27671831c47
--- /dev/null
+++ b/himmelblaud/idmap/src/murmurhash3.h
@@ -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
+
+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
index 00000000000..4da1d0df4e5
--- /dev/null
+++ b/himmelblaud/idmap/src/sss_idmap.c
@@ -0,0 +1,1909 @@
+/*
+ SSSD
+
+ ID-mapping library
+
+ Authors:
+ Sumit Bose
+
+ 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 .
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#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
index 00000000000..a94c07f3bdf
--- /dev/null
+++ b/himmelblaud/idmap/src/sss_idmap.h
@@ -0,0 +1,1100 @@
+/*
+ SSSD
+
+ ID-mapping library
+
+ Authors:
+ Sumit Bose
+
+ 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 .
+*/
+
+#ifndef SSS_IDMAP_H_
+#define SSS_IDMAP_H_
+
+#include
+#include
+#include
+#include
+
+#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
index 00000000000..bd3148d4e90
--- /dev/null
+++ b/himmelblaud/idmap/src/sss_idmap_conv.c
@@ -0,0 +1,570 @@
+/*
+ SSSD
+
+ ID-mapping library - conversion utilities
+
+ Authors:
+ Sumit Bose
+
+ 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 .
+*/
+
+#include
+#include
+#include
+#include
+
+#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
index 00000000000..15300d11fc5
--- /dev/null
+++ b/himmelblaud/idmap/src/sss_idmap_private.h
@@ -0,0 +1,84 @@
+/*
+ SSSD
+
+ ID-mapping library - private headers
+
+ Authors:
+ Sumit Bose
+
+ 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 .
+*/
+
+#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
index 00000000000..12d4cf9663e
--- /dev/null
+++ b/himmelblaud/idmap/src/util.h
@@ -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 .
+*/
+
+#ifndef _UTILS_H
+#define _UTILS_H
+
+#include
+#include
+
+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 */