initial version of idmap_ldap.c; lots of updates to come
[ira/wip.git] / source3 / 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 #if 0
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 #endif
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 gums_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 gums_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 (gums_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 gums_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 = gums_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 = gums_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 = gums_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 gums_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 gums_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 (gums_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 gums_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 (!gums_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                 gums_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 gums_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         gums_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
305 #if 0
306 NTSTATUS create_builtin_alias_default_sec_desc(SEC_DESC **sec_desc, TALLOC_CTX *ctx)
307 {
308         DOM_SID *world = &global_sid_World;
309         DOM_SID *admins = &global_sid_Builtin_Administrators;
310         SEC_ACCESS sa;
311         SEC_ACE sacl_ace;
312         SEC_ACE dacl_aces[2];
313         SEC_ACL *sacl = NULL;
314         SEC_ACL *dacl = NULL;
315         size_t psize;
316
317         init_sec_access(&sa, ALIAS_DEFAULT_SACL_SA_RIGHTS);
318         init_sec_ace(&sacl_ace, world, SEC_ACE_TYPE_SYSTEM_AUDIT, sa, ALIAS_DEFAULT_SACL_SEC_ACE_FLAG);
319         
320         sacl = make_sec_acl(ctx, NT4_ACL_REVISION, 1, &sacl_ace);
321         if (!sacl) {
322                 DEBUG(0, ("build_init_sec_desc: Failed to make SEC_ACL.\n"));
323                 return NT_STATUS_NO_MEMORY;
324         }
325
326         init_sec_access(&sa, ALIAS_DEFAULT_DACL_SA_RIGHTS);
327         init_sec_ace(&(dacl_aces[0]), world, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 0);
328         init_sec_access(&sa, SA_RIGHT_ALIAS_ALL_ACCESS);
329         init_sec_ace(&(dacl_aces[1]), admins, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 0);
330
331         dacl = make_sec_acl(ctx, NT4_ACL_REVISION, 2, dacl_aces);
332         if (!sacl) {
333                 DEBUG(0, ("build_init_sec_desc: Failed to make SEC_ACL.\n"));
334                 return NT_STATUS_NO_MEMORY;
335         }
336
337         *sec_desc = make_sec_desc(ctx, SEC_DESC_REVISION, admins, admins, sacl, dacl, &psize);
338         if (!(*sec_desc)) {
339                 DEBUG(0,("get_share_security: Failed to make SEC_DESC.\n"));
340                 return NT_STATUS_NO_MEMORY;
341         }
342
343         return NT_STATUS_OK;
344 }
345
346 NTSTATUS sec_desc_add_ace_to_dacl(SEC_DESC *sec_desc, TALLOC_CTX *ctx, DOM_SID *sid, uint32 mask)
347 {
348         NTSTATUS result;
349         SEC_ACE *new_aces;
350         unsigned num_aces;
351         int i;
352
353         num_aces = sec_desc->dacl->num_aces + 1;
354         result = sec_ace_add_sid(ctx, &new_aces, sec_desc->dacl->ace, &num_aces, sid, mask);
355         if (NT_STATUS_IS_OK(result)) {
356                 sec_desc->dacl->ace = new_aces;
357                 sec_desc->dacl->num_aces = num_aces;
358                 sec_desc->dacl->size = SEC_ACL_HEADER_SIZE;
359                 for (i = 0; i < num_aces; i++) {
360                         sec_desc->dacl->size += sec_desc->dacl->ace[i].size;
361                 }
362         }
363         return result;
364 }
365
366 NTSTATUS gums_init_builtin_groups(void)
367 {
368         NTSTATUS result;
369         GUMS_OBJECT g_obj;
370         GUMS_GROUP *g_grp;
371         GUMS_PRIVILEGE g_priv;
372
373         /* Build the well known Builtin Local Groups */
374         g_obj.type = GUMS_OBJ_GROUP;
375         g_obj.version = 1;
376         g_obj.seq_num = 0;
377         g_obj.mem_ctx = talloc_init("gums_init_backend_acct");
378         if (g_obj.mem_ctx == NULL) {
379                 DEBUG(0, ("gums_init_backend: Out of Memory!\n"));
380                 return NT_STATUS_NO_MEMORY;
381         }
382
383         /* Administrators * /
384
385         /* alloc group structure */
386         g_obj.data.group = (GUMS_GROUP *)talloc(g_obj.mem_ctx, sizeof(GUMS_GROUP));
387         ALLOC_CHECK("gums_init_backend", g_obj.data.group, result, done);
388
389         /* make admins sid */
390         g_grp = (GUMS_GROUP *)g_obj.data.group;
391         sid_copy(g_obj.sid, &global_sid_Builtin_Administrators);
392
393         /* make security descriptor */
394         result = create_builtin_alias_default_sec_desc(&(g_obj.sec_desc), g_obj.mem_ctx); 
395         NTSTATUS_CHECK("gums_init_backend", "create_builtin_alias_default_sec_desc", result, done);
396
397         /* make privilege set */
398         /* From BDC join trace:
399                 SeSecurityPrivilege
400                 SeBackupPrivilege
401                 SeRestorePrivilege
402                 SeSystemtimePrivilege
403                 SeShutdownPrivilege
404                 SeRemoteShutdownPrivilege
405                 SeTakeOwnershipPrivilege
406                 SeDebugPrivilege
407                 SeSystemEnvironmentPrivilege
408                 SeSystemProfilePrivilege
409                 SeProfileSingleProcessPrivilege
410                 SeIncreaseBasePriorityPrivilege
411                 SeLocalDriverPrivilege
412                 SeCreatePagefilePrivilege
413                 SeIncreaseQuotaPrivilege
414          */
415
416         /* set name */
417         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Administrators");
418         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
419
420         /* set description */
421         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Members can fully administer the computer/domain");
422         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
423
424         /* numebr of group members */
425         g_grp->count = 0;
426         g_grp->members = NULL;
427
428         /* store Administrators group */
429         result = gums_storage->set_object(&g_obj);
430
431         /* Power Users */
432         /* Domain Controllers Does NOT have power Users */
433
434         sid_copy(g_obj.sid, &global_sid_Builtin_Power_Users);
435
436         /* make privilege set */
437         /* SE_PRIV_??? */
438
439         /* set name */
440         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Power Users");
441         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
442
443         /* set description */
444 /* > */ g_obj.description = talloc_strdup(g_obj.mem_ctx, "Power Users");
445         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
446
447         /* store Power Users group */
448         result = gums_storage->set_object(&g_obj);
449
450         /* Account Operators */
451
452         sid_copy(g_obj.sid, &global_sid_Builtin_Account_Operators);
453
454         /* make privilege set */
455         /* From BDC join trace:
456                 SeShutdownPrivilege
457          */
458
459         /* set name */
460         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Account Operators");
461         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
462
463         /* set description */
464         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Members can administer domain user and group accounts");
465         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
466
467         /* store Account Operators group */
468         result = gums_storage->set_object(&g_obj);
469
470         /* Server Operators */
471
472         sid_copy(g_obj.sid, &global_sid_Builtin_Server_Operators);
473
474         /* make privilege set */
475         /* From BDC join trace:
476                 SeBackupPrivilege
477                 SeRestorePrivilege
478                 SeSystemtimePrivilege
479                 SeShutdownPrivilege
480                 SeRemoteShutdownPrivilege
481          */
482
483         /* set name */
484         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Server Operators");
485         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
486
487         /* set description */
488         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Members can administer domain servers");
489         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
490
491         /* store Server Operators group */
492         result = gums_storage->set_object(&g_obj);
493
494         /* Print Operators */
495
496         sid_copy(g_obj.sid, &global_sid_Builtin_Print_Operators);
497
498         /* make privilege set */
499         /* From BDC join trace:
500                 SeShutdownPrivilege
501          */
502
503         /* set name */
504         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Print Operators");
505         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
506
507         /* set description */
508         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Members can administer domain printers");
509         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
510
511         /* store Print Operators group */
512         result = gums_storage->set_object(&g_obj);
513
514         /* Backup Operators */
515
516         sid_copy(g_obj.sid, &global_sid_Builtin_Backup_Operators);
517
518         /* make privilege set */
519         /* From BDC join trace:
520                 SeBackupPrivilege
521                 SeRestorePrivilege
522                 SeShutdownPrivilege
523          */
524
525         /* set name */
526         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Backup Operators");
527         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
528
529         /* set description */
530         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Members can bypass file security to backup files");
531         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
532
533         /* store Backup Operators group */
534         result = gums_storage->set_object(&g_obj);
535
536         /* Replicator */
537
538         sid_copy(g_obj.sid, &global_sid_Builtin_Replicator);
539
540         /* make privilege set */
541         /* From BDC join trace:
542                 SeBackupPrivilege
543                 SeRestorePrivilege
544                 SeShutdownPrivilege
545          */
546
547         /* set name */
548         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Replicator");
549         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
550
551         /* set description */
552         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Supports file replication in a domain");
553         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
554
555         /* store Replicator group */
556         result = gums_storage->set_object(&g_obj);
557
558         /* Users */
559
560         sid_copy(g_obj.sid, &global_sid_Builtin_Users);
561
562         /* add ACE to sec dsec dacl */
563         sec_desc_add_ace_to_dacl(g_obj.sec_desc, g_obj.mem_ctx, &global_sid_Builtin_Account_Operators, ALIAS_DEFAULT_DACL_SA_RIGHTS);
564         sec_desc_add_ace_to_dacl(g_obj.sec_desc, g_obj.mem_ctx, &global_sid_Builtin_Power_Users, ALIAS_DEFAULT_DACL_SA_RIGHTS);
565
566         /* set name */
567         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Users");
568         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
569
570         /* set description */
571         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Ordinary users");
572         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
573
574         /* store Users group */
575         result = gums_storage->set_object(&g_obj);
576
577         /* Guests */
578
579         sid_copy(g_obj.sid, &global_sid_Builtin_Guests);
580
581         /* set name */
582         g_obj.name = talloc_strdup(g_obj.mem_ctx, "Guests");
583         ALLOC_CHECK("gums_init_backend", g_obj.name, result, done);
584
585         /* set description */
586         g_obj.description = talloc_strdup(g_obj.mem_ctx, "Users granted guest access to the computer/domain");
587         ALLOC_CHECK("gums_init_backend", g_obj.description, result, done);
588
589         /* store Guests group */
590         result = gums_storage->set_object(&g_obj);
591
592         /* set default privileges */
593         g_priv.type = GUMS_OBJ_GROUP;
594         g_priv.version = 1;
595         g_priv.seq_num = 0;
596         g_priv.mem_ctx = talloc_init("gums_init_backend_priv");
597         if (g_priv.mem_ctx == NULL) {
598                 DEBUG(0, ("gums_init_backend: Out of Memory!\n"));
599                 return NT_STATUS_NO_MEMORY;
600         }
601
602                 
603
604 done:
605         talloc_destroy(g_obj.mem_ctx);
606         talloc_destroy(g_priv.mem_ctx);
607         return result;
608 }
609 #endif
610