3 * Unix SMB/Netbios implementation.
5 * RPC Pipe client / server routines
6 * Copyright (C) Andrew Tridgell 1992-1998
7 * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
8 * Copyright (C) Paul Ashton 1997-1998.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /* this module apparently provides an implementation of DCE/RPC over a
26 * named pipe (IPC$ connection using SMBtrans). details of DCE/RPC
27 * documentation are available (in on-line form) from the X-Open group.
29 * this module should provide a level of abstraction between SMB
30 * and DCE/RPC, while minimising the amount of mallocs, unnecessary
31 * data copies, and network traffic.
33 * in this version, which takes a "let's learn what's going on and
34 * get something running" approach, there is additional network
35 * traffic generated, but the code should be easier to understand...
37 * ... if you read the docs. or stare at packets for weeks on end.
44 extern int DEBUGLEVEL;
46 /* array lookup of well-known RID aliases. the purpose of these escapes me.. */
47 /* XXXX this structure should not have the well-known RID groups added to it,
48 i.e the DOMAIN_GROUP_RID_ADMIN/USER/GUEST. */
49 rid_name domain_alias_rids[] =
51 { DOMAIN_ALIAS_RID_ADMINS , "admins" },
52 { DOMAIN_ALIAS_RID_USERS , "users" },
53 { DOMAIN_ALIAS_RID_GUESTS , "guests" },
54 { DOMAIN_ALIAS_RID_POWER_USERS , "power_users" },
56 { DOMAIN_ALIAS_RID_ACCOUNT_OPS , "account_ops" },
57 { DOMAIN_ALIAS_RID_SYSTEM_OPS , "system_ops" },
58 { DOMAIN_ALIAS_RID_PRINT_OPS , "print_ops" },
59 { DOMAIN_ALIAS_RID_BACKUP_OPS , "backup_ops" },
60 { DOMAIN_ALIAS_RID_REPLICATOR , "replicator" },
64 /* array lookup of well-known Domain RID groups. */
65 rid_name domain_group_rids[] =
67 { DOMAIN_GROUP_RID_ADMINS , "domain admins" },
68 { DOMAIN_GROUP_RID_USERS , "domain users" },
69 { DOMAIN_GROUP_RID_GUESTS , "domain guests" },
75 int make_dom_gids(char *gids_str, DOM_GID *gids)
81 DEBUG(4,("make_dom_gids: %s\n", gids_str));
83 if (gids_str == NULL || *gids_str == 0) return 0;
85 for (count = 0, ptr = gids_str; next_token(&ptr, s2, NULL) && count < LSA_MAX_GROUPS; count++)
87 /* the entries are of the form GID/ATTR, ATTR being optional.*/
92 attr = strchr(s2,'/');
93 if (attr) *attr++ = 0;
94 if (!attr || !*attr) attr = "7"; /* default value for attribute is 7 */
96 /* look up the RID string and see if we can turn it into a rid number */
97 for (i = 0; domain_alias_rids[i].name != NULL; i++)
99 if (strequal(domain_alias_rids[i].name, s2))
101 rid = domain_alias_rids[i].rid;
106 if (rid == 0) rid = atoi(s2);
110 DEBUG(1,("make_dom_gids: unknown well-known alias RID %s/%s\n",
116 gids[count].g_rid = rid;
117 gids[count].attr = atoi(attr);
119 DEBUG(5,("group id: %d attr: %d\n",
128 /*******************************************************************
129 gets a domain user's groups
130 ********************************************************************/
131 void get_domain_user_groups(char *domain_groups, char *user)
135 if (domain_groups == NULL || user == NULL) return;
137 /* any additional groups this user is in. e.g power users */
138 pstrcpy(domain_groups, lp_domain_groups());
140 /* can only be a user or a guest. cannot be guest _and_ admin */
141 if (user_in_list(user, lp_domain_guest_users()))
143 sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_GUESTS);
144 strcat(domain_groups, tmp);
146 DEBUG(3,("domain guest access %s granted\n", tmp));
150 sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_USERS);
151 strcat(domain_groups, tmp);
153 DEBUG(3,("domain user access %s granted\n", tmp));
155 if (user_in_list(user, lp_domain_admin_users()))
157 sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_ADMINS);
158 strcat(domain_groups, tmp);
160 DEBUG(3,("domain admin access %s granted\n", tmp));
166 /*******************************************************************
167 turns a DCE/RPC request into a DCE/RPC reply
169 this is where the data really should be split up into an array of
170 headers and data sections.
172 ********************************************************************/
173 BOOL create_rpc_reply(pipes_struct *p,
174 uint32 data_start, uint32 data_end)
176 mem_buf_init(&(p->rhdr.data), 0);
177 mem_alloc_data(p->rhdr.data, 0x18);
182 p->hdr_rr.alloc_hint = data_end - data_start; /* calculate remaining data to be sent */
183 p->hdr.pkt_type = RPC_RESPONSE; /* mark header as an rpc response */
185 /* set up rpc header (fragmentation issues) */
188 p->hdr.flags = RPC_FLG_FIRST;
195 if (p->hdr_rr.alloc_hint + 0x18 <= p->hdr_ba.bba.max_tsize)
197 p->hdr.flags |= RPC_FLG_LAST;
198 p->hdr.frag_len = p->hdr_rr.alloc_hint + 0x18;
202 p->hdr.frag_len = p->hdr_ba.bba.max_tsize;
205 p->rhdr.data->offset.start = 0;
206 p->rhdr.data->offset.end = 0x18;
208 /* store the header in the data stream */
210 smb_io_rpc_hdr ("hdr", &(p->hdr ), &(p->rhdr), 0);
211 smb_io_rpc_hdr_rr("rr" , &(p->hdr_rr), &(p->rhdr), 0);
213 return p->rhdr.data != NULL && p->rhdr.offset == 0x18;
217 /*******************************************************************
218 receives a netlogon pipe and responds.
219 ********************************************************************/
220 static BOOL api_rpc_command(pipes_struct *p,
221 char *rpc_name, struct api_struct *api_rpc_cmds,
225 DEBUG(4,("api_rpc_command: %s op 0x%x - ", rpc_name, p->hdr_rr.opnum));
227 for (fn_num = 0; api_rpc_cmds[fn_num].name; fn_num++)
229 if (api_rpc_cmds[fn_num].opnum == p->hdr_rr.opnum && api_rpc_cmds[fn_num].fn != NULL)
231 DEBUG(3,("api_rpc_command: %s\n", api_rpc_cmds[fn_num].name));
236 if (api_rpc_cmds[fn_num].name == NULL)
238 DEBUG(4, ("unknown\n"));
242 /* start off with 1024 bytes, and a large safety margin too */
243 mem_buf_init(&(p->rdata.data), SAFETY_MARGIN);
244 mem_alloc_data(p->rdata.data, 1024);
249 p->rdata.data->offset.start = 0;
250 p->rdata.data->offset.end = 0xffffffff;
252 /* do the actual command */
254 api_rpc_cmds[fn_num].fn(p->uid, data, &(p->rdata));
256 if (p->rdata.data == NULL || p->rdata.offset == 0)
258 mem_free_data(p->rdata.data);
262 mem_realloc_data(p->rdata.data, p->rdata.offset);
264 DEBUG(10,("called %s\n", rpc_name));
270 /*******************************************************************
271 receives a netlogon pipe and responds.
272 ********************************************************************/
273 BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds,
276 if (data == NULL || data->data == NULL)
278 DEBUG(2,("%s: NULL data received\n", rpc_name));
282 /* read the rpc header */
283 smb_io_rpc_hdr_rr("", &(p->hdr_rr), data, 0);
285 /* interpret the command */
286 if (!api_rpc_command(p, rpc_name, api_rpc_cmds, data))
291 /* create the rpc header */
292 if (!create_rpc_reply(p, 0, p->rdata.offset))
297 /* set up the data chain */
298 p->rhdr.data->offset.start = 0;
299 p->rhdr.data->offset.end = p->rhdr.offset;
300 p->rhdr.data->next = p->rdata.data;
302 p->rdata.data->offset.start = p->rhdr.data->offset.end;
303 p->rdata.data->offset.end = p->rhdr.data->offset.end + p->rdata.offset;
304 p->rdata.data->next = NULL;
309 extern rid_name domain_group_rids[];
311 /*******************************************************************
313 ********************************************************************/
314 uint32 lookup_group_name(uint32 rid, char *group_name, uint32 *type)
317 (*type) = SID_NAME_DOM_GRP;
319 while (domain_group_rids[i].rid != rid && domain_group_rids[i].rid != 0)
324 if (domain_group_rids[i].rid != 0)
326 fstrcpy(group_name, domain_group_rids[i].name);
330 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
333 extern rid_name domain_alias_rids[];
335 /*******************************************************************
337 ********************************************************************/
338 uint32 lookup_alias_name(uint32 rid, char *alias_name, uint32 *type)
341 (*type) = SID_NAME_WKN_GRP;
343 while (domain_alias_rids[i].rid != rid && domain_alias_rids[i].rid != 0)
348 if (domain_alias_rids[i].rid != 0)
350 fstrcpy(alias_name, domain_alias_rids[i].name);
354 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
357 /*******************************************************************
359 ********************************************************************/
360 uint32 lookup_user_name(uint32 rid, char *user_name, uint32 *type)
362 struct smb_passwd *smb_pass;
363 (*type) = SID_NAME_USER;
365 /* find the user account */
367 smb_pass = get_smbpwd_entry(NULL, rid); /* lkclXXXX SHOULD use rid mapping here! */
370 if (smb_pass != NULL)
372 fstrcpy(user_name, smb_pass->smb_name);
376 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
379 /*******************************************************************
381 ********************************************************************/
382 uint32 lookup_group_rid(char *group_name, uint32 *rid)
385 int i = -1; /* start do loop at -1 */
387 do /* find, if it exists, a group rid for the group name*/
390 (*rid) = domain_group_rids[i].rid;
391 grp_name = domain_group_rids[i].name;
393 } while (grp_name != NULL && !strequal(grp_name, group_name));
395 return (grp_name != NULL) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED;
398 /*******************************************************************
400 ********************************************************************/
401 uint32 lookup_alias_rid(char *alias_name, uint32 *rid)
404 int i = -1; /* start do loop at -1 */
406 do /* find, if it exists, a alias rid for the alias name*/
409 (*rid) = domain_alias_rids[i].rid;
410 als_name = domain_alias_rids[i].name;
412 } while (als_name != NULL && !strequal(als_name, alias_name));
414 return (als_name != NULL) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED;
417 /*******************************************************************
419 ********************************************************************/
420 uint32 lookup_user_rid(char *user_name, uint32 *rid)
422 struct smb_passwd *smb_pass;
425 /* find the user account */
427 smb_pass = get_smbpwd_entry(user_name, 0);
430 if (smb_pass != NULL)
432 /* lkclXXXX SHOULD use name_to_rid() here! */
433 (*rid) = smb_pass->smb_userid;
437 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
440 /*******************************************************************
441 Group and User RID username mapping function
442 ********************************************************************/
443 BOOL name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid)
445 struct passwd *pw = Get_Pwnam(user_name, False);
447 if (u_rid == NULL || g_rid == NULL || user_name == NULL)
454 DEBUG(1,("Username %s is invalid on this system\n", user_name));
458 if (user_in_list(user_name, lp_domain_guest_users()))
460 *u_rid = DOMAIN_USER_RID_GUEST;
462 else if (user_in_list(user_name, lp_domain_admin_users()))
464 *u_rid = DOMAIN_USER_RID_ADMIN;
468 /* turn the unix UID into a Domain RID. this is what the posix
469 sub-system does (adds 1000 to the uid) */
470 *u_rid = (uint32)(pw->pw_uid + 1000);
473 /* absolutely no idea what to do about the unix GID to Domain RID mapping */
474 *g_rid = (uint32)(pw->pw_gid + 1000);