r5569: fix more breakage on gcc 2.96
[Samba.git] / source / sam / idmap_rid.c
blobef4b8ef56922bbe98209175e3abe30c3bb432a32
1 /*
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.
22 #include "includes.h"
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_IDMAP
27 NTSTATUS init_module(void);
29 struct dom_entry {
30 fstring name;
31 fstring sid;
32 uint32 min_id;
33 uint32 max_id;
36 typedef struct trust_dom_array {
37 int number;
38 struct dom_entry *dom;
39 } trust_dom_array;
41 static trust_dom_array trust;
43 static NTSTATUS rid_idmap_parse(const char *init_param,
44 uint32 num_domains,
45 fstring *domain_names,
46 DOM_SID *domain_sids,
47 uid_t u_low,
48 uid_t u_high)
50 const char *p;
51 int i;
52 fstring sid_str;
53 BOOL known_domain = False;
54 fstring tok;
56 p = init_param;
57 trust.number = 0;
59 /* falling back to automatic mapping when there were no options given */
60 if (!*init_param) {
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;
70 trust.number = 1;
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));
74 return NT_STATUS_OK;
77 /* scan through the init_param-list */
78 while (next_token(&init_param, tok, LIST_SEP, sizeof(tok))) {
80 p = tok;
81 DEBUG(3,("rid_idmap_parse: parsing entry: %d\n", trust.number));
83 /* reinit sizes */
84 trust.dom = (struct dom_entry *) realloc(trust.dom, sizeof(struct dom_entry)*(trust.number+1));
86 if ( trust.dom == NULL ) {
87 return NT_STATUS_NO_MEMORY;
90 if (!next_token(&p, tok, "=", sizeof(tok))) {
91 DEBUG(0, ("rid_idmap_parse: no '=' sign found in domain list [%s]\n", init_param));
92 return NT_STATUS_UNSUCCESSFUL;
95 /* add the name */
96 fstrcpy(trust.dom[trust.number].name, tok);
97 DEBUGADD(3,("rid_idmap_parse:\tentry %d has name: [%s]\n", trust.number, trust.dom[trust.number].name));
99 /* add the domain-sid */
100 for (i=0; i<num_domains; i++) {
102 known_domain = False;
104 if (strequal(domain_names[i], trust.dom[trust.number].name)) {
106 sid_to_string(sid_str, &domain_sids[i]);
107 fstrcpy(trust.dom[trust.number].sid, sid_str);
109 DEBUGADD(3,("rid_idmap_parse:\tentry %d has sid: [%s]\n", trust.number, trust.dom[trust.number].sid));
110 known_domain = True;
111 break;
115 if (!known_domain) {
116 DEBUG(0,("rid_idmap_parse: your DC does not know anything about domain: [%s]\n", trust.dom[trust.number].name));
117 return NT_STATUS_INVALID_PARAMETER;
120 if (!next_token(&p, tok, "-", sizeof(tok))) {
121 DEBUG(0,("rid_idmap_parse: no mapping-range defined\n"));
122 return NT_STATUS_INVALID_PARAMETER;
125 /* add min_id */
126 trust.dom[trust.number].min_id = atoi(tok);
127 DEBUGADD(3,("rid_idmap_parse:\tentry %d has min_id: [%d]\n", trust.number, trust.dom[trust.number].min_id));
129 /* add max_id */
130 trust.dom[trust.number].max_id = atoi(p);
131 DEBUGADD(3,("rid_idmap_parse:\tentry %d has max_id: [%d]\n", trust.number, trust.dom[trust.number].max_id));
133 trust.number++;
136 return NT_STATUS_OK;
140 static NTSTATUS rid_idmap_get_domains(uint32 *num_domains, fstring **domain_names, DOM_SID **domain_sids)
142 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
143 struct cli_state *cli;
144 TALLOC_CTX *mem_ctx;
145 POLICY_HND pol;
146 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
147 fstring dc_name;
148 struct in_addr dc_ip;
149 char *password = NULL;
150 char *username = NULL;
151 char *domain = NULL;
152 uint32 info_class = 5;
153 char *domain_name = NULL;
154 DOM_SID *domain_sid, sid;
155 fstring sid_str;
156 int i;
157 uint32 trusted_num_domains = 0;
158 char **trusted_domain_names;
159 DOM_SID *trusted_domain_sids;
160 uint32 enum_ctx = 0;
161 DOM_SID builtin_sid;
163 /* put the results together */
164 *num_domains = 1;
165 *domain_names = (fstring *) malloc(sizeof(fstring) * *num_domains);
166 *domain_sids = (DOM_SID *) malloc(sizeof(DOM_SID) * *num_domains);
168 /* avoid calling a DC when trusted domains are not allowed anyway */
169 if (!lp_allow_trusted_domains()) {
171 fstrcpy((*domain_names)[0], lp_workgroup());
172 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
173 DEBUG(0,("rid_idmap_get_domains: failed to retrieve domain sid\n"));
174 return status;
176 sid_copy(&(*domain_sids)[0], &sid);
178 return NT_STATUS_OK;
181 /* create mem_ctx */
182 if (!(mem_ctx = talloc_init("rid_idmap_get_trusted_domains"))) {
183 DEBUG(0, ("rid_idmap_get_domains: talloc_init() failed\n"));
184 return NT_STATUS_NO_MEMORY;
187 if (!get_dc_name(lp_workgroup(), 0, dc_name, &dc_ip)) {
188 DEBUG(1, ("rid_idmap_get_domains: could not get dc-name\n"));
189 return NT_STATUS_UNSUCCESSFUL;
192 /* open a connection to the dc */
193 username = secrets_fetch(SECRETS_AUTH_USER, NULL);
194 password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
195 domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
197 if (username) {
199 if (!domain)
200 domain = smb_xstrdup(lp_workgroup());
202 if (!password)
203 password = smb_xstrdup("");
205 DEBUG(3, ("rid_idmap_get_domains: IPC$ connections done by user %s\\%s\n", domain, username));
207 } else {
209 DEBUG(3, ("rid_idmap_get_domains: IPC$ connections done anonymously\n"));
210 username = "";
211 domain = "";
212 password = "";
215 DEBUG(10, ("rid_idmap_get_domains: opening connection to [%s]\n", dc_name));
217 status = cli_full_connection(&cli, global_myname(), dc_name,
218 NULL, 0,
219 "IPC$", "IPC",
220 username,
221 lp_workgroup(),
222 password,
223 CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, True, NULL);
225 if (!NT_STATUS_IS_OK(status)) {
226 DEBUG(1, ("rid_idmap_get_domains: could not setup connection to dc\n"));
227 return status;
230 /* query the lsa-pipe */
231 if (!cli_nt_session_open (cli, PI_LSARPC)) {
232 DEBUG(1, ("rid_idmap_get_domains: could not setup connection to dc\n"));
233 goto out;
236 /* query policies */
237 status = cli_lsa_open_policy(cli, mem_ctx, False, des_access, &pol);
238 if (!NT_STATUS_IS_OK(status)) {
239 goto out;
242 status = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class, &domain_name, &domain_sid);
243 if (!NT_STATUS_IS_OK(status)) {
244 DEBUG(1, ("rid_idmap_get_domains: cannot retrieve domain-info\n"));
245 goto out;
248 sid_to_string(sid_str, domain_sid);
249 DEBUG(10,("rid_idmap_get_domains: my domain: [%s], sid: [%s]\n", domain_name, sid_str));
251 /* scan trusted domains */
252 DEBUG(10, ("rid_idmap_get_domains: enumerating trusted domains\n"));
253 status = cli_lsa_enum_trust_dom(cli, mem_ctx, &pol, &enum_ctx,
254 &trusted_num_domains,
255 &trusted_domain_names,
256 &trusted_domain_sids);
258 if (!NT_STATUS_IS_OK(status) &&
259 !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES) &&
260 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
261 DEBUG(1, ("rid_idmap_get_domains: could not enumerate trusted domains\n"));
262 goto out;
265 /* show trusted domains */
266 DEBUG(10,("rid_idmap_get_domains: scan for trusted domains gave %d results:\n", trusted_num_domains));
267 for (i=0; i<trusted_num_domains; i++) {
268 sid_to_string(sid_str, &trusted_domain_sids[i]);
269 DEBUGADD(10,("rid_idmap_get_domains:\t#%d\tDOMAIN: [%s], SID: [%s]\n",
270 i, trusted_domain_names[i], sid_str));
273 int own_domains = 2;
274 if (!sid_equal(domain_sid, get_global_sam_sid()))
275 ++own_domains;
277 /* put the results together */
278 *num_domains = trusted_num_domains + own_domains;
279 *domain_names = (fstring *) realloc(*domain_names, sizeof(fstring) * *num_domains);
280 *domain_sids = (DOM_SID *) realloc(*domain_sids, sizeof(DOM_SID) * *num_domains);
282 /* first add mydomain */
283 fstrcpy((*domain_names)[0], domain_name);
284 sid_copy(&(*domain_sids)[0], domain_sid);
286 /* then add BUILTIN */
287 string_to_sid(&builtin_sid, "S-1-5-32");
288 fstrcpy((*domain_names)[1], "BUILTIN");
289 sid_copy(&(*domain_sids)[1], &builtin_sid);
291 /* then add my local sid */
292 if (!sid_equal(domain_sid, get_global_sam_sid())) {
293 fstrcpy((*domain_names)[2], global_myname());
294 sid_copy(&(*domain_sids)[2], get_global_sam_sid());
297 /* add trusted domains */
298 for (i=0; i<trusted_num_domains; i++) {
299 fstrcpy((*domain_names)[i+own_domains], trusted_domain_names[i]);
300 sid_copy(&((*domain_sids)[i+own_domains]), &(trusted_domain_sids[i]));
303 /* show complete domain list */
304 DEBUG(5,("rid_idmap_get_domains: complete domain-list has %d entries:\n", *num_domains));
305 for (i=0; i<*num_domains; i++) {
306 sid_to_string(sid_str, &((*domain_sids)[i]));
307 DEBUGADD(5,("rid_idmap_get_domains:\t#%d\tdomain: [%s], sid: [%s]\n",
308 i, (*domain_names)[i], sid_str ));
311 status = NT_STATUS_OK;
313 out:
314 cli_lsa_close(cli, mem_ctx, &pol);
315 cli_nt_session_close(cli);
316 talloc_destroy(mem_ctx);
317 cli_shutdown(cli);
319 return status;
322 static NTSTATUS rid_idmap_init(char *init_param)
324 int i, j;
325 uid_t u_low, u_high;
326 gid_t g_low, g_high;
327 uint32 num_domains = 0;
328 fstring *domain_names;
329 DOM_SID *domain_sids;
330 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
331 trust.dom = NULL;
333 /* basic sanity checks */
334 if (!lp_idmap_uid(&u_low, &u_high) || !lp_idmap_gid(&g_low, &g_high)) {
335 DEBUG(0, ("rid_idmap_init: cannot get required global idmap-ranges.\n"));
336 return nt_status;
339 if (u_low != g_low || u_high != g_high) {
340 DEBUG(0, ("rid_idmap_init: range defined in \"idmap uid\" must match range of \"idmap gid\".\n"));
341 return nt_status;
344 if (lp_allow_trusted_domains()) {
345 #if IDMAP_RID_SUPPORT_TRUSTED_DOMAINS
346 DEBUG(3,("rid_idmap_init: enabling trusted-domain-mapping\n"));
347 #else
348 DEBUG(0,("rid_idmap_init: idmap_rid does not work with trusted domains\n"));
349 DEBUGADD(0,("rid_idmap_init: please set \"allow trusted domains\" to \"no\" when using idmap_rid\n"));
350 return nt_status;
351 #endif
354 /* init sizes */
355 trust.dom = (struct dom_entry *) malloc(sizeof(struct dom_entry));
356 if (trust.dom == NULL) {
357 return NT_STATUS_NO_MEMORY;
360 /* retrieve full domain list */
361 nt_status = rid_idmap_get_domains(&num_domains, &domain_names, &domain_sids);
362 if (!NT_STATUS_IS_OK(nt_status) &&
363 !NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MORE_ENTRIES) &&
364 !NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES)) {
365 DEBUG(0, ("rid_idmap_init: cannot fetch sids for domain and/or trusted-domains from domain-controller.\n"));
366 return nt_status;
369 /* parse the init string */
370 nt_status = rid_idmap_parse(init_param, num_domains, domain_names, domain_sids, u_low, u_high);
371 if (!NT_STATUS_IS_OK(nt_status)) {
372 DEBUG(0, ("rid_idmap_init: cannot parse module-configuration\n"));
373 goto out;
376 nt_status = NT_STATUS_INVALID_PARAMETER;
378 /* some basic sanity checks */
379 for (i=0; i<trust.number; i++) {
381 if (trust.dom[i].min_id > trust.dom[i].max_id) {
382 DEBUG(0, ("rid_idmap_init: min_id (%d) has to be smaller than max_id (%d) for domain [%s]\n",
383 trust.dom[i].min_id, trust.dom[i].max_id, trust.dom[i].name));
384 goto out;
387 if (trust.dom[i].min_id < u_low || trust.dom[i].max_id > u_high) {
388 DEBUG(0, ("rid_idmap_init: mapping of domain [%s] (%d-%d) has to fit into global idmap range (%d-%d).\n",
389 trust.dom[i].name, trust.dom[i].min_id, trust.dom[i].max_id, u_low, u_high));
390 goto out;
394 /* check for overlaps */
395 for (i=0; i<trust.number-1; i++) {
396 for (j=i+1; j<trust.number; j++) {
397 if (trust.dom[i].min_id <= trust.dom[j].max_id && trust.dom[j].min_id <= trust.dom[i].max_id) {
398 DEBUG(0, ("rid_idmap_init: the ranges of domain [%s] and [%s] overlap\n",
399 trust.dom[i+1].name, trust.dom[i].name));
400 goto out;
405 DEBUG(3, ("rid_idmap_init: using %d mappings:\n", trust.number));
406 for (i=0; i<trust.number; i++) {
407 DEBUGADD(3, ("rid_idmap_init:\tdomain: [%s], sid: [%s], min_id: [%d], max_id: [%d]\n",
408 trust.dom[i].name, trust.dom[i].sid, trust.dom[i].min_id, trust.dom[i].max_id));
411 nt_status = NT_STATUS_OK;
413 out:
414 SAFE_FREE(domain_names);
415 SAFE_FREE(domain_sids);
417 return nt_status;
420 static NTSTATUS rid_idmap_get_sid_from_id(DOM_SID *sid, unid_t unid, int id_type)
422 fstring sid_string;
423 int i;
424 DOM_SID sidstr;
426 /* find range */
427 for (i=0; i<trust.number; i++) {
428 if (trust.dom[i].min_id <= unid.uid && trust.dom[i].max_id >= unid.uid )
429 break;
432 if (i == trust.number) {
433 DEBUG(0,("rid_idmap_get_sid_from_id: no suitable range available for id: %d\n", unid.uid));
434 return NT_STATUS_INVALID_PARAMETER;
437 /* use lower-end of idmap-range as offset for users and groups*/
438 unid.uid -= trust.dom[i].min_id;
440 if (!trust.dom[i].sid)
441 return NT_STATUS_INVALID_PARAMETER;
443 string_to_sid(&sidstr, trust.dom[i].sid);
444 sid_copy(sid, &sidstr);
445 if (!sid_append_rid( sid, (unsigned long)unid.uid )) {
446 DEBUG(0,("rid_idmap_get_sid_from_id: could not append rid to domain sid\n"));
447 return NT_STATUS_NO_MEMORY;
450 DEBUG(3, ("rid_idmap_get_sid_from_id: mapped POSIX %s %d to SID [%s]\n",
451 (id_type == ID_GROUPID) ? "GID" : "UID", unid.uid,
452 sid_to_string(sid_string, sid)));
454 return NT_STATUS_OK;
457 static NTSTATUS rid_idmap_get_id_from_sid(unid_t *unid, int *id_type, const DOM_SID *sid)
459 fstring sid_string;
460 int i;
461 uint32 rid;
462 DOM_SID sidstr;
464 /* check if we have a mapping for the sid */
465 for (i=0; i<trust.number; i++) {
466 if (!trust.dom[i].sid) {
467 return NT_STATUS_INVALID_PARAMETER;
469 string_to_sid(&sidstr, trust.dom[i].sid);
470 if ( sid_compare_domain(sid, &sidstr) == 0 )
471 break;
474 if (i == trust.number) {
475 DEBUG(0,("rid_idmap_get_id_from_sid: no suitable range available for sid: %s\n",
476 sid_string_static(sid)));
477 return NT_STATUS_INVALID_PARAMETER;
480 if (!sid_peek_rid(sid, &rid)) {
481 DEBUG(0,("rid_idmap_get_id_from_sid: could not peek rid\n"));
482 return NT_STATUS_INVALID_PARAMETER;
485 /* use lower-end of idmap-range as offset for users and groups */
486 unid->uid = rid + trust.dom[i].min_id;
488 if (unid->uid > trust.dom[i].max_id) {
489 DEBUG(0,("rid_idmap_get_id_from_sid: rid: %d (%s: %d) too high for mapping of domain: %s (%d-%d)\n",
490 rid, (*id_type == ID_GROUPID) ? "GID" : "UID", unid->uid, trust.dom[i].name,
491 trust.dom[i].min_id, trust.dom[i].max_id));
492 return NT_STATUS_INVALID_PARAMETER;
494 if (unid->uid < trust.dom[i].min_id) {
495 DEBUG(0,("rid_idmap_get_id_from_sid: rid: %d (%s: %d) too low for mapping of domain: %s (%d-%d)\n",
496 rid, (*id_type == ID_GROUPID) ? "GID" : "UID", unid->uid,
497 trust.dom[i].name, trust.dom[i].min_id, trust.dom[i].max_id));
498 return NT_STATUS_INVALID_PARAMETER;
501 DEBUG(3,("rid_idmap_get_id_from_sid: mapped SID [%s] to POSIX %s %d\n",
502 sid_to_string(sid_string, sid),
503 (*id_type == ID_GROUPID) ? "GID" : "UID", unid->uid));
505 return NT_STATUS_OK;
509 static NTSTATUS rid_idmap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
511 return NT_STATUS_NOT_IMPLEMENTED;
514 static NTSTATUS rid_idmap_close(void)
516 SAFE_FREE(trust.dom);
518 return NT_STATUS_OK;
521 static NTSTATUS rid_idmap_allocate_rid(uint32 *rid, int rid_type)
523 return NT_STATUS_NOT_IMPLEMENTED;
526 static NTSTATUS rid_idmap_allocate_id(unid_t *id, int id_type)
528 return NT_STATUS_NOT_IMPLEMENTED;
531 static void rid_idmap_status(void)
533 DEBUG(0, ("RID IDMAP Status not available\n"));
536 static struct idmap_methods rid_methods = {
537 rid_idmap_init,
538 rid_idmap_allocate_rid,
539 rid_idmap_allocate_id,
540 rid_idmap_get_sid_from_id,
541 rid_idmap_get_id_from_sid,
542 rid_idmap_set_mapping,
543 rid_idmap_close,
544 rid_idmap_status
547 NTSTATUS init_module(void)
549 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "idmap_rid", &rid_methods);