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