and so it begins....
[samba.git] / source3 / sam / idmap_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    ID Mapping
4    Copyright (C) Simo Sorce 2003
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 #include "includes.h"
21
22 #undef DBGC_CLASS
23 #define DBGC_CLASS DBGC_IDMAP
24
25
26 /******************************************************************
27  * Get the free RID base if idmap is configured, otherwise return 0
28  ******************************************************************/
29
30 uint32 idmap_get_free_rid_base(void)
31 {
32         uint32 low, high;
33         if (idmap_get_free_rid_range(&low, &high)) {
34                 return low;
35         }
36         return 0;
37 }
38
39 BOOL idmap_check_ugid_is_in_free_range(uint32 id)
40 {
41         uint32 low, high;
42
43         if (!idmap_get_free_ugid_range(&low, &high)) {
44                 return False;
45         }
46         if (id < low || id > high) {
47                 return False;
48         }
49         return True;
50 }
51
52 BOOL idmap_check_rid_is_in_free_range(uint32 rid)
53 {
54         uint32 low, high;
55
56         if (!idmap_get_free_rid_range(&low, &high)) {
57                 return False;
58         }
59         if (rid < algorithmic_rid_base()) {
60                 return True;
61         }
62
63         if (rid < low || rid > high) {
64                 return False;
65         }
66
67         return True;
68 }
69
70 /* if it is a foreign SID or if the SID is in the free range, return true */
71
72 BOOL idmap_check_sid_is_in_free_range(const DOM_SID *sid)
73 {
74         if (sid_compare_domain(get_global_sam_sid(), sid) == 0) {
75         
76                 uint32 rid;
77
78                 if (sid_peek_rid(sid, &rid)) {
79                         return idmap_check_rid_is_in_free_range(rid);
80                 }
81
82                 return False;
83         }
84
85         return True;
86 }
87
88 /******************************************************************
89  * Get the the non-algorithmic RID range if idmap range are defined
90  ******************************************************************/
91
92 BOOL idmap_get_free_rid_range(uint32 *low, uint32 *high)
93 {
94         uint32 id_low, id_high;
95
96         if (!lp_enable_rid_algorithm()) {
97                 *low = BASE_RID;
98                 *high = (uint32)-1;
99         }
100
101         if (!idmap_get_free_ugid_range(&id_low, &id_high)) {
102                 return False;
103         }
104
105         *low = fallback_pdb_uid_to_user_rid(id_low);
106         if (fallback_pdb_user_rid_to_uid((uint32)-1) < id_high) {
107                 *high = (uint32)-1;
108         } else {
109                 *high = fallback_pdb_uid_to_user_rid(id_high);
110         }
111
112         return True;
113 }
114
115 BOOL idmap_get_free_ugid_range(uint32 *low, uint32 *high)
116 {
117         uid_t u_low, u_high;
118         gid_t g_low, g_high;
119
120         if (!lp_idmap_uid(&u_low, &u_high) || !lp_idmap_gid(&g_low, &g_high)) {
121                 return False;
122         }
123         if (u_low < g_low) {
124                 *low = u_low;
125         } else {
126                 *low = g_low;
127         }
128         if (u_high < g_high) {
129                 *high = g_high;
130         } else {
131                 *high = u_high;
132         }
133         return True;
134 }
135
136 /*****************************************************************
137  check idmap if uid is in idmap range, otherwise falls back to
138  the legacy algorithmic mapping.  Returns SID pointer.
139 *****************************************************************/  
140
141 NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid)
142 {
143         unid_t id;
144         int flags;
145
146         DEBUG(10,("idmap_uid_to_sid: uid = [%d]\n", uid));
147
148         flags = ID_USERID;
149         id.uid = uid;
150         
151         return idmap_get_sid_from_id(sid, id, flags);
152 }
153
154 /*****************************************************************
155  check idmap if gid is in idmap range, otherwise falls back to
156  the legacy algorithmic mapping.
157  Group mapping is used for gids that maps to Wellknown SIDs
158  Returns SID pointer.
159 *****************************************************************/  
160
161 NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid)
162 {
163         unid_t id;
164         int flags;
165
166         DEBUG(10,("idmap_gid_to_sid: gid = [%d]\n", gid));
167
168         flags = ID_GROUPID;
169         if (!idmap_check_ugid_is_in_free_range(gid)) {
170                 flags |= ID_QUERY_ONLY;
171         }
172
173         id.gid = gid;
174         return idmap_get_sid_from_id(sid, id, flags);
175 }
176
177 /*****************************************************************
178  if it is a foreign sid or it is in idmap rid range check idmap,
179  otherwise falls back to the legacy algorithmic mapping.
180  Returns True if this name is a user sid and the conversion
181  was done correctly, False if not.
182 *****************************************************************/  
183
184 NTSTATUS idmap_sid_to_uid(const DOM_SID *sid, uid_t *uid, uint32 flags)
185 {
186         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
187         unid_t id;
188
189         DEBUG(10,("idmap_sid_to_uid: sid = [%s]\n", sid_string_static(sid)));
190
191         flags |= ID_USERID;
192
193         ret = idmap_get_id_from_sid(&id, &flags, sid);
194         
195         if ( NT_STATUS_IS_OK(ret) ) {
196                 DEBUG(10,("idmap_sid_to_uid: uid = [%d]\n", id.uid));
197                 *uid = id.uid;
198         } 
199
200         return ret;
201
202 }
203
204 /*****************************************************************
205  *THE CANONICAL* convert SID to gid function.
206  if it is a foreign sid or it is in idmap rid range check idmap,
207  otherwise falls back to the legacy algorithmic mapping.
208  Group mapping is used for gids that maps to Wellknown SIDs
209  Returns True if this name is a user sid and the conversion
210  was done correctly, False if not.
211 *****************************************************************/  
212
213 NTSTATUS idmap_sid_to_gid(const DOM_SID *sid, gid_t *gid, uint32 flags)
214 {
215         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
216         unid_t id;
217
218         DEBUG(10,("sid_to_gid: sid = [%s]\n", sid_string_static(sid)));
219
220         flags |= ID_GROUPID;
221
222         ret = idmap_get_id_from_sid(&id, &flags, sid);
223         
224         if ( NT_STATUS_IS_OK(ret) ) 
225         {
226                 DEBUG(10,("idmap_sid_to_gid: gid = [%d]\n", id.gid));
227                 *gid = id.gid;
228         }
229
230         return ret;
231 }
232
233
234 /***************************************************************************
235  Check first, call set_mapping if it doesn't already exist.
236 ***************************************************************************/
237
238 static NTSTATUS wellknown_id_init(DOM_SID *sid, unid_t id, int flags)
239 {
240         unid_t storedid;
241         int qflags = flags | ID_QUERY_ONLY;
242
243         if (!NT_STATUS_IS_OK(idmap_get_id_from_sid(&storedid, &qflags, sid))) {
244                 return idmap_set_mapping(sid, id, flags);
245         } else {
246                 if (flags == ID_USERID && id.uid != storedid.uid) {
247                         DEBUG(0,("wellknown_id_init: WARNING ! Stored uid %u for SID %s is not the same as the requested uid %u\n",
248                                 (unsigned int)storedid.uid, sid_string_static(sid), (unsigned int)id.uid ));
249                         DEBUG(0,("wellknown_id_init: Attempting to overwrite old mapping with new.\n"));
250                         return idmap_set_mapping(sid, id, flags);
251                 } else if (flags == ID_GROUPID && id.gid != storedid.gid) {
252                         DEBUG(0,("wellknown_id_init: WARNING ! Stored gid %u for SID %s is not the same as the requested gid %u\n",
253                                 (unsigned int)storedid.gid, sid_string_static(sid), (unsigned int)id.gid ));
254                         DEBUG(0,("wellknown_id_init: Attempting to overwrite old mapping with new.\n"));
255                         return idmap_set_mapping(sid, id, flags);
256                 }
257         }
258         return NT_STATUS_OK;
259 }
260
261 /***************************************************************************
262  Initialize idmap withWellknown SIDs like Guest, that are necessary
263  to make samba run properly.
264 ***************************************************************************/
265
266 BOOL idmap_init_wellknown_sids(void)
267 {
268         const char *guest_account = lp_guestaccount();
269         struct passwd *pass;
270         GROUP_MAP *map=NULL;
271         int num_entries=0;
272         DOM_SID sid;
273         unid_t id;
274         fstring sid_string;
275
276         if (!(guest_account && *guest_account)) {
277                 DEBUG(1, ("NULL guest account!?!?\n"));
278                 return False;
279         }
280
281         pass = getpwnam_alloc(guest_account);
282         if (!pass) {
283                 return False;
284         }
285
286         /* Fill in the SID for the guest account. */
287         id.uid = pass->pw_uid;
288         sid_copy(&sid, get_global_sam_sid());
289         sid_append_rid(&sid, DOMAIN_USER_RID_GUEST);
290
291         if (!NT_STATUS_IS_OK(wellknown_id_init(&sid, id, ID_USERID))) {
292                 DEBUG(0, ("Failed to setup UID mapping for GUEST (%s) to (%u)\n", 
293                           sid_to_string(sid_string, &sid), (unsigned int)id.uid));
294                 passwd_free(&pass);
295                 return False;
296         }
297
298         /* check if DOMAIN_GROUP_RID_GUESTS SID is set, if not store the
299          * guest account gid as mapping */
300         id.gid = pass->pw_gid;
301         sid_copy(&sid, get_global_sam_sid());
302         sid_append_rid(&sid, DOMAIN_GROUP_RID_GUESTS);
303         if (!NT_STATUS_IS_OK(wellknown_id_init(&sid, id, ID_GROUPID))) {
304                 DEBUG(0, ("Failed to setup GID mapping for Group DOMAIN GUESTS (%s) to (%u)\n", 
305                           sid_to_string(sid_string, &sid), (unsigned int)id.gid));
306                 passwd_free(&pass);
307                 return False;
308         }
309
310         passwd_free(&pass);
311         /* now fill in group mappings */
312         if(pdb_enum_group_mapping(SID_NAME_UNKNOWN, &map, &num_entries, ENUM_ONLY_MAPPED)) {
313                 int i;
314
315                 for (i = 0; i < num_entries; i++) {
316                         id.gid = map[i].gid;
317                         wellknown_id_init(&map[i].sid, id, ID_GROUPID);
318                 }
319                 SAFE_FREE(map);
320         }
321
322         /* Fill in the SID for the administrator account. */
323         id.uid = 0;
324         sid_copy(&sid, get_global_sam_sid());
325         sid_append_rid(&sid, DOMAIN_USER_RID_ADMIN);
326
327         if (!NT_STATUS_IS_OK(wellknown_id_init(&sid, id, ID_USERID))) {
328                 DEBUG(0, ("Failed to setup UID mapping for ADMINISTRATOR (%s) to (%u)\n", 
329                           sid_to_string(sid_string, &sid), (unsigned int)id.uid));
330                 return False;
331         }
332
333         return True;
334 }