s3/smbd: make make_default_filesystem_acl public
[samba.git] / source3 / modules / vfs_acl_common.c
1 /*
2  * Store Windows ACLs in data store - common functions.
3  * #included into modules/vfs_acl_xattr.c and modules/vfs_acl_tdb.c
4  *
5  * Copyright (C) Volker Lendecke, 2008
6  * Copyright (C) Jeremy Allison, 2009
7  * Copyright (C) Ralph Böhme, 2016
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "includes.h"
24 #include "vfs_acl_common.h"
25 #include "smbd/smbd.h"
26 #include "system/filesys.h"
27 #include "librpc/gen_ndr/ndr_xattr.h"
28 #include "../libcli/security/security.h"
29 #include "../librpc/gen_ndr/ndr_security.h"
30 #include "../lib/util/bitmap.h"
31 #include "lib/crypto/sha256.h"
32 #include "passdb/lookup_sid.h"
33
34 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
35                         DATA_BLOB *pblob,
36                         uint16_t hash_type,
37                         uint8_t hash[XATTR_SD_HASH_SIZE]);
38
39 #define HASH_SECURITY_INFO (SECINFO_OWNER | \
40                                 SECINFO_GROUP | \
41                                 SECINFO_DACL | \
42                                 SECINFO_SACL)
43
44 bool init_acl_common_config(vfs_handle_struct *handle,
45                             const char *module_name)
46 {
47         struct acl_common_config *config = NULL;
48         const struct enum_list *default_acl_style_list = NULL;
49
50         default_acl_style_list = get_default_acl_style_list();
51
52         config = talloc_zero(handle->conn, struct acl_common_config);
53         if (config == NULL) {
54                 DBG_ERR("talloc_zero() failed\n");
55                 errno = ENOMEM;
56                 return false;
57         }
58
59         config->ignore_system_acls = lp_parm_bool(SNUM(handle->conn),
60                                                   module_name,
61                                                   "ignore system acls",
62                                                   false);
63         config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
64                                                  module_name,
65                                                  "default acl style",
66                                                  default_acl_style_list,
67                                                  DEFAULT_ACL_POSIX);
68
69         SMB_VFS_HANDLE_SET_DATA(handle, config, NULL,
70                                 struct acl_common_config,
71                                 return false);
72
73         return true;
74 }
75
76
77 /*******************************************************************
78  Hash a security descriptor.
79 *******************************************************************/
80
81 static NTSTATUS hash_blob_sha256(DATA_BLOB blob,
82                                  uint8_t *hash)
83 {
84         SHA256_CTX tctx;
85
86         memset(hash, '\0', XATTR_SD_HASH_SIZE);
87
88         samba_SHA256_Init(&tctx);
89         samba_SHA256_Update(&tctx, blob.data, blob.length);
90         samba_SHA256_Final(hash, &tctx);
91
92         return NT_STATUS_OK;
93 }
94
95 /*******************************************************************
96  Hash a security descriptor.
97 *******************************************************************/
98
99 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
100                         uint8_t *hash)
101 {
102         DATA_BLOB blob;
103         NTSTATUS status;
104
105         memset(hash, '\0', XATTR_SD_HASH_SIZE);
106         status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
107         if (!NT_STATUS_IS_OK(status)) {
108                 return status;
109         }
110         return hash_blob_sha256(blob, hash);
111 }
112
113 /*******************************************************************
114  Parse out a struct security_descriptor from a DATA_BLOB.
115 *******************************************************************/
116
117 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
118                                TALLOC_CTX *mem_ctx,
119                                struct security_descriptor **ppdesc,
120                                uint16_t *p_hash_type,
121                                uint16_t *p_version,
122                                uint8_t hash[XATTR_SD_HASH_SIZE],
123                                uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE])
124 {
125         struct xattr_NTACL xacl;
126         enum ndr_err_code ndr_err;
127         size_t sd_size;
128         TALLOC_CTX *frame = talloc_stackframe();
129
130         ndr_err = ndr_pull_struct_blob(pblob, frame, &xacl,
131                         (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
132
133         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
134                 DBG_INFO("ndr_pull_xattr_NTACL failed: %s\n",
135                          ndr_errstr(ndr_err));
136                 TALLOC_FREE(frame);
137                 return ndr_map_error2ntstatus(ndr_err);
138         }
139
140         *p_version = xacl.version;
141
142         switch (xacl.version) {
143                 case 1:
144                         *ppdesc = make_sec_desc(mem_ctx, SD_REVISION,
145                                         xacl.info.sd->type | SEC_DESC_SELF_RELATIVE,
146                                         xacl.info.sd->owner_sid,
147                                         xacl.info.sd->group_sid,
148                                         xacl.info.sd->sacl,
149                                         xacl.info.sd->dacl,
150                                         &sd_size);
151                         /* No hash - null out. */
152                         *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
153                         memset(hash, '\0', XATTR_SD_HASH_SIZE);
154                         break;
155                 case 2:
156                         *ppdesc = make_sec_desc(mem_ctx, SD_REVISION,
157                                         xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
158                                         xacl.info.sd_hs2->sd->owner_sid,
159                                         xacl.info.sd_hs2->sd->group_sid,
160                                         xacl.info.sd_hs2->sd->sacl,
161                                         xacl.info.sd_hs2->sd->dacl,
162                                         &sd_size);
163                         /* No hash - null out. */
164                         *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
165                         memset(hash, '\0', XATTR_SD_HASH_SIZE);
166                         break;
167                 case 3:
168                         *ppdesc = make_sec_desc(mem_ctx, SD_REVISION,
169                                         xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
170                                         xacl.info.sd_hs3->sd->owner_sid,
171                                         xacl.info.sd_hs3->sd->group_sid,
172                                         xacl.info.sd_hs3->sd->sacl,
173                                         xacl.info.sd_hs3->sd->dacl,
174                                         &sd_size);
175                         *p_hash_type = xacl.info.sd_hs3->hash_type;
176                         /* Current version 3 (if no sys acl hash available). */
177                         memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
178                         break;
179                 case 4:
180                         *ppdesc = make_sec_desc(mem_ctx, SD_REVISION,
181                                         xacl.info.sd_hs4->sd->type | SEC_DESC_SELF_RELATIVE,
182                                         xacl.info.sd_hs4->sd->owner_sid,
183                                         xacl.info.sd_hs4->sd->group_sid,
184                                         xacl.info.sd_hs4->sd->sacl,
185                                         xacl.info.sd_hs4->sd->dacl,
186                                         &sd_size);
187                         *p_hash_type = xacl.info.sd_hs4->hash_type;
188                         /* Current version 4. */
189                         memcpy(hash, xacl.info.sd_hs4->hash, XATTR_SD_HASH_SIZE);
190                         memcpy(sys_acl_hash, xacl.info.sd_hs4->sys_acl_hash, XATTR_SD_HASH_SIZE);
191                         break;
192                 default:
193                         TALLOC_FREE(frame);
194                         return NT_STATUS_REVISION_MISMATCH;
195         }
196
197         TALLOC_FREE(frame);
198
199         return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
200 }
201
202 /*******************************************************************
203  Create a DATA_BLOB from a hash of the security descriptor storead at
204  the system layer and the NT ACL we wish to preserve
205 *******************************************************************/
206
207 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
208                         DATA_BLOB *pblob,
209                         uint16_t hash_type,
210                         uint8_t hash[XATTR_SD_HASH_SIZE])
211 {
212         struct xattr_NTACL xacl;
213         struct security_descriptor_hash_v3 sd_hs3;
214         enum ndr_err_code ndr_err;
215         TALLOC_CTX *ctx = talloc_tos();
216
217         ZERO_STRUCT(xacl);
218         ZERO_STRUCT(sd_hs3);
219
220         xacl.version = 3;
221         xacl.info.sd_hs3 = &sd_hs3;
222         xacl.info.sd_hs3->sd = discard_const_p(struct security_descriptor, psd);
223         xacl.info.sd_hs3->hash_type = hash_type;
224         memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
225
226         ndr_err = ndr_push_struct_blob(
227                         pblob, ctx, &xacl,
228                         (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
229
230         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
231                 DBG_INFO("ndr_push_xattr_NTACL failed: %s\n",
232                          ndr_errstr(ndr_err));
233                 return ndr_map_error2ntstatus(ndr_err);
234         }
235
236         return NT_STATUS_OK;
237 }
238
239 /*******************************************************************
240  Create a DATA_BLOB from a hash of the security descriptors 
241  (system and NT) stored at the system layer and the NT ACL we wish 
242  to preserve.
243 *******************************************************************/
244
245 static NTSTATUS create_sys_acl_blob(const struct security_descriptor *psd,
246                                     DATA_BLOB *pblob,
247                                     uint16_t hash_type,
248                                     uint8_t hash[XATTR_SD_HASH_SIZE],
249                                     const char *description,
250                                     uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE])
251 {
252         struct xattr_NTACL xacl;
253         struct security_descriptor_hash_v4 sd_hs4;
254         enum ndr_err_code ndr_err;
255         TALLOC_CTX *ctx = talloc_tos();
256         NTTIME nttime_now;
257         struct timeval now = timeval_current();
258         nttime_now = timeval_to_nttime(&now);
259
260         ZERO_STRUCT(xacl);
261         ZERO_STRUCT(sd_hs4);
262
263         xacl.version = 4;
264         xacl.info.sd_hs4 = &sd_hs4;
265         xacl.info.sd_hs4->sd = discard_const_p(struct security_descriptor, psd);
266         xacl.info.sd_hs4->hash_type = hash_type;
267         memcpy(&xacl.info.sd_hs4->hash[0], hash, XATTR_SD_HASH_SIZE);
268         xacl.info.sd_hs4->description = description;
269         xacl.info.sd_hs4->time = nttime_now;
270         memcpy(&xacl.info.sd_hs4->sys_acl_hash[0], sys_acl_hash, XATTR_SD_HASH_SIZE);
271
272         ndr_err = ndr_push_struct_blob(
273                         pblob, ctx, &xacl,
274                         (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
275
276         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
277                 DBG_INFO("ndr_push_xattr_NTACL failed: %s\n",
278                          ndr_errstr(ndr_err));
279                 return ndr_map_error2ntstatus(ndr_err);
280         }
281
282         return NT_STATUS_OK;
283 }
284
285 /*******************************************************************
286  Add in 3 inheritable components for a non-inheritable directory ACL.
287  CREATOR_OWNER/CREATOR_GROUP/WORLD.
288 *******************************************************************/
289
290 static NTSTATUS add_directory_inheritable_components(vfs_handle_struct *handle,
291                                 const char *name,
292                                 SMB_STRUCT_STAT *psbuf,
293                                 struct security_descriptor *psd)
294 {
295         struct connection_struct *conn = handle->conn;
296         int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
297         struct smb_filename smb_fname;
298         enum security_ace_type acltype;
299         uint32_t access_mask;
300         mode_t dir_mode;
301         mode_t file_mode;
302         mode_t mode;
303         struct security_ace *new_ace_list;
304
305         if (psd->dacl) {
306                 new_ace_list = talloc_zero_array(psd->dacl,
307                                                  struct security_ace,
308                                                  num_aces + 3);
309         } else {
310                 /*
311                  * make_sec_acl() at the bottom of this function
312                  * dupliates new_ace_list
313                  */
314                 new_ace_list = talloc_zero_array(talloc_tos(),
315                                                  struct security_ace,
316                                                  num_aces + 3);
317         }
318
319         if (new_ace_list == NULL) {
320                 return NT_STATUS_NO_MEMORY;
321         }
322
323         /* Fake a quick smb_filename. */
324         ZERO_STRUCT(smb_fname);
325         smb_fname.st = *psbuf;
326         smb_fname.base_name = discard_const_p(char, name);
327
328         dir_mode = unix_mode(conn,
329                         FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
330         file_mode = unix_mode(conn,
331                         FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
332
333         mode = dir_mode | file_mode;
334
335         DBG_DEBUG("directory %s, mode = 0%o\n", name, (unsigned int)mode);
336
337         if (num_aces) {
338                 memcpy(new_ace_list, psd->dacl->aces,
339                         num_aces * sizeof(struct security_ace));
340         }
341         access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
342                                 mode & 0700, false);
343
344         init_sec_ace(&new_ace_list[num_aces],
345                         &global_sid_Creator_Owner,
346                         acltype,
347                         access_mask,
348                         SEC_ACE_FLAG_CONTAINER_INHERIT|
349                                 SEC_ACE_FLAG_OBJECT_INHERIT|
350                                 SEC_ACE_FLAG_INHERIT_ONLY);
351         access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
352                                 (mode << 3) & 0700, false);
353         init_sec_ace(&new_ace_list[num_aces+1],
354                         &global_sid_Creator_Group,
355                         acltype,
356                         access_mask,
357                         SEC_ACE_FLAG_CONTAINER_INHERIT|
358                                 SEC_ACE_FLAG_OBJECT_INHERIT|
359                                 SEC_ACE_FLAG_INHERIT_ONLY);
360         access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
361                                 (mode << 6) & 0700, false);
362         init_sec_ace(&new_ace_list[num_aces+2],
363                         &global_sid_World,
364                         acltype,
365                         access_mask,
366                         SEC_ACE_FLAG_CONTAINER_INHERIT|
367                                 SEC_ACE_FLAG_OBJECT_INHERIT|
368                                 SEC_ACE_FLAG_INHERIT_ONLY);
369         if (psd->dacl) {
370                 psd->dacl->aces = new_ace_list;
371                 psd->dacl->num_aces += 3;
372                 psd->dacl->size += new_ace_list[num_aces].size +
373                         new_ace_list[num_aces+1].size +
374                         new_ace_list[num_aces+2].size;
375         } else {
376                 psd->dacl = make_sec_acl(psd,
377                                 NT4_ACL_REVISION,
378                                 3,
379                                 new_ace_list);
380                 if (psd->dacl == NULL) {
381                         return NT_STATUS_NO_MEMORY;
382                 }
383         }
384         return NT_STATUS_OK;
385 }
386
387 /**
388  * Validate an ACL blob
389  *
390  * This validates an ACL blob against the underlying filesystem ACL. If this
391  * function returns NT_STATUS_OK ppsd can be
392  *
393  * 1. the ACL from the blob (psd_from_fs=false), or
394  * 2. the ACL from the fs (psd_from_fs=true), or
395  * 3. NULL (!)
396  *
397  * If the return value is anything else then NT_STATUS_OK, ppsd is set to NULL
398  * and psd_from_fs set to false.
399  *
400  * Returning the underlying filesystem ACL in case no. 2 is really just an
401  * optimisation, because some validations have to fetch the filesytem ACL as
402  * part of the validation, so we already have it available and callers might
403  * need it as well.
404  **/
405 static NTSTATUS validate_nt_acl_blob(TALLOC_CTX *mem_ctx,
406                                      vfs_handle_struct *handle,
407                                      files_struct *fsp,
408                                      const struct smb_filename *smb_fname,
409                                      const DATA_BLOB *blob,
410                                      struct security_descriptor **ppsd,
411                                      bool *psd_is_from_fs)
412 {
413         NTSTATUS status;
414         uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
415         uint16_t xattr_version = 0;
416         uint8_t hash[XATTR_SD_HASH_SIZE];
417         uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE];
418         uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
419         uint8_t sys_acl_hash_tmp[XATTR_SD_HASH_SIZE];
420         struct security_descriptor *psd = NULL;
421         struct security_descriptor *psd_blob = NULL;
422         struct security_descriptor *psd_fs = NULL;
423         char *sys_acl_blob_description = NULL;
424         DATA_BLOB sys_acl_blob = { 0 };
425         struct acl_common_config *config = NULL;
426
427         *ppsd = NULL;
428         *psd_is_from_fs = false;
429
430         SMB_VFS_HANDLE_GET_DATA(handle, config,
431                                 struct acl_common_config,
432                                 return NT_STATUS_UNSUCCESSFUL);
433
434         status = parse_acl_blob(blob,
435                                 mem_ctx,
436                                 &psd_blob,
437                                 &hash_type,
438                                 &xattr_version,
439                                 &hash[0],
440                                 &sys_acl_hash[0]);
441         if (!NT_STATUS_IS_OK(status)) {
442                 DBG_DEBUG("parse_acl_blob returned %s\n", nt_errstr(status));
443                 goto fail;
444         }
445
446         /* determine which type of xattr we got */
447         switch (xattr_version) {
448         case 1:
449         case 2:
450                 /* These xattr types are unilatteral, they do not
451                  * require confirmation of the hash.  In particular,
452                  * the NTVFS file server uses version 1, but
453                  * 'samba-tool ntacl' can set these as well */
454                 *ppsd = psd_blob;
455                 return NT_STATUS_OK;
456         case 3:
457         case 4:
458                 if (config->ignore_system_acls) {
459                         *ppsd = psd_blob;
460                         return NT_STATUS_OK;
461                 }
462
463                 break;
464         default:
465                 DBG_DEBUG("ACL blob revision mismatch (%u) for file %s\n",
466                           (unsigned int)hash_type, smb_fname->base_name);
467                 TALLOC_FREE(psd_blob);
468                 return NT_STATUS_OK;
469         }
470
471         /* determine which type of xattr we got */
472         if (hash_type != XATTR_SD_HASH_TYPE_SHA256) {
473                 DBG_DEBUG("ACL blob hash type (%u) unexpected for file %s\n",
474                           (unsigned int)hash_type, smb_fname->base_name);
475                 TALLOC_FREE(psd_blob);
476                 return NT_STATUS_OK;
477         }
478
479         /* determine which type of xattr we got */
480         switch (xattr_version) {
481         case 4:
482         {
483                 int ret;
484                 if (fsp) {
485                         /* Get the full underlying sd, then hash. */
486                         ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle,
487                                                                fsp,
488                                                                mem_ctx,
489                                                                &sys_acl_blob_description,
490                                                                &sys_acl_blob);
491                 } else {
492                         /* Get the full underlying sd, then hash. */
493                         ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FILE(handle,
494                                                  smb_fname,
495                                                  mem_ctx,
496                                                  &sys_acl_blob_description,
497                                                  &sys_acl_blob);
498                 }
499
500                 /* If we fail to get the ACL blob (for some reason) then this
501                  * is not fatal, we just work based on the NT ACL only */
502                 if (ret == 0) {
503                         status = hash_blob_sha256(sys_acl_blob, sys_acl_hash_tmp);
504                         if (!NT_STATUS_IS_OK(status)) {
505                                 goto fail;
506                         }
507
508                         TALLOC_FREE(sys_acl_blob_description);
509                         TALLOC_FREE(sys_acl_blob.data);
510
511                         if (memcmp(&sys_acl_hash[0], &sys_acl_hash_tmp[0], 
512                                    XATTR_SD_HASH_SIZE) == 0) {
513                                 /* Hash matches, return blob sd. */
514                                 DBG_DEBUG("blob hash matches for file %s\n",
515                                           smb_fname->base_name);
516                                 *ppsd = psd_blob;
517                                 return NT_STATUS_OK;
518                         }
519                 }
520
521                 /* Otherwise, fall though and see if the NT ACL hash matches */
522         }
523         case 3:
524                 /* Get the full underlying sd for the hash
525                    or to return as backup. */
526                 if (fsp) {
527                         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
528                                                           fsp,
529                                                           HASH_SECURITY_INFO,
530                                                           mem_ctx,
531                                                           &psd_fs);
532                 } else {
533                         status = SMB_VFS_NEXT_GET_NT_ACL(handle,
534                                                          smb_fname,
535                                                          HASH_SECURITY_INFO,
536                                                          mem_ctx,
537                                                          &psd_fs);
538                 }
539
540                 if (!NT_STATUS_IS_OK(status)) {
541                         DBG_DEBUG("get_next_acl for file %s returned %s\n",
542                                   smb_fname->base_name, nt_errstr(status));
543                         goto fail;
544                 }
545
546                 status = hash_sd_sha256(psd_fs, hash_tmp);
547                 if (!NT_STATUS_IS_OK(status)) {
548                         TALLOC_FREE(psd_blob);
549                         *ppsd = psd_fs;
550                         *psd_is_from_fs = true;
551                         return NT_STATUS_OK;
552                 }
553
554                 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
555                         /* Hash matches, return blob sd. */
556                         DBG_DEBUG("blob hash matches for file %s\n",
557                                   smb_fname->base_name);
558                         *ppsd = psd_blob;
559                         return NT_STATUS_OK;
560                 }
561
562                 /* Hash doesn't match, return underlying sd. */
563                 DBG_DEBUG("blob hash does not match for file %s - returning "
564                           "file system SD mapping.\n",
565                           smb_fname->base_name);
566
567                 if (DEBUGLEVEL >= 10) {
568                         DBG_DEBUG("acl for blob hash for %s is:\n",
569                                   smb_fname->base_name);
570                         NDR_PRINT_DEBUG(security_descriptor, psd_fs);
571                 }
572
573                 TALLOC_FREE(psd_blob);
574                 *ppsd = psd_fs;
575                 *psd_is_from_fs = true;
576         }
577
578         return NT_STATUS_OK;
579
580 fail:
581         TALLOC_FREE(psd);
582         TALLOC_FREE(psd_blob);
583         TALLOC_FREE(psd_fs);
584         TALLOC_FREE(sys_acl_blob_description);
585         TALLOC_FREE(sys_acl_blob.data);
586         return status;
587 }
588
589 static NTSTATUS stat_fsp_or_smb_fname(vfs_handle_struct *handle,
590                                       files_struct *fsp,
591                                       const struct smb_filename *smb_fname,
592                                       SMB_STRUCT_STAT *sbuf,
593                                       SMB_STRUCT_STAT **psbuf)
594 {
595         NTSTATUS status;
596         int ret;
597
598         if (fsp) {
599                 status = vfs_stat_fsp(fsp);
600                 if (!NT_STATUS_IS_OK(status)) {
601                         return status;
602                 }
603                 *psbuf = &fsp->fsp_name->st;
604         } else {
605                 /*
606                  * https://bugzilla.samba.org/show_bug.cgi?id=11249
607                  *
608                  * We are currently guaranteed that 'name' here is a
609                  * smb_fname->base_name, which *cannot* contain a stream name
610                  * (':'). vfs_stat_smb_fname() splits a name into a base name +
611                  * stream name, which when we get here we know we've already
612                  * done.  So we have to call the stat or lstat VFS calls
613                  * directly here. Else, a base_name that contains a ':' (from a
614                  * demangled name) will get split again.
615                  *
616                  * FIXME.
617                  * This uglyness will go away once smb_fname is fully plumbed
618                  * through the VFS.
619                  */
620                 ret = vfs_stat_smb_basename(handle->conn,
621                                             smb_fname,
622                                             sbuf);
623                 if (ret == -1) {
624                         return map_nt_error_from_unix(errno);
625                 }
626         }
627
628         return NT_STATUS_OK;
629 }
630
631 /*******************************************************************
632  Pull a DATA_BLOB from an xattr given a pathname.
633  If the hash doesn't match, or doesn't exist - return the underlying
634  filesystem sd.
635 *******************************************************************/
636
637 NTSTATUS get_nt_acl_common(
638         NTSTATUS (*get_acl_blob_fn)(TALLOC_CTX *ctx,
639                                     vfs_handle_struct *handle,
640                                     files_struct *fsp,
641                                     const struct smb_filename *smb_fname,
642                                     DATA_BLOB *pblob),
643         vfs_handle_struct *handle,
644         files_struct *fsp,
645         const struct smb_filename *smb_fname_in,
646         uint32_t security_info,
647         TALLOC_CTX *mem_ctx,
648         struct security_descriptor **ppdesc)
649 {
650         DATA_BLOB blob = data_blob_null;
651         NTSTATUS status;
652         struct security_descriptor *psd = NULL;
653         const struct smb_filename *smb_fname = NULL;
654         bool psd_is_from_fs = false;
655         struct acl_common_config *config = NULL;
656
657         SMB_VFS_HANDLE_GET_DATA(handle, config,
658                                 struct acl_common_config,
659                                 return NT_STATUS_UNSUCCESSFUL);
660
661         if (fsp && smb_fname_in == NULL) {
662                 smb_fname = fsp->fsp_name;
663         } else {
664                 smb_fname = smb_fname_in;
665         }
666
667         DBG_DEBUG("name=%s\n", smb_fname->base_name);
668
669         status = get_acl_blob_fn(mem_ctx, handle, fsp, smb_fname, &blob);
670         if (NT_STATUS_IS_OK(status)) {
671                 status = validate_nt_acl_blob(mem_ctx,
672                                               handle,
673                                               fsp,
674                                               smb_fname,
675                                               &blob,
676                                               &psd,
677                                               &psd_is_from_fs);
678                 TALLOC_FREE(blob.data);
679                 if (!NT_STATUS_IS_OK(status)) {
680                         DBG_DEBUG("ACL validation for [%s] failed\n",
681                                   smb_fname->base_name);
682                         goto fail;
683                 }
684         }
685
686         if (psd == NULL) {
687                 /* Get the full underlying sd, as we failed to get the
688                  * blob for the hash, or the revision/hash type wasn't
689                  * known */
690
691                 if (config->ignore_system_acls) {
692                         SMB_STRUCT_STAT sbuf;
693                         SMB_STRUCT_STAT *psbuf = &sbuf;
694
695                         status = stat_fsp_or_smb_fname(handle, fsp, smb_fname,
696                                                        &sbuf, &psbuf);
697                         if (!NT_STATUS_IS_OK(status)) {
698                                 goto fail;
699                         }
700
701                         status = make_default_filesystem_acl(
702                                 mem_ctx,
703                                 config->default_acl_style,
704                                 smb_fname->base_name,
705                                 psbuf,
706                                 &psd);
707                         if (!NT_STATUS_IS_OK(status)) {
708                                 goto fail;
709                         }
710                 } else {
711                         if (fsp) {
712                                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
713                                                                   fsp,
714                                                                   security_info,
715                                                                   mem_ctx,
716                                                                   &psd);
717                         } else {
718                                 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
719                                                                  smb_fname,
720                                                                  security_info,
721                                                                  mem_ctx,
722                                                                  &psd);
723                         }
724
725                         if (!NT_STATUS_IS_OK(status)) {
726                                 DBG_DEBUG("get_next_acl for file %s "
727                                           "returned %s\n",
728                                           smb_fname->base_name,
729                                           nt_errstr(status));
730                                 goto fail;
731                         }
732
733                         psd_is_from_fs = true;
734                 }
735         }
736
737         if (psd_is_from_fs) {
738                 SMB_STRUCT_STAT sbuf;
739                 SMB_STRUCT_STAT *psbuf = &sbuf;
740                 bool is_directory = false;
741
742                 /*
743                  * We're returning the underlying ACL from the
744                  * filesystem. If it's a directory, and has no
745                  * inheritable ACE entries we have to fake them.
746                  */
747
748                 status = stat_fsp_or_smb_fname(handle, fsp, smb_fname,
749                                                &sbuf, &psbuf);
750                 if (!NT_STATUS_IS_OK(status)) {
751                         goto fail;
752                 }
753
754                 is_directory = S_ISDIR(psbuf->st_ex_mode);
755
756                 if (is_directory && !sd_has_inheritable_components(psd, true)) {
757                         status = add_directory_inheritable_components(
758                                 handle,
759                                 smb_fname->base_name,
760                                 psbuf,
761                                 psd);
762                         if (!NT_STATUS_IS_OK(status)) {
763                                 goto fail;
764                         }
765                 }
766
767                 /*
768                  * The underlying POSIX module always sets the
769                  * ~SEC_DESC_DACL_PROTECTED bit, as ACLs can't be inherited in
770                  * this way under POSIX. Remove it for Windows-style ACLs.
771                  */
772                 psd->type &= ~SEC_DESC_DACL_PROTECTED;
773         }
774
775         if (!(security_info & SECINFO_OWNER)) {
776                 psd->owner_sid = NULL;
777         }
778         if (!(security_info & SECINFO_GROUP)) {
779                 psd->group_sid = NULL;
780         }
781         if (!(security_info & SECINFO_DACL)) {
782                 psd->type &= ~SEC_DESC_DACL_PRESENT;
783                 psd->dacl = NULL;
784         }
785         if (!(security_info & SECINFO_SACL)) {
786                 psd->type &= ~SEC_DESC_SACL_PRESENT;
787                 psd->sacl = NULL;
788         }
789
790         if (DEBUGLEVEL >= 10) {
791                 DBG_DEBUG("returning acl for %s is:\n",
792                           smb_fname->base_name);
793                 NDR_PRINT_DEBUG(security_descriptor, psd);
794         }
795
796         *ppdesc = psd;
797
798         return NT_STATUS_OK;
799
800 fail:
801         TALLOC_FREE(psd);
802         return status;
803 }
804
805 /*********************************************************************
806  Set the underlying ACL (e.g. POSIX ACLS, POSIX owner, etc)
807 *********************************************************************/
808 static NTSTATUS set_underlying_acl(vfs_handle_struct *handle, files_struct *fsp,
809                                    struct security_descriptor *psd,
810                                    uint32_t security_info_sent,
811                                    bool chown_needed)
812 {
813         NTSTATUS status;
814         const struct security_token *token = NULL;
815
816         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
817         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
818                 return status;
819         }
820
821         /* We got access denied here. If we're already root,
822            or we didn't need to do a chown, or the fsp isn't
823            open with WRITE_OWNER access, just return. */
824         if (get_current_uid(handle->conn) == 0 || chown_needed == false ||
825             !(fsp->access_mask & SEC_STD_WRITE_OWNER)) {
826                 return NT_STATUS_ACCESS_DENIED;
827         }
828
829         /*
830          * Only allow take-ownership, not give-ownership. That's the way Windows
831          * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
832          * InputBuffer.OwnerSid is not a valid owner SID for a file in the
833          * objectstore, as determined in an implementation specific manner, the
834          * object store MUST return STATUS_INVALID_OWNER.
835          */
836         token = get_current_nttok(fsp->conn);
837         if (!security_token_is_sid(token, psd->owner_sid)) {
838                 return NT_STATUS_INVALID_OWNER;
839         }
840
841         DBG_DEBUG("overriding chown on file %s for sid %s\n",
842                    fsp_str_dbg(fsp), sid_string_tos(psd->owner_sid));
843
844         /* Ok, we failed to chown and we have
845            SEC_STD_WRITE_OWNER access - override. */
846         become_root();
847         status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
848         unbecome_root();
849
850         return status;
851 }
852
853 /*********************************************************************
854  Store a v3 security descriptor
855 *********************************************************************/
856 static NTSTATUS store_v3_blob(
857         NTSTATUS (*store_acl_blob_fsp_fn)(vfs_handle_struct *handle,
858                                           files_struct *fsp,
859                                           DATA_BLOB *pblob),
860         vfs_handle_struct *handle, files_struct *fsp,
861         struct security_descriptor *psd,
862         struct security_descriptor *pdesc_next,
863         uint8_t hash[XATTR_SD_HASH_SIZE])
864 {
865         NTSTATUS status;
866         DATA_BLOB blob;
867
868         if (DEBUGLEVEL >= 10) {
869                 DBG_DEBUG("storing xattr sd for file %s\n",
870                           fsp_str_dbg(fsp));
871                 NDR_PRINT_DEBUG(
872                     security_descriptor,
873                     discard_const_p(struct security_descriptor, psd));
874
875                 if (pdesc_next != NULL) {
876                         DBG_DEBUG("storing xattr sd based on \n");
877                         NDR_PRINT_DEBUG(
878                             security_descriptor,
879                             discard_const_p(struct security_descriptor,
880                                             pdesc_next));
881                 } else {
882                         DBG_DEBUG("ignoring underlying sd\n");
883                 }
884         }
885         status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
886         if (!NT_STATUS_IS_OK(status)) {
887                 DBG_DEBUG("create_acl_blob failed\n");
888                 return status;
889         }
890
891         status = store_acl_blob_fsp_fn(handle, fsp, &blob);
892         return status;
893 }
894
895 /*********************************************************************
896  Store a security descriptor given an fsp.
897 *********************************************************************/
898
899 NTSTATUS fset_nt_acl_common(
900         NTSTATUS (*get_acl_blob_fn)(TALLOC_CTX *ctx,
901                                     vfs_handle_struct *handle,
902                                     files_struct *fsp,
903                                     const struct smb_filename *smb_fname,
904                                     DATA_BLOB *pblob),
905         NTSTATUS (*store_acl_blob_fsp_fn)(vfs_handle_struct *handle,
906                                           files_struct *fsp,
907                                           DATA_BLOB *pblob),
908         const char *module_name,
909         vfs_handle_struct *handle, files_struct *fsp,
910         uint32_t security_info_sent,
911         const struct security_descriptor *orig_psd)
912 {
913         NTSTATUS status;
914         int ret;
915         DATA_BLOB blob, sys_acl_blob;
916         struct security_descriptor *pdesc_next = NULL;
917         struct security_descriptor *psd = NULL;
918         uint8_t hash[XATTR_SD_HASH_SIZE];
919         uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE];
920         bool chown_needed = false;
921         char *sys_acl_description;
922         TALLOC_CTX *frame = talloc_stackframe();
923         bool ignore_file_system_acl = lp_parm_bool(
924             SNUM(handle->conn), module_name, "ignore system acls", false);
925
926         if (DEBUGLEVEL >= 10) {
927                 DBG_DEBUG("incoming sd for file %s\n", fsp_str_dbg(fsp));
928                 NDR_PRINT_DEBUG(security_descriptor,
929                         discard_const_p(struct security_descriptor, orig_psd));
930         }
931
932         status = get_nt_acl_common(get_acl_blob_fn, handle, fsp,
933                         NULL,
934                         SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
935                                      frame,
936                         &psd);
937
938         if (!NT_STATUS_IS_OK(status)) {
939                 TALLOC_FREE(frame);
940                 return status;
941         }
942
943         psd->revision = orig_psd->revision;
944         /* All our SD's are self relative. */
945         psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
946
947         if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
948                 if (!dom_sid_equal(orig_psd->owner_sid, psd->owner_sid)) {
949                         /* We're changing the owner. */
950                         chown_needed = true;
951                 }
952                 psd->owner_sid = orig_psd->owner_sid;
953         }
954         if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
955                 if (!dom_sid_equal(orig_psd->group_sid, psd->group_sid)) {
956                         /* We're changing the group. */
957                         chown_needed = true;
958                 }
959                 psd->group_sid = orig_psd->group_sid;
960         }
961         if (security_info_sent & SECINFO_DACL) {
962                 if (security_descriptor_with_ms_nfs(orig_psd)) {
963                         /*
964                          * If the sd contains a MS NFS SID, do
965                          * nothing, it's a chmod() request from OS X
966                          * with AAPL context.
967                          */
968                         TALLOC_FREE(frame);
969                         return NT_STATUS_OK;
970                 }
971                 psd->dacl = orig_psd->dacl;
972                 psd->type |= SEC_DESC_DACL_PRESENT;
973         }
974         if (security_info_sent & SECINFO_SACL) {
975                 psd->sacl = orig_psd->sacl;
976                 psd->type |= SEC_DESC_SACL_PRESENT;
977         }
978
979         if (ignore_file_system_acl) {
980                 if (chown_needed) {
981                         /* send only ownership stuff to lower layer */
982                         security_info_sent &= (SECINFO_OWNER | SECINFO_GROUP);
983                         status = set_underlying_acl(handle, fsp, psd,
984                                                     security_info_sent, true);
985                         if (!NT_STATUS_IS_OK(status)) {
986                                 TALLOC_FREE(frame);
987                                 return status;
988                         }
989                 }
990                 ZERO_ARRAY(hash);
991                 status = store_v3_blob(store_acl_blob_fsp_fn, handle, fsp, psd,
992                                        NULL, hash);
993
994                 TALLOC_FREE(frame);
995                 return status;
996         }
997
998         status = set_underlying_acl(handle, fsp, psd, security_info_sent,
999                                     chown_needed);
1000         if (!NT_STATUS_IS_OK(status)) {
1001                 TALLOC_FREE(frame);
1002                 return status;
1003         }
1004
1005         /* Get the full underlying sd, then hash. */
1006         status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
1007                                           fsp,
1008                                           HASH_SECURITY_INFO,
1009                                           frame,
1010                                           &pdesc_next);
1011
1012         if (!NT_STATUS_IS_OK(status)) {
1013                 TALLOC_FREE(frame);
1014                 return status;
1015         }
1016
1017         status = hash_sd_sha256(pdesc_next, hash);
1018         if (!NT_STATUS_IS_OK(status)) {
1019                 TALLOC_FREE(frame);
1020                 return status;
1021         }
1022
1023         /* Get the full underlying sd, then hash. */
1024         ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle,
1025                                                fsp,
1026                                                frame,
1027                                                &sys_acl_description,
1028                                                &sys_acl_blob);
1029
1030         /* If we fail to get the ACL blob (for some reason) then this
1031          * is not fatal, we just work based on the NT ACL only */
1032         if (ret != 0) {
1033                 status = store_v3_blob(store_acl_blob_fsp_fn, handle, fsp, psd,
1034                                        pdesc_next, hash);
1035
1036                 TALLOC_FREE(frame);
1037                 return status;
1038         }
1039
1040         status = hash_blob_sha256(sys_acl_blob, sys_acl_hash);
1041         if (!NT_STATUS_IS_OK(status)) {
1042                 TALLOC_FREE(frame);
1043                 return status;
1044         }
1045
1046         if (DEBUGLEVEL >= 10) {
1047                 DBG_DEBUG("storing xattr sd for file %s based on system ACL\n",
1048                           fsp_str_dbg(fsp));
1049                 NDR_PRINT_DEBUG(security_descriptor,
1050                                 discard_const_p(struct security_descriptor, psd));
1051
1052                 DBG_DEBUG("storing hash in xattr sd based on system ACL and:\n");
1053                 NDR_PRINT_DEBUG(security_descriptor,
1054                                 discard_const_p(struct security_descriptor, pdesc_next));
1055         }
1056
1057         /* We store hashes of both the sys ACL blob and the NT
1058          * security desciptor mapped from that ACL so as to improve
1059          * our chances against some inadvertant change breaking the
1060          * hash used */
1061         status = create_sys_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash, 
1062                                      sys_acl_description, sys_acl_hash);
1063         if (!NT_STATUS_IS_OK(status)) {
1064                 DBG_DEBUG("create_sys_acl_blob failed\n");
1065                 TALLOC_FREE(frame);
1066                 return status;
1067         }
1068
1069         status = store_acl_blob_fsp_fn(handle, fsp, &blob);
1070
1071         TALLOC_FREE(frame);
1072         return status;
1073 }
1074
1075 static int acl_common_remove_object(vfs_handle_struct *handle,
1076                                         const struct smb_filename *smb_fname,
1077                                         bool is_directory)
1078 {
1079         connection_struct *conn = handle->conn;
1080         struct file_id id;
1081         files_struct *fsp = NULL;
1082         int ret = 0;
1083         char *parent_dir = NULL;
1084         const char *final_component = NULL;
1085         struct smb_filename local_fname = {0};
1086         struct smb_filename parent_dir_fname = {0};
1087         int saved_errno = 0;
1088         struct smb_filename *saved_dir_fname = NULL;
1089
1090         saved_dir_fname = vfs_GetWd(talloc_tos(),conn);
1091         if (saved_dir_fname == NULL) {
1092                 saved_errno = errno;
1093                 goto out;
1094         }
1095
1096         if (!parent_dirname(talloc_tos(), smb_fname->base_name,
1097                         &parent_dir, &final_component)) {
1098                 saved_errno = ENOMEM;
1099                 goto out;
1100         }
1101
1102         DBG_DEBUG("removing %s %s/%s\n", is_directory ? "directory" : "file",
1103                   parent_dir, final_component);
1104
1105         parent_dir_fname = (struct smb_filename) { .base_name = parent_dir };
1106
1107         /* cd into the parent dir to pin it. */
1108         ret = vfs_ChDir(conn, &parent_dir_fname);
1109         if (ret == -1) {
1110                 saved_errno = errno;
1111                 goto out;
1112         }
1113
1114         local_fname.base_name = discard_const_p(char, final_component);
1115
1116         /* Must use lstat here. */
1117         ret = SMB_VFS_LSTAT(conn, &local_fname);
1118         if (ret == -1) {
1119                 saved_errno = errno;
1120                 goto out;
1121         }
1122
1123         /* Ensure we have this file open with DELETE access. */
1124         id = vfs_file_id_from_sbuf(conn, &local_fname.st);
1125         for (fsp = file_find_di_first(conn->sconn, id); fsp;
1126                      fsp = file_find_di_next(fsp)) {
1127                 if (fsp->access_mask & DELETE_ACCESS &&
1128                                 fsp->delete_on_close) {
1129                         /* We did open this for delete,
1130                          * allow the delete as root.
1131                          */
1132                         break;
1133                 }
1134         }
1135
1136         if (!fsp) {
1137                 DBG_DEBUG("%s %s/%s not an open file\n",
1138                           is_directory ? "directory" : "file",
1139                           parent_dir, final_component);
1140                 saved_errno = EACCES;
1141                 goto out;
1142         }
1143
1144         become_root();
1145         if (is_directory) {
1146                 ret = SMB_VFS_NEXT_RMDIR(handle, &local_fname);
1147         } else {
1148                 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
1149         }
1150         unbecome_root();
1151
1152         if (ret == -1) {
1153                 saved_errno = errno;
1154         }
1155
1156   out:
1157
1158         TALLOC_FREE(parent_dir);
1159
1160         if (saved_dir_fname) {
1161                 vfs_ChDir(conn, saved_dir_fname);
1162                 TALLOC_FREE(saved_dir_fname);
1163         }
1164         if (saved_errno) {
1165                 errno = saved_errno;
1166         }
1167         return ret;
1168 }
1169
1170 int rmdir_acl_common(struct vfs_handle_struct *handle,
1171                      const struct smb_filename *smb_fname)
1172 {
1173         int ret;
1174
1175         /* Try the normal rmdir first. */
1176         ret = SMB_VFS_NEXT_RMDIR(handle, smb_fname);
1177         if (ret == 0) {
1178                 return 0;
1179         }
1180         if (errno == EACCES || errno == EPERM) {
1181                 /* Failed due to access denied,
1182                    see if we need to root override. */
1183                 return acl_common_remove_object(handle,
1184                                                 smb_fname,
1185                                                 true);
1186         }
1187
1188         DBG_DEBUG("unlink of %s failed %s\n",
1189                   smb_fname->base_name,
1190                   strerror(errno));
1191         return -1;
1192 }
1193
1194 int unlink_acl_common(struct vfs_handle_struct *handle,
1195                         const struct smb_filename *smb_fname)
1196 {
1197         int ret;
1198
1199         /* Try the normal unlink first. */
1200         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1201         if (ret == 0) {
1202                 return 0;
1203         }
1204         if (errno == EACCES || errno == EPERM) {
1205                 /* Failed due to access denied,
1206                    see if we need to root override. */
1207
1208                 /* Don't do anything fancy for streams. */
1209                 if (smb_fname->stream_name) {
1210                         return -1;
1211                 }
1212                 return acl_common_remove_object(handle,
1213                                         smb_fname,
1214                                         false);
1215         }
1216
1217         DBG_DEBUG("unlink of %s failed %s\n",
1218                   smb_fname->base_name,
1219                   strerror(errno));
1220         return -1;
1221 }
1222
1223 int chmod_acl_module_common(struct vfs_handle_struct *handle,
1224                             const struct smb_filename *smb_fname,
1225                             mode_t mode)
1226 {
1227         if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
1228                 /* Only allow this on POSIX pathnames. */
1229                 return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1230         }
1231         return 0;
1232 }
1233
1234 int fchmod_acl_module_common(struct vfs_handle_struct *handle,
1235                              struct files_struct *fsp, mode_t mode)
1236 {
1237         if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1238                 /* Only allow this on POSIX opens. */
1239                 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1240         }
1241         return 0;
1242 }
1243
1244 int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1245                                 const struct smb_filename *smb_fname,
1246                                 mode_t mode)
1247 {
1248         if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
1249                 /* Only allow this on POSIX pathnames. */
1250                 return SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
1251         }
1252         return 0;
1253 }
1254
1255 int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1256                                  struct files_struct *fsp, mode_t mode)
1257 {
1258         if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1259                 /* Only allow this on POSIX opens. */
1260                 return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
1261         }
1262         return 0;
1263 }