added ASSERT() and ASSERT_ARRAY() macros and sprinkled them liberally
[kai/samba.git] / source / 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 extern DOM_SID global_machine_sid;
46
47 /*
48  * A list of the rids of well known BUILTIN and Domain users
49  * and groups.
50  */
51
52 rid_name builtin_alias_rids[] =
53 {  
54     { BUILTIN_ALIAS_RID_ADMINS       , "Administrators" },
55     { BUILTIN_ALIAS_RID_USERS        , "Users" },
56     { BUILTIN_ALIAS_RID_GUESTS       , "Guests" },
57     { BUILTIN_ALIAS_RID_POWER_USERS  , "Power Users" },
58    
59     { BUILTIN_ALIAS_RID_ACCOUNT_OPS  , "Account Operators" },
60     { BUILTIN_ALIAS_RID_SYSTEM_OPS   , "System Operators" },
61     { BUILTIN_ALIAS_RID_PRINT_OPS    , "Print Operators" },
62     { BUILTIN_ALIAS_RID_BACKUP_OPS   , "Backup Operators" },
63     { BUILTIN_ALIAS_RID_REPLICATOR   , "Replicator" },
64     { 0                             , NULL }
65 };
66
67 /* array lookup of well-known Domain RID users. */
68 rid_name domain_user_rids[] =
69 {  
70     { DOMAIN_USER_RID_ADMIN         , "Administrator" },
71     { DOMAIN_USER_RID_GUEST         , "Guest" },
72     { 0                             , NULL }
73 };
74
75 /* array lookup of well-known Domain RID groups. */
76 rid_name domain_group_rids[] =
77 {  
78     { DOMAIN_GROUP_RID_ADMINS       , "Domain Admins" },
79     { DOMAIN_GROUP_RID_USERS        , "Domain Users" },
80     { DOMAIN_GROUP_RID_GUESTS       , "Domain Guests" },
81     { 0                             , NULL }
82 };
83
84 /**************************************************************************
85  Check if a name matches any of the well known SID values.
86 ***************************************************************************/
87
88 BOOL lookup_wellknown_sid_from_name(char *windows_name, DOM_SID *psid)
89 {
90   rid_name *rnp;
91   int i;
92
93   for( i = 0; builtin_alias_rids[i].name != NULL; i++) {
94     rnp = &builtin_alias_rids[i];
95     if(strequal(rnp->name, windows_name)) {
96       string_to_sid( psid, "S-1-5-32" );
97       ASSERT_ARRAY(psid->sub_auths, psid->num_auths+1);
98       psid->sub_auths[psid->num_auths++] = rnp->rid;
99       return True;
100     }
101   }
102
103   for( i = 0; domain_user_rids[i].name != NULL; i++ ) {
104     rnp = &domain_user_rids[i];
105     if(strequal(rnp->name, windows_name)) {
106       *psid = global_machine_sid;
107       ASSERT_ARRAY(psid->sub_auths, psid->num_auths+1);
108       psid->sub_auths[psid->num_auths++] = rnp->rid;
109       return True;
110     }
111   }
112
113   for( i = 0; domain_group_rids[i].name != NULL; i++ ) {
114     rnp = &domain_group_rids[i];
115     if(strequal(rnp->name, windows_name)) {
116       *psid = global_machine_sid;
117       ASSERT_ARRAY(psid->sub_auths, psid->num_auths+1);
118       psid->sub_auths[psid->num_auths++] = rnp->rid;
119       return True;
120     }
121   }
122
123   return False;
124 }
125
126 int make_dom_gids(char *gids_str, DOM_GID **ppgids)
127 {
128   char *ptr;
129   pstring s2;
130   int count;
131   DOM_GID *gids;
132
133   *ppgids = NULL;
134
135   DEBUG(4,("make_dom_gids: %s\n", gids_str));
136
137   if (gids_str == NULL || *gids_str == 0)
138     return 0;
139
140   for (count = 0, ptr = gids_str; next_token(&ptr, s2, NULL); count++)
141     ;
142
143   gids = (DOM_GID *)malloc( sizeof(DOM_GID) * count );
144   if(!gids)
145   {
146     DEBUG(0,("make_dom_gids: malloc fail !\n"));
147     return 0;
148   }
149
150   for (count = 0, ptr = gids_str; next_token(&ptr, s2, NULL) && 
151                        count < LSA_MAX_GROUPS; count++) 
152   {
153     /* the entries are of the form GID/ATTR, ATTR being optional.*/
154     char *attr;
155     uint32 rid = 0;
156     int i;
157
158     attr = strchr(s2,'/');
159     if (attr)
160       *attr++ = 0;
161
162     if (!attr || !*attr)
163       attr = "7"; /* default value for attribute is 7 */
164
165     /* look up the RID string and see if we can turn it into a rid number */
166     for (i = 0; builtin_alias_rids[i].name != NULL; i++)
167     {
168       if (strequal(builtin_alias_rids[i].name, s2))
169       {
170         rid = builtin_alias_rids[i].rid;
171         break;
172       }
173     }
174
175     if (rid == 0)
176       rid = atoi(s2);
177
178     if (rid == 0)
179     {
180       DEBUG(1,("make_dom_gids: unknown well-known alias RID %s/%s\n", s2, attr));
181       count--;
182     }
183     else
184     {
185       gids[count].g_rid = rid;
186       gids[count].attr  = atoi(attr);
187
188       DEBUG(5,("group id: %d attr: %d\n", gids[count].g_rid, gids[count].attr));
189     }
190   }
191
192   *ppgids = gids;
193   return count;
194 }
195
196 /*******************************************************************
197  turns a DCE/RPC request into a DCE/RPC reply
198
199  this is where the data really should be split up into an array of
200  headers and data sections.
201
202  ********************************************************************/
203 BOOL create_rpc_reply(pipes_struct *p,
204                                 uint32 data_start, uint32 data_end)
205 {
206         DEBUG(5,("create_rpc_reply: data_start: %d data_end: %d max_tsize: %d\n",
207                   data_start, data_end, p->hdr_ba.bba.max_tsize));
208
209         mem_buf_init(&(p->rhdr.data), 0);
210         mem_alloc_data(p->rhdr.data, 0x18);
211
212         p->rhdr.align = 4;
213         p->rhdr.io = False;
214
215         p->hdr_resp.alloc_hint = data_end - data_start; /* calculate remaining data to be sent */
216         p->hdr.pkt_type = RPC_RESPONSE; /* mark header as an rpc response */
217
218         /* set up rpc header (fragmentation issues) */
219         if (data_start == 0)
220         {
221                 p->hdr.flags = RPC_FLG_FIRST;
222         }
223         else
224         {
225                 p->hdr.flags = 0;
226         }
227
228         if (p->hdr_resp.alloc_hint + 0x18 <= p->hdr_ba.bba.max_tsize)
229         {
230                 p->hdr.flags |= RPC_FLG_LAST;
231                 p->hdr.frag_len = p->hdr_resp.alloc_hint + 0x18;
232         }
233         else
234         {
235                 p->hdr.frag_len = p->hdr_ba.bba.max_tsize;
236         }
237
238         p->rhdr.data->offset.start = 0;
239         p->rhdr.data->offset.end   = 0x18;
240
241         /* store the header in the data stream */
242         p->rhdr.offset = 0;
243         smb_io_rpc_hdr   ("hdr", &(p->hdr   ), &(p->rhdr), 0);
244         smb_io_rpc_hdr_resp("resp", &(p->hdr_resp), &(p->rhdr), 0);
245
246         return p->rhdr.data != NULL && p->rhdr.offset == 0x18;
247 }
248
249
250 /*******************************************************************
251  receives a netlogon pipe and responds.
252  ********************************************************************/
253 static BOOL api_rpc_command(pipes_struct *p, 
254                                 char *rpc_name, struct api_struct *api_rpc_cmds,
255                                 prs_struct *data)
256 {
257         int fn_num;
258         DEBUG(4,("api_rpc_command: %s op 0x%x - ", rpc_name, p->hdr_req.opnum));
259
260         for (fn_num = 0; api_rpc_cmds[fn_num].name; fn_num++)
261         {
262                 if (api_rpc_cmds[fn_num].opnum == p->hdr_req.opnum && api_rpc_cmds[fn_num].fn != NULL)
263                 {
264                         DEBUG(3,("api_rpc_command: %s\n", api_rpc_cmds[fn_num].name));
265                         break;
266                 }
267         }
268
269         if (api_rpc_cmds[fn_num].name == NULL)
270         {
271                 DEBUG(4, ("unknown\n"));
272                 return False;
273         }
274
275         /* start off with 1024 bytes, and a large safety margin too */
276         mem_buf_init(&(p->rdata.data), SAFETY_MARGIN);
277         mem_alloc_data(p->rdata.data, 1024);
278
279         p->rdata.io = False;
280         p->rdata.align = 4;
281
282         p->rdata.data->offset.start = 0;
283         p->rdata.data->offset.end   = 0xffffffff;
284
285         /* do the actual command */
286         p->rdata.offset = 0; 
287         api_rpc_cmds[fn_num].fn(p->uid, data, &(p->rdata));
288
289         if (p->rdata.data == NULL || p->rdata.offset == 0)
290         {
291                 mem_free_data(p->rdata.data);
292                 return False;
293         }
294
295         mem_realloc_data(p->rdata.data, p->rdata.offset);
296
297     DEBUG(10,("called %s\n", rpc_name));
298
299         return True;
300 }
301
302
303 /*******************************************************************
304  receives a netlogon pipe and responds.
305  ********************************************************************/
306 BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds,
307                                 prs_struct *data)
308 {
309         if (data == NULL || data->data == NULL)
310         {
311                 DEBUG(2,("%s: NULL data received\n", rpc_name));
312                 return False;
313         }
314
315         /* read the rpc header */
316         smb_io_rpc_hdr_req("req", &(p->hdr_req), data, 0);
317
318         /* interpret the command */
319         if (!api_rpc_command(p, rpc_name, api_rpc_cmds, data))
320         {
321                 return False;
322         }
323
324         /* create the rpc header */
325         if (!create_rpc_reply(p, 0, p->rdata.offset))
326         {
327                 return False;
328         }
329
330         p->frag_len_left   = p->hdr.frag_len - p->file_offset;
331         p->next_frag_start = p->hdr.frag_len; 
332         
333         /* set up the data chain */
334         p->rhdr.data->offset.start = 0;
335         p->rhdr.data->offset.end   = p->rhdr.offset;
336         p->rhdr.data->next = p->rdata.data;
337
338         p->rdata.data->offset.start = p->rhdr.data->offset.end;
339         p->rdata.data->offset.end   = p->rhdr.data->offset.end + p->rdata.offset;
340         p->rdata.data->next = NULL;
341
342         return True;
343 }
344
345
346 /*******************************************************************
347  gets a domain user's groups
348  ********************************************************************/
349 void get_domain_user_groups(char *domain_groups, char *user)
350 {
351         pstring tmp;
352
353         if (domain_groups == NULL || user == NULL) return;
354
355         /* any additional groups this user is in.  e.g power users */
356         pstrcpy(domain_groups, lp_domain_groups());
357
358         /* can only be a user or a guest.  cannot be guest _and_ admin */
359         if (user_in_list(user, lp_domain_guest_group()))
360         {
361                 slprintf(tmp, sizeof(tmp) - 1, " %ld/7 ", DOMAIN_GROUP_RID_GUESTS);
362                 pstrcat(domain_groups, tmp);
363
364                 DEBUG(3,("domain guest group access %s granted\n", tmp));
365         }
366         else
367         {
368                 slprintf(tmp, sizeof(tmp) -1, " %ld/7 ", DOMAIN_GROUP_RID_USERS);
369                 pstrcat(domain_groups, tmp);
370
371                 DEBUG(3,("domain group access %s granted\n", tmp));
372
373                 if (user_in_list(user, lp_domain_admin_group()))
374                 {
375                         slprintf(tmp, sizeof(tmp) - 1, " %ld/7 ", DOMAIN_GROUP_RID_ADMINS);
376                         pstrcat(domain_groups, tmp);
377
378                         DEBUG(3,("domain admin group access %s granted\n", tmp));
379                 }
380         }
381 }
382
383
384 /*******************************************************************
385  lookup_group_name
386  ********************************************************************/
387 uint32 lookup_group_name(uint32 rid, char *group_name, uint32 *type)
388 {
389         int i = 0; 
390         (*type) = SID_NAME_DOM_GRP;
391
392         DEBUG(5,("lookup_group_name: rid: %d", rid));
393
394         while (domain_group_rids[i].rid != rid && domain_group_rids[i].rid != 0)
395         {
396                 i++;
397         }
398
399         if (domain_group_rids[i].rid != 0)
400         {
401                 fstrcpy(group_name, domain_group_rids[i].name);
402                 DEBUG(5,(" = %s\n", group_name));
403                 return 0x0;
404         }
405
406         DEBUG(5,(" none mapped\n"));
407         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
408 }
409
410 /*******************************************************************
411  lookup_alias_name
412  ********************************************************************/
413 uint32 lookup_alias_name(uint32 rid, char *alias_name, uint32 *type)
414 {
415         int i = 0; 
416         (*type) = SID_NAME_WKN_GRP;
417
418         DEBUG(5,("lookup_alias_name: rid: %d", rid));
419
420         while (builtin_alias_rids[i].rid != rid && builtin_alias_rids[i].rid != 0)
421         {
422                 i++;
423         }
424
425         if (builtin_alias_rids[i].rid != 0)
426         {
427                 fstrcpy(alias_name, builtin_alias_rids[i].name);
428                 DEBUG(5,(" = %s\n", alias_name));
429                 return 0x0;
430         }
431
432         DEBUG(5,(" none mapped\n"));
433         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
434 }
435
436 /*******************************************************************
437  lookup_user_name
438  ********************************************************************/
439 uint32 lookup_user_name(uint32 rid, char *user_name, uint32 *type)
440 {
441         struct sam_disp_info *disp_info;
442         int i = 0;
443         (*type) = SID_NAME_USER;
444
445         DEBUG(5,("lookup_user_name: rid: %d", rid));
446
447         /* look up the well-known domain user rids first */
448         while (domain_user_rids[i].rid != rid && domain_user_rids[i].rid != 0)
449         {
450                 i++;
451         }
452
453         if (domain_user_rids[i].rid != 0)
454         {
455                 fstrcpy(user_name, domain_user_rids[i].name);
456                 DEBUG(5,(" = %s\n", user_name));
457                 return 0x0;
458         }
459
460         /* ok, it's a user.  find the user account */
461         become_root(True);
462         disp_info = getsamdisprid(rid);
463         unbecome_root(True);
464
465         if (disp_info != NULL)
466         {
467                 fstrcpy(user_name, disp_info->smb_name);
468                 DEBUG(5,(" = %s\n", user_name));
469                 return 0x0;
470         }
471
472         DEBUG(5,(" none mapped\n"));
473         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
474 }
475
476 /*******************************************************************
477  lookup_group_rid
478  ********************************************************************/
479 uint32 lookup_group_rid(char *group_name, uint32 *rid)
480 {
481         char *grp_name;
482         int i = -1; /* start do loop at -1 */
483
484         do /* find, if it exists, a group rid for the group name*/
485         {
486                 i++;
487                 (*rid) = domain_group_rids[i].rid;
488                 grp_name = domain_group_rids[i].name;
489
490         } while (grp_name != NULL && !strequal(grp_name, group_name));
491
492         return (grp_name != NULL) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED;
493 }
494
495 /*******************************************************************
496  lookup_alias_rid
497  ********************************************************************/
498 uint32 lookup_alias_rid(char *alias_name, uint32 *rid)
499 {
500         char *als_name;
501         int i = -1; /* start do loop at -1 */
502
503         do /* find, if it exists, a alias rid for the alias name*/
504         {
505                 i++;
506                 (*rid) = builtin_alias_rids[i].rid;
507                 als_name = builtin_alias_rids[i].name;
508
509         } while (als_name != NULL && !strequal(als_name, alias_name));
510
511         return (als_name != NULL) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED;
512 }
513
514 /*******************************************************************
515  lookup_user_rid
516  ********************************************************************/
517 uint32 lookup_user_rid(char *user_name, uint32 *rid)
518 {
519         struct smb_passwd *smb_pass;
520         (*rid) = 0;
521
522         /* find the user account */
523         become_root(True);
524         smb_pass = getsmbpwnam(user_name);
525         unbecome_root(True);
526
527         if (smb_pass != NULL)
528         {
529                 /* lkclXXXX SHOULD use name_to_rid() here! */
530                 (*rid) = smb_pass->smb_userid;
531                 return 0x0;
532         }
533
534         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
535 }