r3220: merging current 3.0 code to release branch
[Samba.git] / source / rpc_server / srv_util.c
blobce8e02fae79a43b8fb1636b5457106265bc24468
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-1998
5 * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
6 * Copyright (C) Paul Ashton 1997-1998,
7 * Copyright (C) Andrew Bartlett 2004.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* this module apparently provides an implementation of DCE/RPC over a
25 * named pipe (IPC$ connection using SMBtrans). details of DCE/RPC
26 * documentation are available (in on-line form) from the X-Open group.
28 * this module should provide a level of abstraction between SMB
29 * and DCE/RPC, while minimising the amount of mallocs, unnecessary
30 * data copies, and network traffic.
32 * in this version, which takes a "let's learn what's going on and
33 * get something running" approach, there is additional network
34 * traffic generated, but the code should be easier to understand...
36 * ... if you read the docs. or stare at packets for weeks on end.
40 #include "includes.h"
42 #undef DBGC_CLASS
43 #define DBGC_CLASS DBGC_RPC_SRV
46 * A list of the rids of well known BUILTIN and Domain users
47 * and groups.
50 static const rid_name builtin_alias_rids[] =
52 { BUILTIN_ALIAS_RID_ADMINS , "Administrators" },
53 { BUILTIN_ALIAS_RID_USERS , "Users" },
54 { BUILTIN_ALIAS_RID_GUESTS , "Guests" },
55 { BUILTIN_ALIAS_RID_POWER_USERS , "Power Users" },
57 { BUILTIN_ALIAS_RID_ACCOUNT_OPS , "Account Operators" },
58 { BUILTIN_ALIAS_RID_SYSTEM_OPS , "System Operators" },
59 { BUILTIN_ALIAS_RID_PRINT_OPS , "Print Operators" },
60 { BUILTIN_ALIAS_RID_BACKUP_OPS , "Backup Operators" },
61 { BUILTIN_ALIAS_RID_REPLICATOR , "Replicator" },
62 { 0 , NULL }
65 /* array lookup of well-known Domain RID users. */
66 static const rid_name domain_user_rids[] =
68 { DOMAIN_USER_RID_ADMIN , "Administrator" },
69 { DOMAIN_USER_RID_GUEST , "Guest" },
70 { 0 , NULL }
73 /* array lookup of well-known Domain RID groups. */
74 static const rid_name domain_group_rids[] =
76 { DOMAIN_GROUP_RID_ADMINS , "Domain Admins" },
77 { DOMAIN_GROUP_RID_USERS , "Domain Users" },
78 { DOMAIN_GROUP_RID_GUESTS , "Domain Guests" },
79 { 0 , NULL }
82 /*******************************************************************
83 gets a domain user's groups
84 ********************************************************************/
85 NTSTATUS get_alias_user_groups(TALLOC_CTX *ctx, DOM_SID *sid, int *numgroups, uint32 **prids, DOM_SID *q_sid)
87 SAM_ACCOUNT *sam_pass=NULL;
88 int i, cur_rid=0;
89 gid_t gid;
90 gid_t *groups = NULL;
91 int num_groups;
92 GROUP_MAP map;
93 DOM_SID tmp_sid;
94 fstring user_name;
95 fstring str_domsid, str_qsid;
96 uint32 rid,grid;
97 uint32 *rids=NULL, *new_rids=NULL;
98 gid_t winbind_gid_low, winbind_gid_high;
99 BOOL ret;
100 BOOL winbind_groups_exist;
102 *prids=NULL;
103 *numgroups=0;
105 winbind_groups_exist = lp_idmap_gid(&winbind_gid_low, &winbind_gid_high);
108 DEBUG(10,("get_alias_user_groups: looking if SID %s is a member of groups in the SID domain %s\n",
109 sid_to_string(str_qsid, q_sid), sid_to_string(str_domsid, sid)));
111 pdb_init_sam(&sam_pass);
112 become_root();
113 ret = pdb_getsampwsid(sam_pass, q_sid);
114 unbecome_root();
115 if (ret == False) {
116 pdb_free_sam(&sam_pass);
117 return NT_STATUS_NO_SUCH_USER;
120 fstrcpy(user_name, pdb_get_username(sam_pass));
121 grid=pdb_get_group_rid(sam_pass);
122 if (!NT_STATUS_IS_OK(sid_to_gid(pdb_get_group_sid(sam_pass), &gid))) {
123 /* this should never happen */
124 DEBUG(2,("get_alias_user_groups: sid_to_gid failed!\n"));
125 pdb_free_sam(&sam_pass);
126 return NT_STATUS_UNSUCCESSFUL;
129 ret = getgroups_user(user_name, &groups, &num_groups);
130 if (!ret) {
131 /* this should never happen */
132 DEBUG(2,("get_alias_user_groups: getgroups_user failed\n"));
133 pdb_free_sam(&sam_pass);
134 return NT_STATUS_UNSUCCESSFUL;
137 for (i=0;i<num_groups;i++) {
139 become_root();
140 ret = get_group_from_gid(groups[i], &map);
141 unbecome_root();
143 if ( !ret ) {
144 DEBUG(10,("get_alias_user_groups: gid %d. not found\n", (int)groups[i]));
145 continue;
148 /* if it's not an alias, continue */
149 if (map.sid_name_use != SID_NAME_ALIAS) {
150 DEBUG(10,("get_alias_user_groups: not returing %s, not an ALIAS group.\n", map.nt_name));
151 continue;
154 sid_copy(&tmp_sid, &map.sid);
155 sid_split_rid(&tmp_sid, &rid);
157 /* if the sid is not in the correct domain, continue */
158 if (!sid_equal(&tmp_sid, sid)) {
159 DEBUG(10,("get_alias_user_groups: not returing %s, not in the domain SID.\n", map.nt_name));
160 continue;
163 /* Don't return winbind groups as they are not local! */
164 if (winbind_groups_exist && (groups[i] >= winbind_gid_low) && (groups[i] <= winbind_gid_high)) {
165 DEBUG(10,("get_alias_user_groups: not returing %s, not local.\n", map.nt_name));
166 continue;
169 /* Don't return user private groups... */
170 if (Get_Pwnam(map.nt_name) != 0) {
171 DEBUG(10,("get_alias_user_groups: not returing %s, clashes with user.\n", map.nt_name));
172 continue;
175 new_rids=(uint32 *)Realloc(rids, sizeof(uint32)*(cur_rid+1));
176 if (new_rids==NULL) {
177 DEBUG(10,("get_alias_user_groups: could not realloc memory\n"));
178 pdb_free_sam(&sam_pass);
179 free(groups);
180 return NT_STATUS_NO_MEMORY;
182 rids=new_rids;
184 sid_peek_rid(&map.sid, &(rids[cur_rid]));
185 cur_rid++;
186 break;
189 if(num_groups)
190 free(groups);
192 /* now check for the user's gid (the primary group rid) */
193 for (i=0; i<cur_rid && grid!=rids[i]; i++)
196 /* the user's gid is already there */
197 if (i!=cur_rid) {
198 DEBUG(10,("get_alias_user_groups: user is already in the list. good.\n"));
199 goto done;
202 DEBUG(10,("get_alias_user_groups: looking for gid %d of user %s\n", (int)gid, user_name));
204 if(!get_group_from_gid(gid, &map)) {
205 DEBUG(0,("get_alias_user_groups: gid of user %s doesn't exist. Check your "
206 "/etc/passwd and /etc/group files\n", user_name));
207 goto done;
210 /* the primary group isn't an alias */
211 if (map.sid_name_use!=SID_NAME_ALIAS) {
212 DEBUG(10,("get_alias_user_groups: not returing %s, not an ALIAS group.\n", map.nt_name));
213 goto done;
216 sid_copy(&tmp_sid, &map.sid);
217 sid_split_rid(&tmp_sid, &rid);
219 /* if the sid is not in the correct domain, continue */
220 if (!sid_equal(&tmp_sid, sid)) {
221 DEBUG(10,("get_alias_user_groups: not returing %s, not in the domain SID.\n", map.nt_name));
222 goto done;
225 /* Don't return winbind groups as they are not local! */
226 if (winbind_groups_exist && (gid >= winbind_gid_low) && (gid <= winbind_gid_high)) {
227 DEBUG(10,("get_alias_user_groups: not returing %s, not local.\n", map.nt_name ));
228 goto done;
231 /* Don't return user private groups... */
232 if (Get_Pwnam(map.nt_name) != 0) {
233 DEBUG(10,("get_alias_user_groups: not returing %s, clashes with user.\n", map.nt_name ));
234 goto done;
237 new_rids=(uint32 *)Realloc(rids, sizeof(uint32)*(cur_rid+1));
238 if (new_rids==NULL) {
239 DEBUG(10,("get_alias_user_groups: could not realloc memory\n"));
240 pdb_free_sam(&sam_pass);
241 return NT_STATUS_NO_MEMORY;
243 rids=new_rids;
245 sid_peek_rid(&map.sid, &(rids[cur_rid]));
246 cur_rid++;
248 done:
249 *prids=rids;
250 *numgroups=cur_rid;
251 pdb_free_sam(&sam_pass);
253 return NT_STATUS_OK;
257 /*******************************************************************
258 gets a domain user's groups
259 ********************************************************************/
260 BOOL get_domain_user_groups(TALLOC_CTX *ctx, int *numgroups, DOM_GID **pgids, SAM_ACCOUNT *sam_pass)
263 const char *username = pdb_get_username(sam_pass);
264 int n_unix_groups;
265 int i,j;
266 gid_t *unix_groups;
268 *numgroups = 0;
269 *pgids = NULL;
271 if (!getgroups_user(username, &unix_groups, &n_unix_groups)) {
272 return False;
275 /* now setup the space for storing the SIDS */
277 if (n_unix_groups > 0) {
279 *pgids = talloc(ctx, sizeof(DOM_GID) * n_unix_groups);
281 if (!*pgids) {
282 DEBUG(0, ("get_user_group: malloc() failed for DOM_GID list!\n"));
283 SAFE_FREE(unix_groups);
284 return False;
288 become_root();
289 j = 0;
290 for (i = 0; i < n_unix_groups; i++) {
291 GROUP_MAP map;
292 uint32 rid;
294 if (!pdb_getgrgid(&map, unix_groups[i])) {
295 DEBUG(3, ("get_user_groups: failed to convert gid %ld to a domain group!\n",
296 (long int)unix_groups[i+1]));
297 if (i == 0) {
298 DEBUG(1,("get_domain_user_groups: primary gid of user [%s] is not a Domain group !\n", username));
299 DEBUGADD(1,("get_domain_user_groups: You should fix it, NT doesn't like that\n"));
301 } else if ((map.sid_name_use == SID_NAME_DOM_GRP)
302 && sid_peek_check_rid(get_global_sam_sid(), &map.sid, &rid)) {
303 (*pgids)[j].attr=7;
304 (*pgids)[j].g_rid=rid;
305 j++;
308 unbecome_root();
310 *numgroups = j;
312 SAFE_FREE(unix_groups);
314 return True;
317 /*******************************************************************
318 gets a domain user's groups from their already-calculated NT_USER_TOKEN
319 ********************************************************************/
320 NTSTATUS nt_token_to_group_list(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
321 const NT_USER_TOKEN *nt_token,
322 int *numgroups, DOM_GID **pgids)
324 DOM_GID *gids;
325 int i;
327 gids = (DOM_GID *)talloc(mem_ctx, sizeof(*gids) * nt_token->num_sids);
329 if (!gids) {
330 return NT_STATUS_NO_MEMORY;
333 *numgroups=0;
335 for (i=PRIMARY_GROUP_SID_INDEX; i < nt_token->num_sids; i++) {
336 if (sid_compare_domain(domain_sid, &nt_token->user_sids[i])==0) {
337 sid_peek_rid(&nt_token->user_sids[i], &(gids[*numgroups].g_rid));
338 gids[*numgroups].attr=7;
339 (*numgroups)++;
342 *pgids = gids;
343 return NT_STATUS_OK;