*id_to_*id call reshape to return NTSTATUS errors
[ira/wip.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 < low || rid > high) {
60                 return False;
61         }
62         return True;
63 }
64
65 /******************************************************************
66  * Get the the non-algorithmic RID range if idmap range are defined
67  ******************************************************************/
68
69 BOOL idmap_get_free_rid_range(uint32 *low, uint32 *high)
70 {
71         uint32 id_low, id_high;
72
73         if (lp_idmap_only()) {
74                 *low = BASE_RID;
75                 *high = (uint32)-1;
76         }
77
78         if (!idmap_get_free_ugid_range(&id_low, &id_high)) {
79                 return False;
80         }
81
82         *low = fallback_pdb_uid_to_user_rid(id_low);
83         if (fallback_pdb_user_rid_to_uid((uint32)-1) < id_high) {
84                 *high = (uint32)-1;
85         } else {
86                 *high = fallback_pdb_uid_to_user_rid(id_high);
87         }
88
89         return True;
90 }
91
92 BOOL idmap_get_free_ugid_range(uint32 *low, uint32 *high)
93 {
94         uid_t u_low, u_high;
95         gid_t g_low, g_high;
96
97         if (!lp_idmap_uid(&u_low, &u_high) || !lp_idmap_gid(&g_low, &g_high)) {
98                 return False;
99         }
100         if (u_low < g_low) {
101                 *low = u_low;
102         } else {
103                 *low = g_low;
104         }
105         if (u_high < g_high) {
106                 *high = g_high;
107         } else {
108                 *high = u_high;
109         }
110         return True;
111 }
112
113 /*****************************************************************
114  *THE CANONICAL* convert uid_t to SID function.
115  check idmap if uid is in idmap range, otherwise falls back to
116  the legacy algorithmic mapping.
117  A special cache is used for uids that maps to Wellknown SIDs
118  Returns SID pointer.
119 *****************************************************************/  
120
121 NTSTATUS uid_to_sid(DOM_SID *sid, uid_t uid)
122 {
123         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
124         unid_t id;
125         int flags;
126
127         DEBUG(10,("uid_to_sid: uid = [%d]\n", uid));
128
129         flags = ID_USERID;
130         if (!lp_idmap_only() && !idmap_check_ugid_is_in_free_range(uid)) {
131                 flags |= ID_NOMAP;
132         }
133
134         id.uid = uid;
135         if (NT_STATUS_IS_ERR(ret = idmap_get_sid_from_id(sid, id, flags))) {
136                 DEBUG(10, ("uid_to_sid: Failed to map sid = [%s]\n", sid_string_static(sid)));
137                 if (flags & ID_NOMAP) {
138                         sid_copy(sid, get_global_sam_sid());
139                         sid_append_rid(sid, fallback_pdb_uid_to_user_rid(uid));
140
141                         DEBUG(10,("uid_to_sid: Fall back to algorithmic mapping: %u -> %s\n", (unsigned int)uid, sid_string_static(sid)));
142                         ret = NT_STATUS_OK;
143                 }
144         }
145
146         return ret;
147 }
148
149 /*****************************************************************
150  *THE CANONICAL* convert gid_t to SID function.
151  check idmap if gid is in idmap range, otherwise falls back to
152  the legacy algorithmic mapping.
153  Group mapping is used for gids that maps to Wellknown SIDs
154  Returns SID pointer.
155 *****************************************************************/  
156
157 NTSTATUS gid_to_sid(DOM_SID *sid, gid_t gid)
158 {
159         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
160         GROUP_MAP map;
161         unid_t id;
162         int flags;
163
164         DEBUG(10,("gid_to_sid: gid = [%d]\n", gid));
165
166         flags = ID_GROUPID;
167         if (!lp_idmap_only() && !idmap_check_ugid_is_in_free_range(gid)) {
168                 flags |= ID_NOMAP;
169         }
170
171         id.gid = gid;
172         if (NT_STATUS_IS_ERR(ret = idmap_get_sid_from_id(sid, id, flags))) {
173                 DEBUG(10, ("gid_to_sid: Failed to map sid = [%s]\n", sid_string_static(sid)));
174                 if (flags & ID_NOMAP) {
175                         if (pdb_getgrgid(&map, gid, MAPPING_WITHOUT_PRIV)) {
176                                 sid_copy(sid, &map.sid);
177                         } else {
178                                 sid_copy(sid, get_global_sam_sid());
179                                 sid_append_rid(sid, pdb_gid_to_group_rid(gid));
180                         }
181
182                         DEBUG(10,("gid_to_sid: Fall back to algorithmic mapping: %u -> %s\n", (unsigned int)gid, sid_string_static(sid)));
183                         ret = NT_STATUS_OK;
184                 }
185         }
186
187         return ret;
188 }
189
190 /*****************************************************************
191  *THE CANONICAL* convert SID to uid function.
192  if it is a foreign sid or it is in idmap rid range check idmap,
193  otherwise falls back to the legacy algorithmic mapping.
194  A special cache is used for uids that maps to Wellknown SIDs
195  Returns True if this name is a user sid and the conversion
196  was done correctly, False if not.
197 *****************************************************************/  
198
199 NTSTATUS sid_to_uid(const DOM_SID *sid, uid_t *uid)
200 {
201         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
202         BOOL fallback = False;
203         uint32 rid;
204         unid_t id;
205         int flags;
206
207         DEBUG(10,("sid_to_uid: sid = [%s]\n", sid_string_static(sid)));
208
209         flags = ID_USERID;
210         if (!lp_idmap_only()) {
211                 if (sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) {
212                         if (!idmap_check_rid_is_in_free_range(rid)) {
213                                 flags |= ID_NOMAP;
214                                 fallback = True;
215                         }
216                 }
217         }
218
219         if (NT_STATUS_IS_OK(idmap_get_id_from_sid(&id, &flags, sid))) {
220                 DEBUG(10,("sid_to_uid: uid = [%d]\n", id.uid));
221                 *uid = id.uid;
222                 ret = NT_STATUS_OK;
223         } else if (fallback) {
224                 DEBUG(10,("sid_to_uid: Fall back to algorithmic mapping\n"));
225                 if (!fallback_pdb_rid_is_user(rid)) {
226                         DEBUG(3, ("sid_to_uid: SID %s is *NOT* a user\n", sid_string_static(sid)));
227                         ret = NT_STATUS_UNSUCCESSFUL;
228                 } else {
229                         *uid = fallback_pdb_user_rid_to_uid(rid);
230                         DEBUG(10,("sid_to_uid: mapping: %s -> %u\n", sid_string_static(sid), (unsigned int)(*uid)));
231                         ret = NT_STATUS_OK;
232                 }
233         }
234
235         return ret;
236 }
237
238 /*****************************************************************
239  *THE CANONICAL* convert SID to gid function.
240  if it is a foreign sid or it is in idmap rid range check idmap,
241  otherwise falls back to the legacy algorithmic mapping.
242  Group mapping is used for gids that maps to Wellknown SIDs
243  Returns True if this name is a user sid and the conversion
244  was done correctly, False if not.
245 *****************************************************************/  
246
247 NTSTATUS sid_to_gid(const DOM_SID *sid, gid_t *gid)
248 {
249         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
250         BOOL fallback = False;
251         uint32 rid;
252         unid_t id;
253         int flags;
254
255         DEBUG(10,("sid_to_gid: sid = [%s]\n", sid_string_static(sid)));
256
257         flags = ID_GROUPID;
258         if (!lp_idmap_only()) {
259                 if (sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) {
260                         if (!idmap_check_rid_is_in_free_range(rid)) {
261                                 flags |= ID_NOMAP;
262                                 fallback = True;
263                         }
264                 }
265         }
266
267         if (NT_STATUS_IS_OK(idmap_get_id_from_sid(&id, &flags, sid))) {
268                 DEBUG(10,("sid_to_gid: gid = [%d]\n", id.gid));
269                 *gid = id.gid;
270                 ret = NT_STATUS_OK;
271         } else if (fallback) {
272                 GROUP_MAP map;
273                 BOOL result;
274
275                 DEBUG(10,("sid_to_gid: Fall back to algorithmic mapping\n"));
276
277                 /* the group mapping code should register mappings in idmap
278                  * and have the following if() eliminated */
279                 if (pdb_getgrsid(&map, *sid, MAPPING_WITHOUT_PRIV)) {
280                         /* the SID is in the mapping table but not mapped */
281                         if (map.gid==(gid_t)-1) {
282                                 ret = NT_STATUS_UNSUCCESSFUL;
283                         } else {
284                                 *gid = map.gid;
285                                 ret = NT_STATUS_OK;
286                         }
287                 } else {
288                         if (fallback_pdb_rid_is_user(rid)) {
289                                 DEBUG(3, ("sid_to_gid: SID %s is *NOT* a group\n", sid_string_static(sid)));
290                                 ret = NT_STATUS_UNSUCCESSFUL;
291                         } else {
292                                 *gid = pdb_group_rid_to_gid(rid);
293                                 DEBUG(10,("sid_to_gid: mapping: %s -> %u\n", sid_string_static(sid), (unsigned int)(*gid)));
294                                 ret = NT_STATUS_OK;
295                         }
296                 }
297         }
298
299         return ret;
300 }