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