2 Unix SMB/CIFS implementation.
4 idmap script backend, used for Samba setups where you need to map SIDs to
7 Copyright (C) Richard Sharpe 2014.
9 This is heavily based upon idmap_tdb2.c, which is:
11 Copyright (C) Tim Potter 2000
12 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
13 Copyright (C) Jeremy Allison 2006
14 Copyright (C) Simo Sorce 2003-2006
15 Copyright (C) Michael Adam 2009-2010
17 This program is free software; you can redistribute it and/or modify
18 it under the terms of the GNU General Public License as published by
19 the Free Software Foundation; either version 2 of the License, or
20 (at your option) any later version.
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program; if not, write to the Free Software
29 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 #include "system/filesys.h"
37 #include "../libcli/security/dom_sid.h"
40 #define DBGC_CLASS DBGC_IDMAP
42 struct idmap_script_context
{
43 const char *script
; /* script to provide idmaps */
47 run a script to perform a mapping
49 The script should accept the following command lines:
51 SIDTOID S-1-xxxx -> XID:<id> | ERR:<str>
52 SIDTOID S-1-xxxx -> UID:<id> | ERR:<str>
53 SIDTOID S-1-xxxx -> GID:<id> | ERR:<str>
54 IDTOSID XID xxxx -> SID:<sid> | ERR:<str>
55 IDTOSID UID xxxx -> SID:<sid> | ERR:<str>
56 IDTOSID GID xxxx -> SID:<sid> | ERR:<str>
58 where XID means both a UID and a GID. This is the case for ID_TYPE_BOTH.
60 TODO: Needs more validation ... like that we got a UID when we asked for one.
62 static NTSTATUS
idmap_script_script(struct idmap_script_context
*ctx
,
63 struct id_map
*map
, const char *fmt
, ...)
70 cmd
= talloc_asprintf(ctx
, "%s ", ctx
->script
);
72 DEBUG(10, ("Unable to allocate memory for the script command!\n"));
73 return NT_STATUS_NO_MEMORY
;
77 cmd
= talloc_vasprintf_append(cmd
, fmt
, ap
);
80 DEBUG(10, ("Unable to allocate memory for the script command!\n"));
81 return NT_STATUS_NO_MEMORY
;
84 lines
= file_lines_pload(cmd
, &numlines
);
87 return NT_STATUS_NONE_MAPPED
;
90 DEBUG(10,("idmap script gave %d lines, first: %s\n", numlines
,
93 if (sscanf(lines
[0], "XID:%lu", &v
) == 1) {
95 map
->xid
.type
= ID_TYPE_BOTH
;
96 } else if (sscanf(lines
[0], "UID:%lu", &v
) == 1) {
98 map
->xid
.type
= ID_TYPE_UID
;
99 } else if (sscanf(lines
[0], "GID:%lu", &v
) == 1) {
101 map
->xid
.type
= ID_TYPE_GID
;
102 } else if (strncmp(lines
[0], "SID:S-", 6) == 0) {
103 if (!string_to_sid(map
->sid
, &lines
[0][4])) {
104 DEBUG(0,("Bad SID in '%s' from idmap script %s\n",
105 lines
[0], ctx
->script
));
107 return NT_STATUS_NONE_MAPPED
;
110 DEBUG(0,("Bad reply '%s' from idmap script %s\n",
111 lines
[0], ctx
->script
));
113 return NT_STATUS_NONE_MAPPED
;
121 Single id to sid lookup function.
123 static NTSTATUS
idmap_script_id_to_sid(struct idmap_domain
*dom
,
129 struct idmap_script_context
*ctx
= dom
->private_data
;
132 return NT_STATUS_INVALID_PARAMETER
;
135 /* apply filters before checking */
136 if (!idmap_unix_id_is_in_range(map
->xid
.id
, dom
)) {
137 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
138 map
->xid
.id
, dom
->low_id
, dom
->high_id
));
139 return NT_STATUS_NONE_MAPPED
;
142 switch (map
->xid
.type
) {
145 keystr
= talloc_asprintf(ctx
, "UID %lu", (unsigned long)map
->xid
.id
);
149 keystr
= talloc_asprintf(ctx
, "GID %lu", (unsigned long)map
->xid
.id
);
153 keystr
= talloc_asprintf(ctx
, "XID %lu", (unsigned long)map
->xid
.id
);
157 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map
->xid
.type
));
158 return NT_STATUS_INVALID_PARAMETER
;
161 if (keystr
== NULL
) {
162 DEBUG(0, ("Out of memory!\n"));
163 ret
= NT_STATUS_NO_MEMORY
;
167 DEBUG(10,("Running script to fetch mapping %s\n", keystr
));
169 ret
= idmap_script_script(ctx
, map
, "IDTOSID %s", keystr
);
170 if (!NT_STATUS_IS_OK(ret
)) {
174 sidstr
= sid_string_talloc(keystr
, map
->sid
);
176 ret
= NT_STATUS_NO_MEMORY
;
180 DEBUG(10,("Found id %s:%d -> %s\n", keystr
, map
->xid
.id
,
181 (const char *)sidstr
));
190 Single sid to id lookup function.
192 static NTSTATUS
idmap_script_sid_to_id(struct idmap_domain
*dom
,
197 struct idmap_script_context
*ctx
= dom
->private_data
;
198 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
200 keystr
= sid_string_talloc(tmp_ctx
, map
->sid
);
201 if (keystr
== NULL
) {
202 DEBUG(0, ("Out of memory!\n"));
203 ret
= NT_STATUS_NO_MEMORY
;
207 DEBUG(10,("Fetching record %s\n", keystr
));
209 if (ctx
->script
== NULL
) {
210 ret
= NT_STATUS_NONE_MAPPED
;
214 ret
= idmap_script_script(ctx
, map
, "SIDTOID %s", keystr
);
215 if (!NT_STATUS_IS_OK(ret
)) {
219 /* apply filters before returning result */
220 if (!idmap_unix_id_is_in_range(map
->xid
.id
, dom
)) {
221 DEBUG(5, ("Script returned id (%u) out of range (%u - %u)."
223 map
->xid
.id
, dom
->low_id
, dom
->high_id
));
224 ret
= NT_STATUS_NONE_MAPPED
;
229 talloc_free(tmp_ctx
);
233 static NTSTATUS
idmap_script_unixids_to_sids(struct idmap_domain
*dom
,
237 int i
, num_mapped
= 0;
239 DEBUG(10, ("%s called ...\n", __func__
));
240 /* Init status to avoid surprise ... */
241 for (i
= 0; ids
[i
]; i
++) {
242 ids
[i
]->status
= ID_UNKNOWN
;
245 for (i
= 0; ids
[i
]; i
++) {
246 ret
= idmap_script_id_to_sid(dom
, ids
[i
]);
247 if (!NT_STATUS_IS_OK(ret
)) {
248 if (NT_STATUS_EQUAL(ret
, NT_STATUS_NONE_MAPPED
)) {
249 ids
[i
]->status
= ID_UNMAPPED
;
254 * We cannot keep going if it is other than mapping
260 ids
[i
]->status
= ID_MAPPED
;
267 if (NT_STATUS_IS_OK(ret
)) {
268 if (i
== 0 || num_mapped
== 0) {
269 ret
= NT_STATUS_NONE_MAPPED
;
271 else if (num_mapped
< i
) {
272 ret
= STATUS_SOME_UNMAPPED
;
274 DEBUG(10, ("Returning NT_STATUS_OK\n"));
282 static NTSTATUS
idmap_script_sids_to_unixids(struct idmap_domain
*dom
,
286 int i
, num_mapped
= 0;
288 DEBUG(10, ("%s called ...\n", __func__
));
289 /* Init status to avoid surprise ... */
290 for (i
= 0; ids
[i
]; i
++) {
291 ids
[i
]->status
= ID_UNKNOWN
;
294 for (i
= 0; ids
[i
]; i
++) {
295 ret
= idmap_script_sid_to_id(dom
, ids
[i
]);
296 if (!NT_STATUS_IS_OK(ret
)) {
297 if (NT_STATUS_EQUAL(ret
, NT_STATUS_NONE_MAPPED
)) {
298 ids
[i
]->status
= ID_UNMAPPED
;
303 * We cannot keep going if it is other than mapping
309 ids
[i
]->status
= ID_MAPPED
;
316 if (NT_STATUS_IS_OK(ret
)) {
317 if (i
== 0 || num_mapped
== 0) {
318 ret
= NT_STATUS_NONE_MAPPED
;
320 else if (num_mapped
< i
) {
321 ret
= STATUS_SOME_UNMAPPED
;
323 DEBUG(10, ("Returning NT_STATUS_OK\n"));
332 * Initialise idmap_script database.
334 static NTSTATUS
idmap_script_db_init(struct idmap_domain
*dom
)
337 struct idmap_script_context
*ctx
;
338 char *config_option
= NULL
;
339 const char * idmap_script
= NULL
;
341 DEBUG(10, ("%s called ...\n", __func__
));
343 ctx
= talloc_zero(dom
, struct idmap_script_context
);
345 DEBUG(0, ("Out of memory!\n"));
346 ret
= NT_STATUS_NO_MEMORY
;
350 config_option
= talloc_asprintf(ctx
, "idmap config %s", dom
->name
);
351 if (config_option
== NULL
) {
352 DEBUG(0, ("Out of memory!\n"));
353 ret
= NT_STATUS_NO_MEMORY
;
356 ctx
->script
= lp_parm_const_string(-1, config_option
, "script", NULL
);
357 talloc_free(config_option
);
359 /* Do we even need to handle this? */
360 idmap_script
= lp_parm_const_string(-1, "idmap", "script", NULL
);
361 if (idmap_script
!= NULL
) {
362 DEBUG(0, ("Warning: 'idmap:script' is deprecated. "
363 " Please use 'idmap config * : script' instead!\n"));
366 if (strequal(dom
->name
, "*") && ctx
->script
== NULL
) {
367 /* fall back to idmap:script for backwards compatibility */
368 ctx
->script
= idmap_script
;
372 DEBUG(1, ("using idmap script '%s'\n", ctx
->script
));
375 dom
->private_data
= ctx
;
376 dom
->read_only
= true; /* We do not allocate!*/
385 static struct idmap_methods db_methods
= {
386 .init
= idmap_script_db_init
,
387 .unixids_to_sids
= idmap_script_unixids_to_sids
,
388 .sids_to_unixids
= idmap_script_sids_to_unixids
,
391 NTSTATUS
idmap_script_init(void)
393 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION
, "script", &db_methods
);