2 * idmap_rid: static map between Active Directory/NT RIDs and RFC 2307 accounts
3 * Copyright (C) Guenther Deschner, 2004
4 * Copyright (C) Sumit Bose, 2004
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define DBGC_CLASS DBGC_IDMAP
27 NTSTATUS
init_module(void);
36 typedef struct trust_dom_array
{
38 struct dom_entry
*dom
;
41 static trust_dom_array trust
;
43 static NTSTATUS
rid_idmap_parse(const char *init_param
,
45 fstring
*domain_names
,
53 BOOL known_domain
= False
;
59 /* falling back to automatic mapping when there were no options given */
62 DEBUG(3,("rid_idmap_parse: no domain list given or trusted domain-support deactivated, falling back to automatic mapping for own domain:\n"));
64 sid_to_string(sid_str
, &domain_sids
[0]);
66 fstrcpy(trust
.dom
[0].name
, domain_names
[0]);
67 fstrcpy(trust
.dom
[0].sid
, sid_str
);
68 trust
.dom
[0].min_id
= u_low
;
69 trust
.dom
[0].max_id
= u_high
;
72 DEBUGADD(3,("rid_idmap_parse:\tdomain: [%s], sid: [%s], range=[%d-%d]\n",
73 trust
.dom
[0].name
, trust
.dom
[0].sid
, trust
.dom
[0].min_id
, trust
.dom
[0].max_id
));
77 /* scan through the init_param-list */
78 while (next_token(&init_param
, tok
, LIST_SEP
, sizeof(tok
))) {
81 DEBUG(3,("rid_idmap_parse: parsing entry: %d\n", trust
.number
));
84 trust
.dom
= SMB_REALLOC_ARRAY(trust
.dom
, struct dom_entry
,
87 if ( trust
.dom
== NULL
) {
88 return NT_STATUS_NO_MEMORY
;
91 if (!next_token(&p
, tok
, "=", sizeof(tok
))) {
92 DEBUG(0, ("rid_idmap_parse: no '=' sign found in domain list [%s]\n", init_param
));
93 return NT_STATUS_UNSUCCESSFUL
;
97 fstrcpy(trust
.dom
[trust
.number
].name
, tok
);
98 DEBUGADD(3,("rid_idmap_parse:\tentry %d has name: [%s]\n", trust
.number
, trust
.dom
[trust
.number
].name
));
100 /* add the domain-sid */
101 for (i
=0; i
<num_domains
; i
++) {
103 known_domain
= False
;
105 if (strequal(domain_names
[i
], trust
.dom
[trust
.number
].name
)) {
107 sid_to_string(sid_str
, &domain_sids
[i
]);
108 fstrcpy(trust
.dom
[trust
.number
].sid
, sid_str
);
110 DEBUGADD(3,("rid_idmap_parse:\tentry %d has sid: [%s]\n", trust
.number
, trust
.dom
[trust
.number
].sid
));
117 DEBUG(0,("rid_idmap_parse: your DC does not know anything about domain: [%s]\n", trust
.dom
[trust
.number
].name
));
118 return NT_STATUS_INVALID_PARAMETER
;
121 if (!next_token(&p
, tok
, "-", sizeof(tok
))) {
122 DEBUG(0,("rid_idmap_parse: no mapping-range defined\n"));
123 return NT_STATUS_INVALID_PARAMETER
;
127 trust
.dom
[trust
.number
].min_id
= atoi(tok
);
128 DEBUGADD(3,("rid_idmap_parse:\tentry %d has min_id: [%d]\n", trust
.number
, trust
.dom
[trust
.number
].min_id
));
131 trust
.dom
[trust
.number
].max_id
= atoi(p
);
132 DEBUGADD(3,("rid_idmap_parse:\tentry %d has max_id: [%d]\n", trust
.number
, trust
.dom
[trust
.number
].max_id
));
141 static NTSTATUS
rid_idmap_get_domains(uint32
*num_domains
, fstring
**domain_names
, DOM_SID
**domain_sids
)
143 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
144 struct cli_state
*cli
;
145 struct rpc_pipe_client
*pipe_hnd
;
148 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
150 struct in_addr dc_ip
;
151 const char *password
= NULL
;
152 const char *username
= NULL
;
153 const char *domain
= NULL
;
154 uint32 info_class
= 5;
155 char *domain_name
= NULL
;
156 DOM_SID
*domain_sid
, sid
;
159 uint32 trusted_num_domains
= 0;
160 char **trusted_domain_names
;
161 DOM_SID
*trusted_domain_sids
;
165 /* put the results together */
167 *domain_names
= SMB_MALLOC_ARRAY(fstring
, *num_domains
);
168 *domain_sids
= SMB_MALLOC_ARRAY(DOM_SID
, *num_domains
);
170 /* avoid calling a DC when trusted domains are not allowed anyway */
171 if (!lp_allow_trusted_domains()) {
173 fstrcpy((*domain_names
)[0], lp_workgroup());
174 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid
)) {
175 DEBUG(0,("rid_idmap_get_domains: failed to retrieve domain sid\n"));
178 sid_copy(&(*domain_sids
)[0], &sid
);
181 fstrcpy((*domain_names
)[1], "BUILTIN");
182 sid_copy(&(*domain_sids
)[1], &global_sid_Builtin
);
188 if (!(mem_ctx
= talloc_init("rid_idmap_get_trusted_domains"))) {
189 DEBUG(0, ("rid_idmap_get_domains: talloc_init() failed\n"));
190 return NT_STATUS_NO_MEMORY
;
193 if (!get_dc_name(lp_workgroup(), 0, dc_name
, &dc_ip
)) {
194 DEBUG(1, ("rid_idmap_get_domains: could not get dc-name\n"));
195 return NT_STATUS_UNSUCCESSFUL
;
198 /* open a connection to the dc */
199 username
= secrets_fetch(SECRETS_AUTH_USER
, NULL
);
200 password
= secrets_fetch(SECRETS_AUTH_PASSWORD
, NULL
);
201 domain
= secrets_fetch(SECRETS_AUTH_DOMAIN
, NULL
);
206 domain
= smb_xstrdup(lp_workgroup());
209 password
= smb_xstrdup("");
211 DEBUG(3, ("rid_idmap_get_domains: IPC$ connections done by user %s\\%s\n", domain
, username
));
215 DEBUG(3, ("rid_idmap_get_domains: IPC$ connections done anonymously\n"));
221 DEBUG(10, ("rid_idmap_get_domains: opening connection to [%s]\n", dc_name
));
223 status
= cli_full_connection(&cli
, global_myname(), dc_name
,
229 CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK
, True
, NULL
);
231 if (!NT_STATUS_IS_OK(status
)) {
232 DEBUG(1, ("rid_idmap_get_domains: could not setup connection to dc\n"));
236 /* query the lsa-pipe */
237 pipe_hnd
= cli_rpc_pipe_open_noauth(cli
, PI_LSARPC
, &status
);
238 if (!NT_STATUS_IS_OK(status
)) {
239 DEBUG(1, ("rid_idmap_get_domains: could not setup connection to dc\n"));
244 status
= rpccli_lsa_open_policy(pipe_hnd
, mem_ctx
, False
, des_access
,
246 if (!NT_STATUS_IS_OK(status
)) {
250 status
= rpccli_lsa_query_info_policy(pipe_hnd
, mem_ctx
, &pol
,
251 info_class
, &domain_name
,
253 if (!NT_STATUS_IS_OK(status
)) {
254 DEBUG(1, ("rid_idmap_get_domains: cannot retrieve domain-info\n"));
258 sid_to_string(sid_str
, domain_sid
);
259 DEBUG(10,("rid_idmap_get_domains: my domain: [%s], sid: [%s]\n", domain_name
, sid_str
));
261 /* scan trusted domains */
262 DEBUG(10, ("rid_idmap_get_domains: enumerating trusted domains\n"));
263 status
= rpccli_lsa_enum_trust_dom(pipe_hnd
, mem_ctx
, &pol
, &enum_ctx
,
264 &trusted_num_domains
,
265 &trusted_domain_names
,
266 &trusted_domain_sids
);
268 if (!NT_STATUS_IS_OK(status
) &&
269 !NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_ENTRIES
) &&
270 !NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) {
271 DEBUG(1, ("rid_idmap_get_domains: could not enumerate trusted domains\n"));
275 /* show trusted domains */
276 DEBUG(10,("rid_idmap_get_domains: scan for trusted domains gave %d results:\n", trusted_num_domains
));
277 for (i
=0; i
<trusted_num_domains
; i
++) {
278 sid_to_string(sid_str
, &trusted_domain_sids
[i
]);
279 DEBUGADD(10,("rid_idmap_get_domains:\t#%d\tDOMAIN: [%s], SID: [%s]\n",
280 i
, trusted_domain_names
[i
], sid_str
));
283 if (!sid_equal(domain_sid
, get_global_sam_sid()))
286 /* put the results together */
287 *num_domains
= trusted_num_domains
+ own_domains
;
288 *domain_names
= SMB_REALLOC_ARRAY(*domain_names
, fstring
,
290 *domain_sids
= SMB_REALLOC_ARRAY(*domain_sids
, DOM_SID
, *num_domains
);
292 /* first add mydomain */
293 fstrcpy((*domain_names
)[0], domain_name
);
294 sid_copy(&(*domain_sids
)[0], domain_sid
);
296 /* then add BUILTIN */
297 fstrcpy((*domain_names
)[1], "BUILTIN");
298 sid_copy(&(*domain_sids
)[1], &global_sid_Builtin
);
300 /* then add my local sid */
301 if (!sid_equal(domain_sid
, get_global_sam_sid())) {
302 fstrcpy((*domain_names
)[2], global_myname());
303 sid_copy(&(*domain_sids
)[2], get_global_sam_sid());
306 /* add trusted domains */
307 for (i
=0; i
<trusted_num_domains
; i
++) {
308 fstrcpy((*domain_names
)[i
+own_domains
], trusted_domain_names
[i
]);
309 sid_copy(&((*domain_sids
)[i
+own_domains
]), &(trusted_domain_sids
[i
]));
312 /* show complete domain list */
313 DEBUG(5,("rid_idmap_get_domains: complete domain-list has %d entries:\n", *num_domains
));
314 for (i
=0; i
<*num_domains
; i
++) {
315 sid_to_string(sid_str
, &((*domain_sids
)[i
]));
316 DEBUGADD(5,("rid_idmap_get_domains:\t#%d\tdomain: [%s], sid: [%s]\n",
317 i
, (*domain_names
)[i
], sid_str
));
320 status
= NT_STATUS_OK
;
323 rpccli_lsa_close(pipe_hnd
, mem_ctx
, &pol
);
324 cli_rpc_pipe_close(pipe_hnd
);
325 talloc_destroy(mem_ctx
);
331 static NTSTATUS
rid_idmap_init(char *init_param
)
336 uint32 num_domains
= 0;
337 fstring
*domain_names
;
338 DOM_SID
*domain_sids
;
339 NTSTATUS nt_status
= NT_STATUS_INVALID_PARAMETER
;
342 /* basic sanity checks */
343 if (!lp_idmap_uid(&u_low
, &u_high
) || !lp_idmap_gid(&g_low
, &g_high
)) {
344 DEBUG(0, ("rid_idmap_init: cannot get required global idmap-ranges.\n"));
348 if (u_low
!= g_low
|| u_high
!= g_high
) {
349 DEBUG(0, ("rid_idmap_init: range defined in \"idmap uid\" must match range of \"idmap gid\".\n"));
353 if (lp_allow_trusted_domains()) {
354 #if IDMAP_RID_SUPPORT_TRUSTED_DOMAINS
355 DEBUG(3,("rid_idmap_init: enabling trusted-domain-mapping\n"));
357 DEBUG(0,("rid_idmap_init: idmap_rid does not work with trusted domains\n"));
358 DEBUGADD(0,("rid_idmap_init: please set \"allow trusted domains\" to \"no\" when using idmap_rid\n"));
364 trust
.dom
= SMB_MALLOC_P(struct dom_entry
);
365 if (trust
.dom
== NULL
) {
366 return NT_STATUS_NO_MEMORY
;
369 /* retrieve full domain list */
370 nt_status
= rid_idmap_get_domains(&num_domains
, &domain_names
, &domain_sids
);
371 if (!NT_STATUS_IS_OK(nt_status
) &&
372 !NT_STATUS_EQUAL(nt_status
, NT_STATUS_NO_MORE_ENTRIES
) &&
373 !NT_STATUS_EQUAL(nt_status
, STATUS_MORE_ENTRIES
)) {
374 DEBUG(0, ("rid_idmap_init: cannot fetch sids for domain and/or trusted-domains from domain-controller.\n"));
378 /* parse the init string */
379 nt_status
= rid_idmap_parse(init_param
, num_domains
, domain_names
, domain_sids
, u_low
, u_high
);
380 if (!NT_STATUS_IS_OK(nt_status
)) {
381 DEBUG(0, ("rid_idmap_init: cannot parse module-configuration\n"));
385 nt_status
= NT_STATUS_INVALID_PARAMETER
;
387 /* some basic sanity checks */
388 for (i
=0; i
<trust
.number
; i
++) {
390 if (trust
.dom
[i
].min_id
> trust
.dom
[i
].max_id
) {
391 DEBUG(0, ("rid_idmap_init: min_id (%d) has to be smaller than max_id (%d) for domain [%s]\n",
392 trust
.dom
[i
].min_id
, trust
.dom
[i
].max_id
, trust
.dom
[i
].name
));
396 if (trust
.dom
[i
].min_id
< u_low
|| trust
.dom
[i
].max_id
> u_high
) {
397 DEBUG(0, ("rid_idmap_init: mapping of domain [%s] (%d-%d) has to fit into global idmap range (%d-%d).\n",
398 trust
.dom
[i
].name
, trust
.dom
[i
].min_id
, trust
.dom
[i
].max_id
, u_low
, u_high
));
403 /* check for overlaps */
404 for (i
=0; i
<trust
.number
-1; i
++) {
405 for (j
=i
+1; j
<trust
.number
; j
++) {
406 if (trust
.dom
[i
].min_id
<= trust
.dom
[j
].max_id
&& trust
.dom
[j
].min_id
<= trust
.dom
[i
].max_id
) {
407 DEBUG(0, ("rid_idmap_init: the ranges of domain [%s] and [%s] overlap\n",
408 trust
.dom
[i
+1].name
, trust
.dom
[i
].name
));
414 DEBUG(3, ("rid_idmap_init: using %d mappings:\n", trust
.number
));
415 for (i
=0; i
<trust
.number
; i
++) {
416 DEBUGADD(3, ("rid_idmap_init:\tdomain: [%s], sid: [%s], min_id: [%d], max_id: [%d]\n",
417 trust
.dom
[i
].name
, trust
.dom
[i
].sid
, trust
.dom
[i
].min_id
, trust
.dom
[i
].max_id
));
420 nt_status
= NT_STATUS_OK
;
423 SAFE_FREE(domain_names
);
424 SAFE_FREE(domain_sids
);
429 static NTSTATUS
rid_idmap_get_sid_from_id(DOM_SID
*sid
, unid_t unid
, int id_type
)
436 for (i
=0; i
<trust
.number
; i
++) {
437 if (trust
.dom
[i
].min_id
<= unid
.uid
&& trust
.dom
[i
].max_id
>= unid
.uid
)
441 if (i
== trust
.number
) {
442 DEBUG(0,("rid_idmap_get_sid_from_id: no suitable range available for id: %d\n", unid
.uid
));
443 return NT_STATUS_INVALID_PARAMETER
;
446 /* use lower-end of idmap-range as offset for users and groups*/
447 unid
.uid
-= trust
.dom
[i
].min_id
;
449 if (!trust
.dom
[i
].sid
)
450 return NT_STATUS_INVALID_PARAMETER
;
452 string_to_sid(&sidstr
, trust
.dom
[i
].sid
);
453 sid_copy(sid
, &sidstr
);
454 if (!sid_append_rid( sid
, (unsigned long)unid
.uid
)) {
455 DEBUG(0,("rid_idmap_get_sid_from_id: could not append rid to domain sid\n"));
456 return NT_STATUS_NO_MEMORY
;
459 DEBUG(3, ("rid_idmap_get_sid_from_id: mapped POSIX %s %d to SID [%s]\n",
460 (id_type
== ID_GROUPID
) ? "GID" : "UID", unid
.uid
,
461 sid_to_string(sid_string
, sid
)));
466 static NTSTATUS
rid_idmap_get_id_from_sid(unid_t
*unid
, int *id_type
, const DOM_SID
*sid
)
473 /* check if we have a mapping for the sid */
474 for (i
=0; i
<trust
.number
; i
++) {
475 if (!trust
.dom
[i
].sid
) {
476 return NT_STATUS_INVALID_PARAMETER
;
478 string_to_sid(&sidstr
, trust
.dom
[i
].sid
);
479 if ( sid_compare_domain(sid
, &sidstr
) == 0 )
483 if (i
== trust
.number
) {
484 DEBUG(0,("rid_idmap_get_id_from_sid: no suitable range available for sid: %s\n",
485 sid_string_static(sid
)));
486 return NT_STATUS_INVALID_PARAMETER
;
489 if (!sid_peek_rid(sid
, &rid
)) {
490 DEBUG(0,("rid_idmap_get_id_from_sid: could not peek rid\n"));
491 return NT_STATUS_INVALID_PARAMETER
;
494 /* use lower-end of idmap-range as offset for users and groups */
495 unid
->uid
= rid
+ trust
.dom
[i
].min_id
;
497 if (unid
->uid
> trust
.dom
[i
].max_id
) {
498 DEBUG(0,("rid_idmap_get_id_from_sid: rid: %d (%s: %d) too high for mapping of domain: %s (%d-%d)\n",
499 rid
, (*id_type
== ID_GROUPID
) ? "GID" : "UID", unid
->uid
, trust
.dom
[i
].name
,
500 trust
.dom
[i
].min_id
, trust
.dom
[i
].max_id
));
501 return NT_STATUS_INVALID_PARAMETER
;
503 if (unid
->uid
< trust
.dom
[i
].min_id
) {
504 DEBUG(0,("rid_idmap_get_id_from_sid: rid: %d (%s: %d) too low for mapping of domain: %s (%d-%d)\n",
505 rid
, (*id_type
== ID_GROUPID
) ? "GID" : "UID", unid
->uid
,
506 trust
.dom
[i
].name
, trust
.dom
[i
].min_id
, trust
.dom
[i
].max_id
));
507 return NT_STATUS_INVALID_PARAMETER
;
510 DEBUG(3,("rid_idmap_get_id_from_sid: mapped SID [%s] to POSIX %s %d\n",
511 sid_to_string(sid_string
, sid
),
512 (*id_type
== ID_GROUPID
) ? "GID" : "UID", unid
->uid
));
518 static NTSTATUS
rid_idmap_set_mapping(const DOM_SID
*sid
, unid_t id
, int id_type
)
520 return NT_STATUS_NOT_IMPLEMENTED
;
523 static NTSTATUS
rid_idmap_close(void)
525 SAFE_FREE(trust
.dom
);
530 static NTSTATUS
rid_idmap_allocate_rid(uint32
*rid
, int rid_type
)
532 return NT_STATUS_NOT_IMPLEMENTED
;
535 static NTSTATUS
rid_idmap_allocate_id(unid_t
*id
, int id_type
)
537 return NT_STATUS_NOT_IMPLEMENTED
;
540 static void rid_idmap_status(void)
542 DEBUG(0, ("RID IDMAP Status not available\n"));
545 static struct idmap_methods rid_methods
= {
547 rid_idmap_allocate_rid
,
548 rid_idmap_allocate_id
,
549 rid_idmap_get_sid_from_id
,
550 rid_idmap_get_id_from_sid
,
551 rid_idmap_set_mapping
,
556 NTSTATUS
init_module(void)
558 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION
, "idmap_rid", &rid_methods
);
559 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION
, "rid", &rid_methods
);