first public release of samba4 code
[samba.git] / source / sam / gums_helper.c
1 /*
2    Unix SMB/CIFS implementation.
3    GUMS backends helper functions
4    Copyright (C) Simo Sorce 2002
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
21 #include "includes.h"
22
23 extern GUMS_FUNCTIONS *gums_storage;
24
25 extern DOM_SID global_sid_World;
26 extern DOM_SID global_sid_Builtin_Administrators;
27 extern DOM_SID global_sid_Builtin_Power_Users;
28 extern DOM_SID global_sid_Builtin_Account_Operators;
29 extern DOM_SID global_sid_Builtin_Server_Operators;
30 extern DOM_SID global_sid_Builtin_Print_Operators;
31 extern DOM_SID global_sid_Builtin_Backup_Operators;
32 extern DOM_SID global_sid_Builtin_Replicator;
33 extern DOM_SID global_sid_Builtin_Users;
34 extern DOM_SID global_sid_Builtin_Guests;
35
36
37 /* defines */
38
39 #define ALLOC_CHECK(str, ptr, err, label) do { if ((ptr) == NULL) { DEBUG(0, ("%s: out of memory!\n", str)); err = NT_STATUS_NO_MEMORY; goto label; } } while(0)
40 #define NTSTATUS_CHECK(str1, str2, err, label) do { if (NT_STATUS_IS_ERR(err)) { DEBUG(0, ("%s: %s failed!\n", str1, str2)); } } while(0)
41
42 /****************************************************************************
43  Check if a user is a mapped group.
44
45    This function will check if the group SID is mapped onto a
46    system managed gid or onto a winbind manged sid.
47    In the first case it will be threated like a mapped group
48    and the backend should take the member list with a getgrgid
49    and ignore any user that have been possibly set into the group
50    object.
51
52    In the second case, the group is a fully SAM managed group
53    served back to the system through winbind. In this case the
54    members of a Local group are "unrolled" to cope with the fact
55    that unix cannot contain groups inside groups.
56    The backend MUST never call any getgr* / getpw* function or
57    loops with winbind may happen. 
58  ****************************************************************************/
59
60 /*
61 NTSTATUS is_mapped_group(BOOL *mapped, const DOM_SID *sid)
62 {
63         NTSTATUS result;
64         gid_t id;
65
66         /* look if mapping exist, do not make idmap alloc an uid if SID is not found * /
67         result = idmap_get_gid_from_sid(&id, sid, False);
68         if (NT_STATUS_IS_OK(result)) {
69                 *mapped = gid_is_in_winbind_range(id);
70         } else {
71                 *mapped = False;
72         }
73
74         return result;
75 }
76 */
77
78 /****************************************************************************
79  duplicate alloc luid_attr
80  ****************************************************************************/
81 NTSTATUS dupalloc_luid_attr(TALLOC_CTX *ctx, LUID_ATTR **new_la, LUID_ATTR old_la)
82 {
83         *new_la = (LUID_ATTR *)talloc(ctx, sizeof(LUID_ATTR));
84         if (*new_la == NULL) {
85                 DEBUG(0,("dupalloc_luid_attr: could not Alloc memory to duplicate LUID_ATTR\n"));
86                 return NT_STATUS_NO_MEMORY;
87         }
88
89         (*new_la)->luid.high = old_la.luid.high;
90         (*new_la)->luid.low = old_la.luid.low;
91         (*new_la)->attr = old_la.attr;
92         
93         return NT_STATUS_OK;    
94 }
95
96 /****************************************************************************
97  initialise a privilege list
98  ****************************************************************************/
99 void init_privilege(PRIVILEGE_SET *priv_set)
100 {
101         priv_set->count=0;
102         priv_set->control=0;
103         priv_set->set=NULL;
104 }
105
106 /****************************************************************************
107  add a privilege to a privilege array
108  ****************************************************************************/
109 NTSTATUS add_privilege(PRIVILEGE_SET *priv_set, TALLOC_CTX *ctx, LUID_ATTR set)
110 {
111         LUID_ATTR *new_set;
112
113         /* check if the privilege is not already in the list */
114         if (check_priv_in_privilege(priv_set, set))
115                 return NT_STATUS_UNSUCCESSFUL;
116
117         /* we can allocate memory to add the new privilege */
118
119         new_set=(LUID_ATTR *)talloc_realloc(ctx, priv_set->set, (priv_set->count+1)*(sizeof(LUID_ATTR)));
120         if (new_set==NULL) {
121                 DEBUG(0,("add_privilege: could not Realloc memory to add a new privilege\n"));
122                 return NT_STATUS_NO_MEMORY;
123         }
124
125         new_set[priv_set->count].luid.high=set.luid.high;
126         new_set[priv_set->count].luid.low=set.luid.low;
127         new_set[priv_set->count].attr=set.attr;
128         
129         priv_set->count++;
130         priv_set->set=new_set;
131         
132         return NT_STATUS_OK;    
133 }
134
135 /****************************************************************************
136  add all the privileges to a privilege array
137  ****************************************************************************/
138 NTSTATUS add_all_privilege(PRIVILEGE_SET *priv_set, TALLOC_CTX *ctx)
139 {
140         NTSTATUS result = NT_STATUS_OK;
141         LUID_ATTR set;
142
143         set.attr=0;
144         set.luid.high=0;
145         
146         set.luid.low=SE_PRIV_ADD_USERS;
147         result = add_privilege(priv_set, ctx, set);
148         NTSTATUS_CHECK("add_all_privilege", "add_privilege", result, done);
149         
150         set.luid.low=SE_PRIV_ADD_MACHINES;
151         result = add_privilege(priv_set, ctx, set);
152         NTSTATUS_CHECK("add_all_privilege", "add_privilege", result, done);
153
154         set.luid.low=SE_PRIV_PRINT_OPERATOR;
155         result = add_privilege(priv_set, ctx, set);
156         NTSTATUS_CHECK("add_all_privilege", "add_privilege", result, done);
157         
158 done:
159         return result;
160 }
161
162 /****************************************************************************
163  check if the privilege list is empty
164  ****************************************************************************/
165 BOOL check_empty_privilege(PRIVILEGE_SET *priv_set)
166 {
167         return (priv_set->count == 0);
168 }
169
170 /****************************************************************************
171  check if the privilege is in the privilege list
172  ****************************************************************************/
173 BOOL check_priv_in_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
174 {
175         int i;
176
177         /* if the list is empty, obviously we can't have it */
178         if (check_empty_privilege(priv_set))
179                 return False;
180
181         for (i=0; i<priv_set->count; i++) {
182                 LUID_ATTR *cur_set;
183
184                 cur_set=&priv_set->set[i];
185                 /* check only the low and high part. Checking the attr field has no meaning */
186                 if( (cur_set->luid.low==set.luid.low) && (cur_set->luid.high==set.luid.high) )
187                         return True;
188         }
189
190         return False;
191 }
192
193 /****************************************************************************
194  remove a privilege from a privilege array
195  ****************************************************************************/
196 NTSTATUS remove_privilege(PRIVILEGE_SET *priv_set, TALLOC_CTX *ctx, LUID_ATTR set)
197 {
198         LUID_ATTR *new_set;
199         LUID_ATTR *old_set;
200         int i,j;
201
202         /* check if the privilege is in the list */
203         if (!check_priv_in_privilege(priv_set, set))
204                 return NT_STATUS_UNSUCCESSFUL;
205
206         /* special case if it's the only privilege in the list */
207         if (priv_set->count==1) {
208                 init_privilege(priv_set);       
209                 return NT_STATUS_OK;
210         }
211
212         /* 
213          * the privilege is there, create a new list,
214          * and copy the other privileges
215          */
216
217         old_set = priv_set->set;
218
219         new_set=(LUID_ATTR *)talloc(ctx, (priv_set->count - 1) * (sizeof(LUID_ATTR)));
220         if (new_set==NULL) {
221                 DEBUG(0,("remove_privilege: could not malloc memory for new privilege list\n"));
222                 return NT_STATUS_NO_MEMORY;
223         }
224
225         for (i=0, j=0; i<priv_set->count; i++) {
226                 if ((old_set[i].luid.low == set.luid.low) && 
227                     (old_set[i].luid.high == set.luid.high)) {
228                         continue;
229                 }
230                 
231                 new_set[j].luid.low = old_set[i].luid.low;
232                 new_set[j].luid.high = old_set[i].luid.high;
233                 new_set[j].attr = old_set[i].attr;
234
235                 j++;
236         }
237         
238         if (j != priv_set->count - 1) {
239                 DEBUG(0,("remove_privilege: mismatch ! difference is not -1\n"));
240                 DEBUGADD(0,("old count:%d, new count:%d\n", priv_set->count, j));
241                 return NT_STATUS_INTERNAL_ERROR;
242         }
243                 
244         /* ok everything is fine */
245         
246         priv_set->count--;
247         priv_set->set=new_set;
248         
249         return NT_STATUS_OK;    
250 }
251
252 /****************************************************************************
253  duplicates a privilege array
254  ****************************************************************************/
255 NTSTATUS dup_priv_set(PRIVILEGE_SET **new_priv_set, TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set)
256 {
257         LUID_ATTR *new_set;
258         LUID_ATTR *old_set;
259         int i;
260
261         *new_priv_set = (PRIVILEGE_SET *)talloc(mem_ctx, sizeof(PRIVILEGE_SET));
262         init_privilege(*new_priv_set);  
263
264         /* special case if there are no privileges in the list */
265         if (priv_set->count == 0) {
266                 return NT_STATUS_OK;
267         }
268
269         /* 
270          * create a new list,
271          * and copy the other privileges
272          */
273
274         old_set = priv_set->set;
275
276         new_set = (LUID_ATTR *)talloc(mem_ctx, (priv_set->count - 1) * (sizeof(LUID_ATTR)));
277         if (new_set==NULL) {
278                 DEBUG(0,("remove_privilege: could not malloc memory for new privilege list\n"));
279                 return NT_STATUS_NO_MEMORY;
280         }
281
282         for (i=0; i < priv_set->count; i++) {
283                 
284                 new_set[i].luid.low = old_set[i].luid.low;
285                 new_set[i].luid.high = old_set[i].luid.high;
286                 new_set[i].attr = old_set[i].attr;
287         }
288                         
289         (*new_priv_set)->count = priv_set->count;
290         (*new_priv_set)->control = priv_set->control;
291         (*new_priv_set)->set = new_set;
292         
293         return NT_STATUS_OK;    
294 }
295
296 #define ALIAS_DEFAULT_SACL_SA_RIGHTS    0x01050013
297 #define ALIAS_DEFAULT_DACL_SA_RIGHTS \
298                 (READ_CONTROL_ACCESS            | \
299                 SA_RIGHT_ALIAS_LOOKUP_INFO      | \
300                 SA_RIGHT_ALIAS_GET_MEMBERS)     /* 0x0002000c */
301
302 #define ALIAS_DEFAULT_SACL_SEC_ACE_FLAG (SEC_ACE_FLAG_FAILED_ACCESS | SEC_ACE_FLAG_SUCCESSFUL_ACCESS) /* 0xc0 */
303
304 NTSTATUS create_builtin_alias_default_sec_desc(SEC_DESC **sec_desc, TALLOC_CTX *ctx)
305 {
306         DOM_SID *world = &global_sid_World;
307         DOM_SID *admins = &global_sid_Builtin_Administrators;
308         SEC_ACCESS sa;
309         SEC_ACE sacl_ace;
310         SEC_ACE dacl_aces[2];
311         SEC_ACL *sacl = NULL;
312         SEC_ACL *dacl = NULL;
313         size_t psize;
314
315         init_sec_access(&sa, ALIAS_DEFAULT_SACL_SA_RIGHTS);
316         init_sec_ace(&sacl_ace, world, SEC_ACE_TYPE_SYSTEM_AUDIT, sa, ALIAS_DEFAULT_SACL_SEC_ACE_FLAG);
317         
318         sacl = make_sec_acl(ctx, NT4_ACL_REVISION, 1, &sacl_ace);
319         if (!sacl) {
320                 DEBUG(0, ("build_init_sec_desc: Failed to make SEC_ACL.\n"));
321                 return NT_STATUS_NO_MEMORY;
322         }
323
324         init_sec_access(&sa, ALIAS_DEFAULT_DACL_SA_RIGHTS);
325         init_sec_ace(&(dacl_aces[0]), world, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 0);
326         init_sec_access(&sa, SA_RIGHT_ALIAS_ALL_ACCESS);
327         init_sec_ace(&(dacl_aces[1]), admins, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 0);
328
329         dacl = make_sec_acl(ctx, NT4_ACL_REVISION, 2, dacl_aces);
330         if (!sacl) {
331                 DEBUG(0, ("build_init_sec_desc: Failed to make SEC_ACL.\n"));
332                 return NT_STATUS_NO_MEMORY;
333         }
334
335         *sec_desc = make_sec_desc(ctx, SEC_DESC_REVISION, admins, admins, sacl, dacl, &psize);
336         if (!(*sec_desc)) {
337                 DEBUG(0,("get_share_security: Failed to make SEC_DESC.\n"));
338                 return NT_STATUS_NO_MEMORY;
339         }
340
341         return NT_STATUS_OK;
342 }
343
344 NTSTATUS sec_desc_add_ace_to_dacl(SEC_DESC *sec_desc, TALLOC_CTX *ctx, DOM_SID *sid, uint32 mask)
345 {
346         NTSTATUS result;
347         SEC_ACE *new_aces;
348         unsigned num_aces;
349         int i;
350
351         num_aces = sec_desc->dacl->num_aces + 1;
352         result = sec_ace_add_sid(ctx, &new_aces, sec_desc->dacl->ace, &num_aces, sid, mask);
353         if (NT_STATUS_IS_OK(result)) {
354                 sec_desc->dacl->ace = new_aces;
355                 sec_desc->dacl->num_aces = num_aces;
356                 sec_desc->dacl->size = SEC_ACL_HEADER_SIZE;
357                 for (i = 0; i < num_aces; i++) {
358                         sec_desc->dacl->size += sec_desc->dacl->ace[i].size;
359                 }
360         }
361         return result;
362 }
363
364 NTSTATUS gums_init_builtin_groups(void)
365 {
366         NTSTATUS result;
367         GUMS_OBJECT g_obj;
368         GUMS_GROUP *g_grp;
369         GUMS_PRIVILEGE g_priv;
370
371         /* Build the well known Builtin Local Groups */
372         g_obj.type = GUMS_OBJ_GROUP;
373         g_obj.version = 1;
374         g_obj.seq_num = 0;
375         g_obj.mem_ctx = talloc_init("gums_init_backend_acct");
376         if (g_obj.mem_ctx == NULL) {
377                 DEBUG(0, ("gums_init_backend: Out of Memory!\n"));
378                 return NT_STATUS_NO_MEMORY;
379         }
380
381         /* Administrators */
382
383         /* alloc group structure */
384         g_obj.data = (void *)talloc(g_obj.mem_ctx, sizeof(GUMS_OBJ_GROUP));
385         ALLOC_CHECK("gums_init_backend", g_obj.data, result, done);
386
387         /* make admins sid */
388         g_grp = (GUMS_GROUP *)g_obj.data;
389         sid_copy(g_obj.sid, &global_sid_Builtin_Administrators);
390
391         /* make security descriptor */
392         result = create_builtin_alias_default_sec_desc(&(g_obj.sec_desc), g_obj.mem_ctx); 
393         NTSTATUS_CHECK("gums_init_backend", "create_builtin_alias_default_sec_desc", result, done);
394
395         /* make privilege set */
396         /* From BDC join trace:
397                 SeSecurityPrivilege
398                 SeBackupPrivilege
399                 SeRestorePrivilege
400                 SeSystemtimePrivilege
401                 SeShutdownPrivilege
402                 SeRemoteShutdownPrivilege
403                 SeTakeOwnershipPrivilege
404                 SeDebugPrivilege
405                 SeSystemEnvironmentPrivilege
406                 SeSystemProfilePrivilege
407                 SeProfileSingleProcessPrivilege
408                 SeIncreaseBasePriorityPrivilege
409                 SeLocalDriverPrivilege
410                 SeCreatePagefilePrivilege
411                 SeIncreaseQuotaPrivilege
412          */
413
414         /* set name */
415         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Administrators");
416         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
417
418         /* set description */
419         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Members can fully administer the computer/domain");
420         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
421
422         /* numebr of group members */
423         g_grp->count = 0;
424         g_grp->members = NULL;
425
426         /* store Administrators group */
427         result = gums_storage->set_object(&g_obj);
428
429         /* Power Users */
430         /* Domain Controllers Does NOT have power Users */
431
432         sid_copy(g_obj.sid, &global_sid_Builtin_Power_Users);
433
434         /* make privilege set */
435         /* SE_PRIV_??? */
436
437         /* set name */
438         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Power Users");
439         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
440
441         /* set description */
442 /* > */ g_obj.description = talloc_strdup(g_obj.mem_ctx, "Power Users");
443         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
444
445         /* store Power Users group */
446         result = gums_storage->set_object(&g_obj);
447
448         /* Account Operators */
449
450         sid_copy(g_obj.sid, &global_sid_Builtin_Account_Operators);
451
452         /* make privilege set */
453         /* From BDC join trace:
454                 SeShutdownPrivilege
455          */
456
457         /* set name */
458         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Account Operators");
459         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
460
461         /* set description */
462         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Members can administer domain user and group accounts");
463         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
464
465         /* store Account Operators group */
466         result = gums_storage->set_object(&g_obj);
467
468         /* Server Operators */
469
470         sid_copy(g_obj.sid, &global_sid_Builtin_Server_Operators);
471
472         /* make privilege set */
473         /* From BDC join trace:
474                 SeBackupPrivilege
475                 SeRestorePrivilege
476                 SeSystemtimePrivilege
477                 SeShutdownPrivilege
478                 SeRemoteShutdownPrivilege
479          */
480
481         /* set name */
482         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Server Operators");
483         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
484
485         /* set description */
486         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Members can administer domain servers");
487         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
488
489         /* store Server Operators group */
490         result = gums_storage->set_object(&g_obj);
491
492         /* Print Operators */
493
494         sid_copy(g_obj.sid, &global_sid_Builtin_Print_Operators);
495
496         /* make privilege set */
497         /* From BDC join trace:
498                 SeShutdownPrivilege
499          */
500
501         /* set name */
502         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Print Operators");
503         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
504
505         /* set description */
506         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Members can administer domain printers");
507         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
508
509         /* store Print Operators group */
510         result = gums_storage->set_object(&g_obj);
511
512         /* Backup Operators */
513
514         sid_copy(g_obj.sid, &global_sid_Builtin_Backup_Operators);
515
516         /* make privilege set */
517         /* From BDC join trace:
518                 SeBackupPrivilege
519                 SeRestorePrivilege
520                 SeShutdownPrivilege
521          */
522
523         /* set name */
524         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Backup Operators");
525         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
526
527         /* set description */
528         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Members can bypass file security to backup files");
529         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
530
531         /* store Backup Operators group */
532         result = gums_storage->set_object(&g_obj);
533
534         /* Replicator */
535
536         sid_copy(g_obj.sid, &global_sid_Builtin_Replicator);
537
538         /* make privilege set */
539         /* From BDC join trace:
540                 SeBackupPrivilege
541                 SeRestorePrivilege
542                 SeShutdownPrivilege
543          */
544
545         /* set name */
546         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Replicator");
547         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
548
549         /* set description */
550         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Supports file replication in a domain");
551         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
552
553         /* store Replicator group */
554         result = gums_storage->set_object(&g_obj);
555
556         /* Users */
557
558         sid_copy(g_obj.sid, &global_sid_Builtin_Users);
559
560         /* add ACE to sec dsec dacl */
561         sec_desc_add_ace_to_dacl(g_obj.sec_desc, g_obj.mem_ctx, &global_sid_Builtin_Account_Operators, ALIAS_DEFAULT_DACL_SA_RIGHTS);
562         sec_desc_add_ace_to_dacl(g_obj.sec_desc, g_obj.mem_ctx, &global_sid_Builtin_Power_Users, ALIAS_DEFAULT_DACL_SA_RIGHTS);
563
564         /* set name */
565         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Users");
566         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
567
568         /* set description */
569         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Ordinary users");
570         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
571
572         /* store Users group */
573         result = gums_storage->set_object(&g_obj);
574
575         /* Guests */
576
577         sid_copy(g_obj.sid, &global_sid_Builtin_Guests);
578
579         /* set name */
580         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Guests");
581         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
582
583         /* set description */
584         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Users granted guest access to the computer/domain");
585         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
586
587         /* store Guests group */
588         result = gums_storage->set_object(&g_obj);
589
590         /* set default privileges */
591         g_priv.type = GUMS_OBJ_GROUP;
592         g_priv.version = 1;
593         g_priv.seq_num = 0;
594         g_priv.mem_ctx = talloc_init("gums_init_backend_priv");
595         if (g_priv.mem_ctx == NULL) {
596                 DEBUG(0, ("gums_init_backend: Out of Memory!\n"));
597                 return NT_STATUS_NO_MEMORY;
598         }
599
600                 
601
602 done:
603         talloc_destroy(g_obj.mem_ctx);
604         talloc_destroy(g_priv.mem_ctx);
605         return result;
606 }
607