version incremented
[samba] / source / sam / idmap_rid.c
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
5  *
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.
10  *
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.
15  *
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.
19  *
20  */
21
22 #include "includes.h"
23
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_IDMAP
26
27 NTSTATUS init_module(void);
28
29 struct dom_entry {
30         fstring name;
31         fstring sid;
32         uint32 min_id;
33         uint32 max_id;
34 };
35
36 typedef struct trust_dom_array {
37         int number;
38         struct dom_entry *dom;
39 } trust_dom_array;
40
41 static trust_dom_array trust;
42
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) 
49 {
50         const char *p;
51         int i;
52         fstring sid_str;
53         BOOL known_domain = False;
54         fstring tok;
55
56         p = init_param;
57         trust.number = 0;
58
59         /* falling back to automatic mapping when there were no options given */
60         if (!*init_param) {
61
62                 DEBUG(3,("rid_idmap_parse: no domain list given or trusted domain-support deactivated, falling back to automatic mapping for own domain:\n"));
63
64                 sid_to_string(sid_str, &domain_sids[0]);
65
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;
71
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;
75         }
76
77         /* scan through the init_param-list */
78         while (next_token(&init_param, tok, LIST_SEP, sizeof(tok))) {
79
80                 p = tok;
81                 DEBUG(3,("rid_idmap_parse: parsing entry: %d\n", trust.number));
82
83                 /* reinit sizes */
84                 trust.dom = SMB_REALLOC_ARRAY(trust.dom, struct dom_entry,
85                                               trust.number+1);
86
87                 if ( trust.dom == NULL ) {
88                         return NT_STATUS_NO_MEMORY;
89                 }
90                 
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;
94                 }
95
96                 /* add the name */
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));
99
100                 /* add the domain-sid */
101                 for (i=0; i<num_domains; i++) {
102
103                         known_domain = False;
104
105                         if (strequal(domain_names[i], trust.dom[trust.number].name)) {
106
107                                 sid_to_string(sid_str, &domain_sids[i]);
108                                 fstrcpy(trust.dom[trust.number].sid, sid_str);
109
110                                 DEBUGADD(3,("rid_idmap_parse:\tentry %d has sid: [%s]\n", trust.number, trust.dom[trust.number].sid));
111                                 known_domain = True;
112                                 break;
113                         } 
114                 }
115
116                 if (!known_domain) {
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;
119                 }
120
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;
124                 }
125
126                 /* add min_id */
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));
129
130                 /* add max_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));
133
134                 trust.number++;
135         }
136
137         return NT_STATUS_OK;
138
139 }
140
141 static NTSTATUS rid_idmap_get_domains(uint32 *num_domains, fstring **domain_names, DOM_SID **domain_sids) 
142 {
143         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
144         struct cli_state *cli;
145         struct rpc_pipe_client *pipe_hnd;
146         TALLOC_CTX *mem_ctx;
147         POLICY_HND pol;
148         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
149         fstring dc_name;
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;
157         fstring sid_str;
158         int i;
159         uint32 trusted_num_domains = 0;
160         char **trusted_domain_names;
161         DOM_SID *trusted_domain_sids;
162         uint32 enum_ctx = 0;
163         int own_domains = 2;
164
165         /* put the results together */
166         *num_domains = 2;
167         *domain_names = SMB_MALLOC_ARRAY(fstring, *num_domains);
168         *domain_sids = SMB_MALLOC_ARRAY(DOM_SID, *num_domains);
169
170         /* avoid calling a DC when trusted domains are not allowed anyway */
171         if (!lp_allow_trusted_domains()) {
172
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"));
176                         return status;
177                 }
178                 sid_copy(&(*domain_sids)[0], &sid);
179
180                 /* add BUILTIN */
181                 fstrcpy((*domain_names)[1], "BUILTIN");
182                 sid_copy(&(*domain_sids)[1], &global_sid_Builtin);
183
184                 return NT_STATUS_OK;
185         }
186
187         /* create mem_ctx */
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;
191         }
192
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;
196         }
197
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);
202
203         if (username) {
204
205                 if (!domain)
206                         domain = smb_xstrdup(lp_workgroup());
207
208                 if (!password)
209                         password = smb_xstrdup("");
210
211                 DEBUG(3, ("rid_idmap_get_domains: IPC$ connections done by user %s\\%s\n", domain, username));
212
213         } else {
214
215                 DEBUG(3, ("rid_idmap_get_domains: IPC$ connections done anonymously\n"));
216                 username = "";
217                 domain = "";
218                 password = "";
219         }
220
221         DEBUG(10, ("rid_idmap_get_domains: opening connection to [%s]\n", dc_name));
222
223         status = cli_full_connection(&cli, global_myname(), dc_name, 
224                         NULL, 0,
225                         "IPC$", "IPC",
226                         username,
227                         lp_workgroup(),
228                         password,
229                         CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, True, NULL);
230
231         if (!NT_STATUS_IS_OK(status)) {
232                 DEBUG(1, ("rid_idmap_get_domains: could not setup connection to dc\n"));
233                 return status;
234         }       
235
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"));
240                 goto out;
241         }
242
243         /* query policies */
244         status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, False, des_access,
245                                         &pol);
246         if (!NT_STATUS_IS_OK(status)) {
247                 goto out;
248         }
249
250         status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, &pol,
251                                               info_class, &domain_name,
252                                               &domain_sid);
253         if (!NT_STATUS_IS_OK(status)) {
254                 DEBUG(1, ("rid_idmap_get_domains: cannot retrieve domain-info\n"));
255                 goto out;
256         }
257
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));
260
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);
267
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"));
272                 goto out;
273         }
274
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));
281         }
282
283         if (!sid_equal(domain_sid, get_global_sam_sid()))
284                 ++own_domains;
285
286         /* put the results together */
287         *num_domains = trusted_num_domains + own_domains;
288         *domain_names = SMB_REALLOC_ARRAY(*domain_names, fstring,
289                                           *num_domains);
290         *domain_sids = SMB_REALLOC_ARRAY(*domain_sids, DOM_SID, *num_domains);
291
292         /* first add mydomain */
293         fstrcpy((*domain_names)[0], domain_name);
294         sid_copy(&(*domain_sids)[0], domain_sid);
295
296         /* then add BUILTIN */
297         fstrcpy((*domain_names)[1], "BUILTIN");
298         sid_copy(&(*domain_sids)[1], &global_sid_Builtin);
299
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());
304         }
305
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]));
310         }
311
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 ));
318         }
319
320         status = NT_STATUS_OK;
321
322 out:
323         rpccli_lsa_close(pipe_hnd, mem_ctx, &pol);
324         cli_rpc_pipe_close(pipe_hnd);
325         talloc_destroy(mem_ctx);
326         cli_shutdown(cli);
327
328         return status;
329 }
330
331 static NTSTATUS rid_idmap_init(char *init_param)
332 {
333         int i, j;
334         uid_t u_low, u_high;
335         gid_t g_low, g_high;
336         uint32 num_domains = 0;
337         fstring *domain_names;
338         DOM_SID *domain_sids;
339         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
340         trust.dom = NULL;
341
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"));
345                 return nt_status;
346         }
347
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"));
350                 return nt_status;
351         }
352
353         if (lp_allow_trusted_domains()) {
354 #if IDMAP_RID_SUPPORT_TRUSTED_DOMAINS
355                 DEBUG(3,("rid_idmap_init: enabling trusted-domain-mapping\n"));
356 #else
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"));
359                 return nt_status;
360 #endif
361         }
362
363         /* init sizes */
364         trust.dom = SMB_MALLOC_P(struct dom_entry);
365         if (trust.dom == NULL) { 
366                 return NT_STATUS_NO_MEMORY;
367         }
368
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"));
375                 return nt_status;
376         }
377
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"));
382                 goto out;
383         }
384
385         nt_status = NT_STATUS_INVALID_PARAMETER;
386
387         /* some basic sanity checks */
388         for (i=0; i<trust.number; i++) {
389
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));
393                         goto out;
394                 }
395
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));
399                         goto out;
400                 }
401         }
402
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));
409                                 goto out;
410                         }
411                 }
412         }
413         
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));
418         }
419
420         nt_status = NT_STATUS_OK;
421
422 out:
423         SAFE_FREE(domain_names);
424         SAFE_FREE(domain_sids);
425                 
426         return nt_status;
427 }
428
429 static NTSTATUS rid_idmap_get_sid_from_id(DOM_SID *sid, unid_t unid, int id_type)
430 {
431         fstring sid_string;
432         int i;
433         DOM_SID sidstr;
434
435         /* find range */
436         for (i=0; i<trust.number; i++) {
437                 if (trust.dom[i].min_id <= unid.uid && trust.dom[i].max_id >= unid.uid ) 
438                         break;
439         }
440
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;
444         }
445         
446         /* use lower-end of idmap-range as offset for users and groups*/
447         unid.uid -= trust.dom[i].min_id;
448
449         if (!trust.dom[i].sid)
450                 return NT_STATUS_INVALID_PARAMETER;
451
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;
457         }
458
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)));
462
463         return NT_STATUS_OK;
464 }
465
466 static NTSTATUS rid_idmap_get_id_from_sid(unid_t *unid, int *id_type, const DOM_SID *sid)
467 {
468         fstring sid_string;
469         int i;
470         uint32 rid;
471         DOM_SID sidstr;
472
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;
477                 }
478                 string_to_sid(&sidstr, trust.dom[i].sid);       
479                 if ( sid_compare_domain(sid, &sidstr) == 0 )
480                         break;
481         }
482         
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;
487         }
488
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;
492         }
493
494         /* use lower-end of idmap-range as offset for users and groups */
495         unid->uid = rid + trust.dom[i].min_id;
496
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;
502         }
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;
508         }
509
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));
513
514         return NT_STATUS_OK;
515
516 }
517
518 static NTSTATUS rid_idmap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
519 {
520         return NT_STATUS_NOT_IMPLEMENTED;
521 }
522
523 static NTSTATUS rid_idmap_close(void)
524 {
525         SAFE_FREE(trust.dom);
526
527         return NT_STATUS_OK;
528 }
529
530 static NTSTATUS rid_idmap_allocate_rid(uint32 *rid, int rid_type)
531 {
532         return NT_STATUS_NOT_IMPLEMENTED;
533 }
534
535 static NTSTATUS rid_idmap_allocate_id(unid_t *id, int id_type)
536 {
537         return NT_STATUS_NOT_IMPLEMENTED;
538 }
539
540 static void rid_idmap_status(void)
541 {
542         DEBUG(0, ("RID IDMAP Status not available\n"));      
543 }
544
545 static struct idmap_methods rid_methods = {
546         rid_idmap_init,
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,
552         rid_idmap_close,
553         rid_idmap_status
554 };
555
556 NTSTATUS init_module(void)
557 {
558         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rid", &rid_methods);
559 }
560