"For I have laboured mightily on Luke's code, and hath broken
[samba.git] / source3 / rpc_server / srv_util.c
1
2 /* 
3  *  Unix SMB/Netbios implementation.
4  *  Version 1.9.
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.
9  *  
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.
14  *  
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.
19  *  
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.
23  */
24
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.
28  *
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.
32  *
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...
36  *
37  *  ... if you read the docs.  or stare at packets for weeks on end.
38  *
39  */
40
41 #include "includes.h"
42 #include "nterr.h"
43
44 extern int DEBUGLEVEL;
45
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[] = 
50 {
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" },
55
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" },
61         { 0                             , NULL }
62 };
63
64 /* array lookup of well-known Domain RID groups. */
65 rid_name domain_group_rids[] = 
66 {
67         { DOMAIN_GROUP_RID_ADMINS       , "domain admins" },
68         { DOMAIN_GROUP_RID_USERS        , "domain users" },
69         { DOMAIN_GROUP_RID_GUESTS       , "domain guests" },
70         { 0                             , NULL }
71 };
72
73
74
75 int make_dom_gids(char *gids_str, DOM_GID *gids)
76 {
77         char *ptr;
78         pstring s2;
79         int count;
80
81         DEBUG(4,("make_dom_gids: %s\n", gids_str));
82
83         if (gids_str == NULL || *gids_str == 0) return 0;
84
85         for (count = 0, ptr = gids_str; next_token(&ptr, s2, NULL) && count < LSA_MAX_GROUPS; count++) 
86         {
87                 /* the entries are of the form GID/ATTR, ATTR being optional.*/
88                 char *attr;
89                 uint32 rid = 0;
90                 int i;
91
92                 attr = strchr(s2,'/');
93                 if (attr) *attr++ = 0;
94                 if (!attr || !*attr) attr = "7"; /* default value for attribute is 7 */
95
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++)
98                 {
99                         if (strequal(domain_alias_rids[i].name, s2))
100                         {
101                                 rid = domain_alias_rids[i].rid;
102                                 break;
103                         }
104                 }
105
106                 if (rid == 0) rid = atoi(s2);
107
108                 if (rid == 0)
109                 {
110                         DEBUG(1,("make_dom_gids: unknown well-known alias RID %s/%s\n",
111                                   s2, attr));
112                         count--;
113                 }
114                 else
115                 {
116                         gids[count].g_rid = rid;
117                         gids[count].attr  = atoi(attr);
118
119                         DEBUG(5,("group id: %d attr: %d\n",
120                                   gids[count].g_rid,
121                                   gids[count].attr));
122                 }
123         }
124
125         return count;
126 }
127
128 /*******************************************************************
129  gets a domain user's groups
130  ********************************************************************/
131 void get_domain_user_groups(char *domain_groups, char *user)
132 {
133         pstring tmp;
134
135         if (domain_groups == NULL || user == NULL) return;
136
137         /* any additional groups this user is in.  e.g power users */
138         pstrcpy(domain_groups, lp_domain_groups());
139
140         /* can only be a user or a guest.  cannot be guest _and_ admin */
141         if (user_in_list(user, lp_domain_guest_users()))
142         {
143                 sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_GUESTS);
144                 strcat(domain_groups, tmp);
145
146                 DEBUG(3,("domain guest access %s granted\n", tmp));
147         }
148         else
149         {
150                 sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_USERS);
151                 strcat(domain_groups, tmp);
152
153                 DEBUG(3,("domain user access %s granted\n", tmp));
154
155                 if (user_in_list(user, lp_domain_admin_users()))
156                 {
157                         sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_ADMINS);
158                         strcat(domain_groups, tmp);
159
160                         DEBUG(3,("domain admin access %s granted\n", tmp));
161                 }
162         }
163 }
164
165
166 /*******************************************************************
167  turns a DCE/RPC request into a DCE/RPC reply
168
169  this is where the data really should be split up into an array of
170  headers and data sections.
171
172  ********************************************************************/
173 BOOL create_rpc_reply(pipes_struct *p,
174                                 uint32 data_start, uint32 data_end)
175 {
176         mem_buf_init(&(p->rhdr.data), 0);
177         mem_alloc_data(p->rhdr.data, 0x18);
178
179         p->rhdr.align = 4;
180         p->rhdr.io = False;
181
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 */
184
185         /* set up rpc header (fragmentation issues) */
186         if (data_start == 0)
187         {
188                 p->hdr.flags = RPC_FLG_FIRST;
189         }
190         else
191         {
192                 p->hdr.flags = 0;
193         }
194
195         if (p->hdr_rr.alloc_hint + 0x18 <= p->hdr_ba.bba.max_tsize)
196         {
197                 p->hdr.flags |= RPC_FLG_LAST;
198                 p->hdr.frag_len = p->hdr_rr.alloc_hint + 0x18;
199         }
200         else
201         {
202                 p->hdr.frag_len = p->hdr_ba.bba.max_tsize;
203         }
204
205         p->rhdr.data->offset.start = 0;
206         p->rhdr.data->offset.end   = 0x18;
207
208         /* store the header in the data stream */
209         p->rhdr.offset = 0;
210         smb_io_rpc_hdr   ("hdr", &(p->hdr   ), &(p->rhdr), 0);
211         smb_io_rpc_hdr_rr("rr" , &(p->hdr_rr), &(p->rhdr), 0);
212
213         return p->rhdr.data != NULL && p->rhdr.offset == 0x18;
214 }
215
216
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,
222                                 prs_struct *data)
223 {
224         int fn_num;
225         DEBUG(4,("api_rpc_command: %s op 0x%x - ", rpc_name, p->hdr_rr.opnum));
226
227         for (fn_num = 0; api_rpc_cmds[fn_num].name; fn_num++)
228         {
229                 if (api_rpc_cmds[fn_num].opnum == p->hdr_rr.opnum && api_rpc_cmds[fn_num].fn != NULL)
230                 {
231                         DEBUG(3,("api_rpc_command: %s\n", api_rpc_cmds[fn_num].name));
232                         break;
233                 }
234         }
235
236         if (api_rpc_cmds[fn_num].name == NULL)
237         {
238                 DEBUG(4, ("unknown\n"));
239                 return False;
240         }
241
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);
245
246         p->rdata.io = False;
247         p->rdata.align = 4;
248
249         p->rdata.data->offset.start = 0;
250         p->rdata.data->offset.end   = 0xffffffff;
251
252         /* do the actual command */
253         p->rdata.offset = 0; 
254         api_rpc_cmds[fn_num].fn(p->uid, data, &(p->rdata));
255
256         if (p->rdata.data == NULL || p->rdata.offset == 0)
257         {
258                 mem_free_data(p->rdata.data);
259                 return False;
260         }
261
262         mem_realloc_data(p->rdata.data, p->rdata.offset);
263
264     DEBUG(10,("called %s\n", rpc_name));
265
266         return True;
267 }
268
269
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,
274                                 prs_struct *data)
275 {
276         if (data == NULL || data->data == NULL)
277         {
278                 DEBUG(2,("%s: NULL data received\n", rpc_name));
279                 return False;
280         }
281
282         /* read the rpc header */
283         smb_io_rpc_hdr_rr("", &(p->hdr_rr), data, 0);
284
285         /* interpret the command */
286         if (!api_rpc_command(p, rpc_name, api_rpc_cmds, data))
287         {
288                 return False;
289         }
290
291         /* create the rpc header */
292         if (!create_rpc_reply(p, 0, p->rdata.offset))
293         {
294                 return False;
295         }
296
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;
301
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;
305
306         return True;
307 }
308
309 extern rid_name domain_group_rids[];
310
311 /*******************************************************************
312  lookup_group_name
313  ********************************************************************/
314 uint32 lookup_group_name(uint32 rid, char *group_name, uint32 *type)
315 {
316         int i = 0; 
317         (*type) = SID_NAME_DOM_GRP;
318
319         while (domain_group_rids[i].rid != rid && domain_group_rids[i].rid != 0)
320         {
321                 i++;
322         }
323
324         if (domain_group_rids[i].rid != 0)
325         {
326                 fstrcpy(group_name, domain_group_rids[i].name);
327                 return 0x0;
328         }
329
330         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
331 }
332
333 extern rid_name domain_alias_rids[];
334
335 /*******************************************************************
336  lookup_alias_name
337  ********************************************************************/
338 uint32 lookup_alias_name(uint32 rid, char *alias_name, uint32 *type)
339 {
340         int i = 0; 
341         (*type) = SID_NAME_WKN_GRP;
342
343         while (domain_alias_rids[i].rid != rid && domain_alias_rids[i].rid != 0)
344         {
345                 i++;
346         }
347
348         if (domain_alias_rids[i].rid != 0)
349         {
350                 fstrcpy(alias_name, domain_alias_rids[i].name);
351                 return 0x0;
352         }
353
354         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
355 }
356
357 /*******************************************************************
358  lookup_user_name
359  ********************************************************************/
360 uint32 lookup_user_name(uint32 rid, char *user_name, uint32 *type)
361 {
362         struct smb_passwd *smb_pass;
363         (*type) = SID_NAME_USER;
364
365         /* find the user account */
366         become_root(True);
367         smb_pass = get_smbpwd_entry(NULL, rid); /* lkclXXXX SHOULD use rid mapping here! */
368         unbecome_root(True);
369
370         if (smb_pass != NULL)
371         {
372                 fstrcpy(user_name, smb_pass->smb_name);
373                 return 0x0;
374         }
375
376         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
377 }
378
379 /*******************************************************************
380  lookup_group_rid
381  ********************************************************************/
382 uint32 lookup_group_rid(char *group_name, uint32 *rid)
383 {
384         char *grp_name;
385         int i = -1; /* start do loop at -1 */
386
387         do /* find, if it exists, a group rid for the group name*/
388         {
389                 i++;
390                 (*rid) = domain_group_rids[i].rid;
391                 grp_name = domain_group_rids[i].name;
392
393         } while (grp_name != NULL && !strequal(grp_name, group_name));
394
395         return (grp_name != NULL) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED;
396 }
397
398 /*******************************************************************
399  lookup_alias_rid
400  ********************************************************************/
401 uint32 lookup_alias_rid(char *alias_name, uint32 *rid)
402 {
403         char *als_name;
404         int i = -1; /* start do loop at -1 */
405
406         do /* find, if it exists, a alias rid for the alias name*/
407         {
408                 i++;
409                 (*rid) = domain_alias_rids[i].rid;
410                 als_name = domain_alias_rids[i].name;
411
412         } while (als_name != NULL && !strequal(als_name, alias_name));
413
414         return (als_name != NULL) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED;
415 }
416
417 /*******************************************************************
418  lookup_user_rid
419  ********************************************************************/
420 uint32 lookup_user_rid(char *user_name, uint32 *rid)
421 {
422         struct smb_passwd *smb_pass;
423         (*rid) = 0;
424
425         /* find the user account */
426         become_root(True);
427         smb_pass = get_smbpwd_entry(user_name, 0);
428         unbecome_root(True);
429
430         if (smb_pass != NULL)
431         {
432                 /* lkclXXXX SHOULD use name_to_rid() here! */
433                 (*rid) = smb_pass->smb_userid;
434                 return 0x0;
435         }
436
437         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
438 }
439
440 /*******************************************************************
441  Group and User RID username mapping function
442  ********************************************************************/
443 BOOL name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid)
444 {
445     struct passwd *pw = Get_Pwnam(user_name, False);
446
447         if (u_rid == NULL || g_rid == NULL || user_name == NULL)
448         {
449                 return False;
450         }
451
452     if (!pw)
453         {
454       DEBUG(1,("Username %s is invalid on this system\n", user_name));
455       return False;
456     }
457
458         if (user_in_list(user_name, lp_domain_guest_users()))
459         {
460                 *u_rid = DOMAIN_USER_RID_GUEST;
461         }
462         else if (user_in_list(user_name, lp_domain_admin_users()))
463         {
464                 *u_rid = DOMAIN_USER_RID_ADMIN;
465         }
466         else
467         {
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);
471         }
472
473         /* absolutely no idea what to do about the unix GID to Domain RID mapping */
474         *g_rid = (uint32)(pw->pw_gid + 1000);
475
476         return True;
477 }