libcli/security Provide a common, top level libcli/security/security.h
[kai/samba.git] / source3 / lib / sharesec.c
1 /* 
2  *  Unix SMB/Netbios implementation.
3  *  SEC_DESC handling functions
4  *  Copyright (C) Jeremy R. Allison            1995-2003.
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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "../libcli/security/security.h"
22 #include "../librpc/gen_ndr/ndr_security.h"
23 #include "dbwrap.h"
24
25 /*******************************************************************
26  Create the share security tdb.
27  ********************************************************************/
28
29 static struct db_context *share_db; /* used for share security descriptors */
30 #define SHARE_DATABASE_VERSION_V1 1
31 #define SHARE_DATABASE_VERSION_V2 2 /* version id in little endian. */
32 #define SHARE_DATABASE_VERSION_V3 3 /* canonicalized sharenames as lower case */
33
34 #define SHARE_SECURITY_DB_KEY_PREFIX_STR "SECDESC/"
35 /* Map generic permissions to file object specific permissions */
36
37 extern const struct generic_mapping file_generic_mapping;
38
39 static int delete_fn(struct db_record *rec, void *priv)
40 {
41         rec->delete_rec(rec);
42         return 0;
43 }
44
45 /*****************************************************
46  Looking for keys of the form: SHARE_SECURITY_DB_KEY_PREFIX_STR + "non lower case str".
47  If we find one re-write it into a canonical case form.
48 *****************************************************/
49
50 static int upgrade_v2_to_v3(struct db_record *rec, void *priv)
51 {
52         size_t prefix_len = strlen(SHARE_SECURITY_DB_KEY_PREFIX_STR);
53         const char *servicename = NULL;
54         char *c_servicename = NULL;
55         char *newkey = NULL;
56         bool *p_upgrade_ok = (bool *)priv;
57         NTSTATUS status;
58
59         /* Is there space for a one character sharename ? */
60         if (rec->key.dsize <= prefix_len+2) {
61                 return 0;
62         }
63
64         /* Does it start with the share key prefix ? */
65         if (memcmp(rec->key.dptr, SHARE_SECURITY_DB_KEY_PREFIX_STR,
66                         prefix_len) != 0) {
67                 return 0;
68         }
69
70         /* Is it a null terminated string as a key ? */
71         if (rec->key.dptr[rec->key.dsize-1] != '\0') {
72                 return 0;
73         }
74
75         /* Bytes after the prefix are the sharename string. */
76         servicename = (char *)&rec->key.dptr[prefix_len];
77         c_servicename = canonicalize_servicename(talloc_tos(), servicename);
78         if (!c_servicename) {
79                 smb_panic("out of memory upgrading share security db from v2 -> v3");
80         }
81
82         if (strcmp(servicename, c_servicename) == 0) {
83                 /* Old and new names match. No canonicalization needed. */
84                 TALLOC_FREE(c_servicename);
85                 return 0;
86         }
87
88         /* Oops. Need to canonicalize name, delete old then store new. */
89         status = rec->delete_rec(rec);
90         if (!NT_STATUS_IS_OK(status)) {
91                 DEBUG(1, ("upgrade_v2_to_v3: Failed to delete secdesc for "
92                           "%s: %s\n", rec->key.dptr, nt_errstr(status)));
93                 TALLOC_FREE(c_servicename);
94                 *p_upgrade_ok = false;
95                 return -1;
96         } else {
97                 DEBUG(10, ("upgrade_v2_to_v3: deleted secdesc for "
98                           "%s\n", rec->key.dptr ));
99         }
100
101         if (!(newkey = talloc_asprintf(talloc_tos(),
102                         SHARE_SECURITY_DB_KEY_PREFIX_STR "%s",
103                         c_servicename))) {
104                 smb_panic("out of memory upgrading share security db from v2 -> v3");
105         }
106
107         status = dbwrap_store(share_db,
108                                 string_term_tdb_data(newkey),
109                                 rec->value,
110                                 TDB_REPLACE);
111
112         if (!NT_STATUS_IS_OK(status)) {
113                 DEBUG(1, ("upgrade_v2_to_v3: Failed to store secdesc for "
114                           "%s: %s\n", c_servicename, nt_errstr(status)));
115                 TALLOC_FREE(c_servicename);
116                 TALLOC_FREE(newkey);
117                 *p_upgrade_ok = false;
118                 return -1;
119         } else {
120                 DEBUG(10, ("upgrade_v2_to_v3: stored secdesc for "
121                           "%s\n", newkey ));
122         }
123
124         TALLOC_FREE(newkey);
125         TALLOC_FREE(c_servicename);
126
127         return 0;
128 }
129
130 bool share_info_db_init(void)
131 {
132         const char *vstring = "INFO/version";
133         int32 vers_id;
134         int ret;
135         bool upgrade_ok = true;
136
137         if (share_db != NULL) {
138                 return True;
139         }
140
141         share_db = db_open(NULL, state_path("share_info.tdb"), 0,
142                                  TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
143         if (share_db == NULL) {
144                 DEBUG(0,("Failed to open share info database %s (%s)\n",
145                         state_path("share_info.tdb"), strerror(errno) ));
146                 return False;
147         }
148
149         vers_id = dbwrap_fetch_int32(share_db, vstring);
150         if (vers_id == SHARE_DATABASE_VERSION_V3) {
151                 return true;
152         }
153
154         if (share_db->transaction_start(share_db) != 0) {
155                 DEBUG(0, ("transaction_start failed\n"));
156                 TALLOC_FREE(share_db);
157                 return false;
158         }
159
160         vers_id = dbwrap_fetch_int32(share_db, vstring);
161         if (vers_id == SHARE_DATABASE_VERSION_V3) {
162                 /*
163                  * Race condition
164                  */
165                 if (share_db->transaction_cancel(share_db)) {
166                         smb_panic("transaction_cancel failed");
167                 }
168                 return true;
169         }
170
171         /* Move to at least V2. */
172
173         /* Cope with byte-reversed older versions of the db. */
174         if ((vers_id == SHARE_DATABASE_VERSION_V1) || (IREV(vers_id) == SHARE_DATABASE_VERSION_V1)) {
175                 /* Written on a bigendian machine with old fetch_int code. Save as le. */
176
177                 if (dbwrap_store_int32(share_db, vstring,
178                                        SHARE_DATABASE_VERSION_V2) != 0) {
179                         DEBUG(0, ("dbwrap_store_int32 failed\n"));
180                         goto cancel;
181                 }
182                 vers_id = SHARE_DATABASE_VERSION_V2;
183         }
184
185         if (vers_id != SHARE_DATABASE_VERSION_V2) {
186                 ret = share_db->traverse(share_db, delete_fn, NULL);
187                 if (ret < 0) {
188                         DEBUG(0, ("traverse failed\n"));
189                         goto cancel;
190                 }
191                 if (dbwrap_store_int32(share_db, vstring,
192                                        SHARE_DATABASE_VERSION_V2) != 0) {
193                         DEBUG(0, ("dbwrap_store_int32 failed\n"));
194                         goto cancel;
195                 }
196         }
197
198         /* Finally upgrade to version 3, with canonicalized sharenames. */
199
200         ret = share_db->traverse(share_db, upgrade_v2_to_v3, &upgrade_ok);
201         if (ret < 0 || upgrade_ok == false) {
202                 DEBUG(0, ("traverse failed\n"));
203                 goto cancel;
204         }
205         if (dbwrap_store_int32(share_db, vstring,
206                                SHARE_DATABASE_VERSION_V3) != 0) {
207                 DEBUG(0, ("dbwrap_store_int32 failed\n"));
208                 goto cancel;
209         }
210
211         if (share_db->transaction_commit(share_db) != 0) {
212                 DEBUG(0, ("transaction_commit failed\n"));
213                 return false;
214         }
215
216         return true;
217
218  cancel:
219         if (share_db->transaction_cancel(share_db)) {
220                 smb_panic("transaction_cancel failed");
221         }
222
223         return false;
224 }
225
226 /*******************************************************************
227  Fake up a Everyone, default access as a default.
228  def_access is a GENERIC_XXX access mode.
229  ********************************************************************/
230
231 struct security_descriptor *get_share_security_default( TALLOC_CTX *ctx, size_t *psize, uint32 def_access)
232 {
233         uint32_t sa;
234         struct security_ace ace;
235         struct security_acl *psa = NULL;
236         struct security_descriptor *psd = NULL;
237         uint32 spec_access = def_access;
238
239         se_map_generic(&spec_access, &file_generic_mapping);
240
241         sa = (def_access | spec_access );
242         init_sec_ace(&ace, &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 0);
243
244         if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 1, &ace)) != NULL) {
245                 psd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
246                                     SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL,
247                                     psa, psize);
248         }
249
250         if (!psd) {
251                 DEBUG(0,("get_share_security: Failed to make SEC_DESC.\n"));
252                 return NULL;
253         }
254
255         return psd;
256 }
257
258 /*******************************************************************
259  Pull a security descriptor from the share tdb.
260  ********************************************************************/
261
262 struct security_descriptor *get_share_security( TALLOC_CTX *ctx, const char *servicename,
263                               size_t *psize)
264 {
265         char *key;
266         struct security_descriptor *psd = NULL;
267         TDB_DATA data;
268         char *c_servicename = canonicalize_servicename(talloc_tos(), servicename);
269         NTSTATUS status;
270
271         if (!c_servicename) {
272                 return NULL;
273         }
274
275         if (!share_info_db_init()) {
276                 TALLOC_FREE(c_servicename);
277                 return NULL;
278         }
279
280         if (!(key = talloc_asprintf(ctx, SHARE_SECURITY_DB_KEY_PREFIX_STR "%s", c_servicename))) {
281                 TALLOC_FREE(c_servicename);
282                 DEBUG(0, ("talloc_asprintf failed\n"));
283                 return NULL;
284         }
285
286         TALLOC_FREE(c_servicename);
287
288         data = dbwrap_fetch_bystring(share_db, talloc_tos(), key);
289
290         TALLOC_FREE(key);
291
292         if (data.dptr == NULL) {
293                 return get_share_security_default(ctx, psize,
294                                                   GENERIC_ALL_ACCESS);
295         }
296
297         status = unmarshall_sec_desc(ctx, data.dptr, data.dsize, &psd);
298
299         TALLOC_FREE(data.dptr);
300
301         if (!NT_STATUS_IS_OK(status)) {
302                 DEBUG(0, ("unmarshall_sec_desc failed: %s\n",
303                           nt_errstr(status)));
304                 return get_share_security_default(ctx, psize,
305                                                   GENERIC_ALL_ACCESS);
306         }
307
308         if (psd) {
309                 *psize = ndr_size_security_descriptor(psd, 0);
310         } else {
311                 return get_share_security_default(ctx, psize,
312                                                   GENERIC_ALL_ACCESS);
313         }
314
315         return psd;
316 }
317
318 /*******************************************************************
319  Store a security descriptor in the share db.
320  ********************************************************************/
321
322 bool set_share_security(const char *share_name, struct security_descriptor *psd)
323 {
324         TALLOC_CTX *frame = talloc_stackframe();
325         char *key;
326         bool ret = False;
327         TDB_DATA blob;
328         NTSTATUS status;
329         char *c_share_name = canonicalize_servicename(frame, share_name);
330
331         if (!c_share_name) {
332                 goto out;
333         }
334
335         if (!share_info_db_init()) {
336                 goto out;
337         }
338
339         status = marshall_sec_desc(frame, psd, &blob.dptr, &blob.dsize);
340
341         if (!NT_STATUS_IS_OK(status)) {
342                 DEBUG(0, ("marshall_sec_desc failed: %s\n",
343                           nt_errstr(status)));
344                 goto out;
345         }
346
347         if (!(key = talloc_asprintf(frame, SHARE_SECURITY_DB_KEY_PREFIX_STR "%s", c_share_name))) {
348                 DEBUG(0, ("talloc_asprintf failed\n"));
349                 goto out;
350         }
351
352         status = dbwrap_trans_store(share_db, string_term_tdb_data(key), blob,
353                                     TDB_REPLACE);
354         if (!NT_STATUS_IS_OK(status)) {
355                 DEBUG(1, ("set_share_security: Failed to store secdesc for "
356                           "%s: %s\n", share_name, nt_errstr(status)));
357                 goto out;
358         }
359
360         DEBUG(5,("set_share_security: stored secdesc for %s\n", share_name ));
361         ret = True;
362
363  out:
364         TALLOC_FREE(frame);
365         return ret;
366 }
367
368 /*******************************************************************
369  Delete a security descriptor.
370 ********************************************************************/
371
372 bool delete_share_security(const char *servicename)
373 {
374         TDB_DATA kbuf;
375         char *key;
376         NTSTATUS status;
377         char *c_servicename = canonicalize_servicename(talloc_tos(), servicename);
378
379         if (!c_servicename) {
380                 return NULL;
381         }
382
383         if (!share_info_db_init()) {
384                 TALLOC_FREE(c_servicename);
385                 return False;
386         }
387
388         if (!(key = talloc_asprintf(talloc_tos(), SHARE_SECURITY_DB_KEY_PREFIX_STR "%s",
389                                     c_servicename))) {
390                 TALLOC_FREE(c_servicename);
391                 return False;
392         }
393         kbuf = string_term_tdb_data(key);
394
395         status = dbwrap_trans_delete(share_db, kbuf);
396         if (!NT_STATUS_IS_OK(status)) {
397                 DEBUG(0, ("delete_share_security: Failed to delete entry for "
398                           "share %s: %s\n", c_servicename, nt_errstr(status)));
399                 TALLOC_FREE(c_servicename);
400                 return False;
401         }
402
403         TALLOC_FREE(c_servicename);
404         return True;
405 }
406
407 /*******************************************************************
408  Can this user access with share with the required permissions ?
409 ********************************************************************/
410
411 bool share_access_check(const struct security_token *token, const char *sharename,
412                         uint32 desired_access)
413 {
414         uint32 granted;
415         NTSTATUS status;
416         struct security_descriptor *psd = NULL;
417         size_t sd_size;
418
419         psd = get_share_security(talloc_tos(), sharename, &sd_size);
420
421         if (!psd) {
422                 return True;
423         }
424
425         status = se_access_check(psd, token, desired_access, &granted);
426
427         TALLOC_FREE(psd);
428
429         return NT_STATUS_IS_OK(status);
430 }
431
432 /***************************************************************************
433  Parse the contents of an acl string from a usershare file.
434 ***************************************************************************/
435
436 bool parse_usershare_acl(TALLOC_CTX *ctx, const char *acl_str, struct security_descriptor **ppsd)
437 {
438         size_t s_size = 0;
439         const char *pacl = acl_str;
440         int num_aces = 0;
441         struct security_ace *ace_list = NULL;
442         struct security_acl *psa = NULL;
443         struct security_descriptor *psd = NULL;
444         size_t sd_size = 0;
445         int i;
446
447         *ppsd = NULL;
448
449         /* If the acl string is blank return "Everyone:R" */
450         if (!*acl_str) {
451                 struct security_descriptor *default_psd = get_share_security_default(ctx, &s_size, GENERIC_READ_ACCESS);
452                 if (!default_psd) {
453                         return False;
454                 }
455                 *ppsd = default_psd;
456                 return True;
457         }
458
459         num_aces = 1;
460
461         /* Add the number of ',' characters to get the number of aces. */
462         num_aces += count_chars(pacl,',');
463
464         ace_list = TALLOC_ARRAY(ctx, struct security_ace, num_aces);
465         if (!ace_list) {
466                 return False;
467         }
468
469         for (i = 0; i < num_aces; i++) {
470                 uint32_t sa;
471                 uint32 g_access;
472                 uint32 s_access;
473                 struct dom_sid sid;
474                 char *sidstr;
475                 enum security_ace_type type = SEC_ACE_TYPE_ACCESS_ALLOWED;
476
477                 if (!next_token_talloc(ctx, &pacl, &sidstr, ":")) {
478                         DEBUG(0,("parse_usershare_acl: malformed usershare acl looking "
479                                 "for ':' in string '%s'\n", pacl));
480                         return False;
481                 }
482
483                 if (!string_to_sid(&sid, sidstr)) {
484                         DEBUG(0,("parse_usershare_acl: failed to convert %s to sid.\n",
485                                 sidstr ));
486                         return False;
487                 }
488
489                 switch (*pacl) {
490                         case 'F': /* Full Control, ie. R+W */
491                         case 'f': /* Full Control, ie. R+W */
492                                 s_access = g_access = GENERIC_ALL_ACCESS;
493                                 break;
494                         case 'R': /* Read only. */
495                         case 'r': /* Read only. */
496                                 s_access = g_access = GENERIC_READ_ACCESS;
497                                 break;
498                         case 'D': /* Deny all to this SID. */
499                         case 'd': /* Deny all to this SID. */
500                                 type = SEC_ACE_TYPE_ACCESS_DENIED;
501                                 s_access = g_access = GENERIC_ALL_ACCESS;
502                                 break;
503                         default:
504                                 DEBUG(0,("parse_usershare_acl: unknown acl type at %s.\n",
505                                         pacl ));
506                                 return False;
507                 }
508
509                 pacl++;
510                 if (*pacl && *pacl != ',') {
511                         DEBUG(0,("parse_usershare_acl: bad acl string at %s.\n",
512                                 pacl ));
513                         return False;
514                 }
515                 pacl++; /* Go past any ',' */
516
517                 se_map_generic(&s_access, &file_generic_mapping);
518                 sa = (g_access | s_access);
519                 init_sec_ace(&ace_list[i], &sid, type, sa, 0);
520         }
521
522         if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, num_aces, ace_list)) != NULL) {
523                 psd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
524                                     SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL,
525                                     psa, &sd_size);
526         }
527
528         if (!psd) {
529                 DEBUG(0,("parse_usershare_acl: Failed to make SEC_DESC.\n"));
530                 return False;
531         }
532
533         *ppsd = psd;
534         return True;
535 }