vfs: Use static_decl_vfs in all VFS modules
[samba.git] / source3 / modules / vfs_nfs4acl_xattr.c
1 /*
2  * Convert NFSv4 acls stored per http://www.suse.de/~agruen/nfs4acl/ to NT acls and vice versa.
3  *
4  * Copyright (C) Jiri Sasek, 2007
5  * based on the foobar.c module which is copyrighted by Volker Lendecke
6  * based on pvfs_acl_nfs4.c  Copyright (C) Andrew Tridgell 2006
7  *
8  * based on vfs_fake_acls:
9  * Copyright (C) Tim Potter, 1999-2000
10  * Copyright (C) Alexander Bokovoy, 2002
11  * Copyright (C) Andrew Bartlett, 2002,2012
12  * Copyright (C) Ralph Boehme 2017
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, see <http://www.gnu.org/licenses/>.
26  *
27  */
28
29 #include "includes.h"
30 #include "system/filesys.h"
31 #include "smbd/smbd.h"
32 #include "libcli/security/security_token.h"
33 #include "nfs4_acls.h"
34 #include "librpc/gen_ndr/ndr_nfs4acl.h"
35 #include "nfs4acl_xattr.h"
36 #include "nfs4acl_xattr_ndr.h"
37 #include "nfs4acl_xattr_xdr.h"
38
39 #undef DBGC_CLASS
40 #define DBGC_CLASS DBGC_VFS
41
42 static const struct enum_list nfs4acl_encoding[] = {
43         {NFS4ACL_ENCODING_NDR, "ndr"},
44         {NFS4ACL_ENCODING_XDR, "xdr"},
45 };
46
47 /*
48  * Check if someone changed the POSIX mode, for files we expect 0666, for
49  * directories 0777. Discard the ACL blob if the mode is different.
50  */
51 static bool nfs4acl_validate_blob(vfs_handle_struct *handle,
52                                   const struct smb_filename *smb_fname)
53 {
54         struct nfs4acl_config *config = NULL;
55         mode_t expected_mode;
56         int saved_errno = 0;
57         int ret;
58
59         SMB_VFS_HANDLE_GET_DATA(handle, config,
60                                 struct nfs4acl_config,
61                                 return false);
62
63         if (!VALID_STAT(smb_fname->st)) {
64                 /* might be a create */
65                 return true;
66         }
67
68         if (S_ISDIR(smb_fname->st.st_ex_mode)) {
69                 expected_mode = 0777;
70         } else {
71                 expected_mode = 0666;
72         }
73         if ((smb_fname->st.st_ex_mode & expected_mode) == expected_mode) {
74                 return true;
75         }
76
77         become_root();
78         ret = SMB_VFS_NEXT_REMOVEXATTR(handle,
79                                        smb_fname,
80                                        config->xattr_name);
81         if (ret != 0) {
82                 saved_errno = errno;
83         }
84         unbecome_root();
85         if (saved_errno != 0) {
86                 errno = saved_errno;
87         }
88         if (ret != 0 && errno != ENOATTR) {
89                 DBG_ERR("Removing NFS4 xattr failed: %s\n", strerror(errno));
90                 return false;
91         }
92
93         return true;
94 }
95
96 static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
97                                  files_struct *fsp,
98                                  const struct smb_filename *smb_fname_in,
99                                  TALLOC_CTX *mem_ctx,
100                                  DATA_BLOB *blob)
101 {
102         struct nfs4acl_config *config = NULL;
103         const struct smb_filename *smb_fname = NULL;
104         size_t allocsize = 256;
105         ssize_t length;
106         bool ok;
107
108         SMB_VFS_HANDLE_GET_DATA(handle, config,
109                                 struct nfs4acl_config,
110                                 return NT_STATUS_INTERNAL_ERROR);
111
112         *blob = data_blob_null;
113
114         if (fsp == NULL && smb_fname_in == NULL) {
115                 return NT_STATUS_INTERNAL_ERROR;
116         }
117         smb_fname = smb_fname_in;
118         if (smb_fname == NULL) {
119                 smb_fname = fsp->fsp_name;
120         }
121         if (smb_fname == NULL) {
122                 return NT_STATUS_INTERNAL_ERROR;
123         }
124
125         ok = nfs4acl_validate_blob(handle, smb_fname);
126         if (!ok) {
127                 return NT_STATUS_INTERNAL_ERROR;
128         }
129
130         do {
131                 int saved_errno = 0;
132
133                 allocsize *= 4;
134                 ok = data_blob_realloc(mem_ctx, blob, allocsize);
135                 if (!ok) {
136                         return NT_STATUS_NO_MEMORY;
137                 }
138
139                 become_root();
140                 if (fsp != NULL && fsp->fh->fd != -1) {
141                         length = SMB_VFS_NEXT_FGETXATTR(handle,
142                                                         fsp,
143                                                         config->xattr_name,
144                                                         blob->data,
145                                                         blob->length);
146                 } else {
147                         length = SMB_VFS_NEXT_GETXATTR(handle,
148                                                        smb_fname,
149                                                        config->xattr_name,
150                                                        blob->data,
151                                                        blob->length);
152                 }
153                 if (length == -1) {
154                         saved_errno = errno;
155                 }
156                 unbecome_root();
157                 if (saved_errno != 0) {
158                         errno = saved_errno;
159                 }
160         } while (length == -1 && errno == ERANGE && allocsize <= 65536);
161
162         if (length == -1) {
163                 return map_nt_error_from_unix(errno);
164         }
165
166         return NT_STATUS_OK;
167 }
168
169 static NTSTATUS nfs4acl_xattr_default_sd(
170         struct vfs_handle_struct *handle,
171         const struct smb_filename *smb_fname,
172         TALLOC_CTX *mem_ctx,
173         struct security_descriptor **sd)
174 {
175         struct nfs4acl_config *config = NULL;
176         enum default_acl_style default_acl_style;
177         mode_t required_mode;
178         SMB_STRUCT_STAT sbuf = smb_fname->st;
179         int ret;
180
181         SMB_VFS_HANDLE_GET_DATA(handle, config,
182                                 struct nfs4acl_config,
183                                 return NT_STATUS_INTERNAL_ERROR);
184
185         default_acl_style = config->default_acl_style;
186
187         if (!VALID_STAT(sbuf)) {
188                 ret = vfs_stat_smb_basename(handle->conn,
189                                             smb_fname,
190                                             &sbuf);
191                 if (ret != 0) {
192                         return map_nt_error_from_unix(errno);
193                 }
194         }
195
196         if (S_ISDIR(sbuf.st_ex_mode)) {
197                 required_mode = 0777;
198         } else {
199                 required_mode = 0666;
200         }
201         if ((sbuf.st_ex_mode & required_mode) != required_mode) {
202                 default_acl_style = DEFAULT_ACL_POSIX;
203         }
204
205         return make_default_filesystem_acl(mem_ctx,
206                                            default_acl_style,
207                                            smb_fname->base_name,
208                                            &sbuf,
209                                            sd);
210 }
211
212 static NTSTATUS nfs4acl_blob_to_smb4(struct vfs_handle_struct *handle,
213                                      DATA_BLOB *blob,
214                                      TALLOC_CTX *mem_ctx,
215                                      struct SMB4ACL_T **smb4acl)
216 {
217         struct nfs4acl_config *config = NULL;
218         NTSTATUS status;
219
220         SMB_VFS_HANDLE_GET_DATA(handle, config,
221                                 struct nfs4acl_config,
222                                 return NT_STATUS_INTERNAL_ERROR);
223
224         switch (config->encoding) {
225         case NFS4ACL_ENCODING_NDR:
226                 status = nfs4acl_ndr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
227                 break;
228         case NFS4ACL_ENCODING_XDR:
229                 status = nfs4acl_xdr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
230                 break;
231         default:
232                 status = NT_STATUS_INTERNAL_ERROR;
233                 break;
234         }
235
236         return status;
237 }
238
239 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
240                                    struct files_struct *fsp,
241                                    uint32_t security_info,
242                                    TALLOC_CTX *mem_ctx,
243                                    struct security_descriptor **sd)
244 {
245         struct SMB4ACL_T *smb4acl = NULL;
246         TALLOC_CTX *frame = talloc_stackframe();
247         DATA_BLOB blob;
248         NTSTATUS status;
249
250         status = nfs4acl_get_blob(handle, fsp, NULL, frame, &blob);
251         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
252                 TALLOC_FREE(frame);
253                 return nfs4acl_xattr_default_sd(
254                         handle, fsp->fsp_name, mem_ctx, sd);
255         }
256         if (!NT_STATUS_IS_OK(status)) {
257                 TALLOC_FREE(frame);
258                 return status;
259         }
260
261         status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
262         if (!NT_STATUS_IS_OK(status)) {
263                 TALLOC_FREE(frame);
264                 return status;
265         }
266
267         status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
268                                       sd, smb4acl);
269         TALLOC_FREE(frame);
270         return status;
271 }
272
273 static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
274                                   const struct smb_filename *smb_fname,
275                                   uint32_t security_info,
276                                   TALLOC_CTX *mem_ctx,
277                                   struct security_descriptor **sd)
278 {
279         struct SMB4ACL_T *smb4acl = NULL;
280         TALLOC_CTX *frame = talloc_stackframe();
281         DATA_BLOB blob;
282         NTSTATUS status;
283
284         status = nfs4acl_get_blob(handle, NULL, smb_fname, frame, &blob);
285         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
286                 TALLOC_FREE(frame);
287                 return nfs4acl_xattr_default_sd(
288                         handle, smb_fname, mem_ctx, sd);
289         }
290         if (!NT_STATUS_IS_OK(status)) {
291                 TALLOC_FREE(frame);
292                 return status;
293         }
294
295         status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
296         if (!NT_STATUS_IS_OK(status)) {
297                 TALLOC_FREE(frame);
298                 return status;
299         }
300
301         status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
302                                      security_info, mem_ctx, sd,
303                                      smb4acl);
304         TALLOC_FREE(frame);
305         return status;
306 }
307
308 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
309                                    files_struct *fsp,
310                                    struct SMB4ACL_T *smb4acl)
311 {
312         struct nfs4acl_config *config = NULL;
313         DATA_BLOB blob;
314         NTSTATUS status;
315         int saved_errno = 0;
316         int ret;
317
318         SMB_VFS_HANDLE_GET_DATA(handle, config,
319                                 struct nfs4acl_config,
320                                 return false);
321
322         switch (config->encoding) {
323         case NFS4ACL_ENCODING_NDR:
324                 status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
325                                                      smb4acl, &blob);
326                 break;
327         case NFS4ACL_ENCODING_XDR:
328                 status = nfs4acl_smb4acl_to_xdr_blob(handle, talloc_tos(),
329                                                      smb4acl, &blob);
330                 break;
331         default:
332                 status = NT_STATUS_INTERNAL_ERROR;
333                 break;
334         }
335         if (!NT_STATUS_IS_OK(status)) {
336                 return false;
337         }
338
339         become_root();
340         if (fsp->fh->fd != -1) {
341                 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
342                                              blob.data, blob.length, 0);
343         } else {
344                 ret = SMB_VFS_NEXT_SETXATTR(handle, fsp->fsp_name,
345                                             config->xattr_name,
346                                             blob.data, blob.length, 0);
347         }
348         if (ret != 0) {
349                 saved_errno = errno;
350         }
351         unbecome_root();
352         data_blob_free(&blob);
353         if (saved_errno != 0) {
354                 errno = saved_errno;
355         }
356         if (ret != 0) {
357                 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
358                 return false;
359         }
360
361         return true;
362 }
363
364 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
365                          files_struct *fsp,
366                          uint32_t security_info_sent,
367                          const struct security_descriptor *psd)
368 {
369         struct nfs4acl_config *config = NULL;
370         const struct security_token *token = NULL;
371         mode_t existing_mode;
372         mode_t expected_mode;
373         mode_t restored_mode;
374         bool chown_needed = false;
375         NTSTATUS status;
376         int ret;
377
378         SMB_VFS_HANDLE_GET_DATA(handle, config,
379                                 struct nfs4acl_config,
380                                 return NT_STATUS_INTERNAL_ERROR);
381
382         if (!VALID_STAT(fsp->fsp_name->st)) {
383                 DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp));
384                 return NT_STATUS_INTERNAL_ERROR;
385         }
386
387         existing_mode = fsp->fsp_name->st.st_ex_mode;
388         if (S_ISDIR(existing_mode)) {
389                 expected_mode = 0777;
390         } else {
391                 expected_mode = 0666;
392         }
393         if ((existing_mode & expected_mode) != expected_mode) {
394                 int saved_errno = 0;
395
396                 restored_mode = existing_mode | expected_mode;
397
398                 become_root();
399                 if (fsp->fh->fd != -1) {
400                         ret = SMB_VFS_NEXT_FCHMOD(handle,
401                                                   fsp,
402                                                   restored_mode);
403                 } else {
404                         ret = SMB_VFS_NEXT_CHMOD(handle,
405                                                  fsp->fsp_name,
406                                                  restored_mode);
407                 }
408                 if (ret != 0) {
409                         saved_errno = errno;
410                 }
411                 unbecome_root();
412                 if (saved_errno != 0) {
413                         errno = saved_errno;
414                 }
415                 if (ret != 0) {
416                         DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
417                                 fsp_str_dbg(fsp), existing_mode,
418                                 strerror(errno));
419                         return map_nt_error_from_unix(errno);
420                 }
421         }
422
423         status = smb_set_nt_acl_nfs4(handle,
424                                      fsp,
425                                      &config->nfs4_params,
426                                      security_info_sent,
427                                      psd,
428                                      nfs4acl_smb4acl_set_fn);
429         if (NT_STATUS_IS_OK(status)) {
430                 return NT_STATUS_OK;
431         }
432
433         /*
434          * We got access denied. If we're already root, or we didn't
435          * need to do a chown, or the fsp isn't open with WRITE_OWNER
436          * access, just return.
437          */
438
439         if ((security_info_sent & SECINFO_OWNER) &&
440             (psd->owner_sid != NULL))
441         {
442                 chown_needed = true;
443         }
444         if ((security_info_sent & SECINFO_GROUP) &&
445             (psd->group_sid != NULL))
446         {
447                 chown_needed = true;
448         }
449
450         if (get_current_uid(handle->conn) == 0 ||
451             chown_needed == false ||
452             !(fsp->access_mask & SEC_STD_WRITE_OWNER))
453         {
454                 return NT_STATUS_ACCESS_DENIED;
455         }
456
457         /*
458          * Only allow take-ownership, not give-ownership. That's the way Windows
459          * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
460          * InputBuffer.OwnerSid is not a valid owner SID for a file in the
461          * objectstore, as determined in an implementation specific manner, the
462          * object store MUST return STATUS_INVALID_OWNER.
463          */
464         token = get_current_nttok(fsp->conn);
465         if (!security_token_is_sid(token, psd->owner_sid)) {
466                 return NT_STATUS_INVALID_OWNER;
467         }
468
469         DBG_DEBUG("overriding chown on file %s for sid %s\n",
470                   fsp_str_dbg(fsp), sid_string_tos(psd->owner_sid));
471
472         become_root();
473         status = smb_set_nt_acl_nfs4(handle,
474                                      fsp,
475                                      &config->nfs4_params,
476                                      security_info_sent,
477                                      psd,
478                                      nfs4acl_smb4acl_set_fn);
479         unbecome_root();
480         return status;
481 }
482
483 static int nfs4acl_connect(struct vfs_handle_struct *handle,
484                            const char *service,
485                            const char *user)
486 {
487         struct nfs4acl_config *config = NULL;
488         const struct enum_list *default_acl_style_list = NULL;
489         const char *default_xattr_name = NULL;
490         int enumval;
491         unsigned nfs_version;
492         int ret;
493
494         default_acl_style_list = get_default_acl_style_list();
495
496         config = talloc_zero(handle->conn, struct nfs4acl_config);
497         if (config == NULL) {
498                 DBG_ERR("talloc_zero() failed\n");
499                 return -1;
500         }
501
502         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
503         if (ret < 0) {
504                 TALLOC_FREE(config);
505                 return ret;
506         }
507
508         ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
509         if (ret < 0) {
510                 TALLOC_FREE(config);
511                 return ret;
512         }
513
514         enumval = lp_parm_enum(SNUM(handle->conn),
515                                "nfs4acl_xattr",
516                                "encoding",
517                                nfs4acl_encoding,
518                                NFS4ACL_ENCODING_NDR);
519         if (enumval == -1) {
520                 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
521                 return -1;
522         }
523         config->encoding = (enum nfs4acl_encoding)enumval;
524
525         switch (config->encoding) {
526         case NFS4ACL_ENCODING_XDR:
527                 default_xattr_name = NFS4ACL_XDR_XATTR_NAME;
528                 break;
529         case NFS4ACL_ENCODING_NDR:
530         default:
531                 default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
532                 break;
533         }
534
535         nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
536                                             "nfs4acl_xattr",
537                                             "version",
538                                             41);
539         switch (nfs_version) {
540         case 40:
541                 config->nfs_version = ACL4_XATTR_VERSION_40;
542                 break;
543         case 41:
544                 config->nfs_version = ACL4_XATTR_VERSION_41;
545                 break;
546         default:
547                 config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
548                 break;
549         }
550
551         config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
552                                                  "nfs4acl_xattr",
553                                                  "default acl style",
554                                                  default_acl_style_list,
555                                                  DEFAULT_ACL_EVERYONE);
556
557         config->xattr_name = lp_parm_talloc_string(config,
558                                                    SNUM(handle->conn),
559                                                    "nfs4acl_xattr",
560                                                    "xattr_name",
561                                                    default_xattr_name);
562
563         SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
564                                 return -1);
565
566         /*
567          * Ensure we have the parameters correct if we're using this module.
568          */
569         DBG_NOTICE("Setting 'inherit acls = true', "
570                    "'dos filemode = true', "
571                    "'force unknown acl user = true', "
572                    "'create mask = 0666', "
573                    "'directory mask = 0777' and "
574                    "'store dos attributes = yes' "
575                    "for service [%s]\n", service);
576
577         lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
578         lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
579         lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
580         lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
581         lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
582         lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
583
584         return 0;
585 }
586
587 /*
588    As long as Samba does not support an exiplicit method for a module
589    to define conflicting vfs methods, we should override all conflicting
590    methods here.  That way, we know we are using the NFSv4 storage
591
592    Function declarations taken from vfs_solarisacl
593 */
594
595 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
596                                         const struct smb_filename *smb_fname,
597                                         SMB_ACL_TYPE_T type,
598                                         TALLOC_CTX *mem_ctx)
599 {
600         return (SMB_ACL_T)NULL;
601 }
602
603 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
604                                                     files_struct *fsp,
605                                                     TALLOC_CTX *mem_ctx)
606 {
607         return (SMB_ACL_T)NULL;
608 }
609
610 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
611                                          const struct smb_filename *smb_fname,
612                                          SMB_ACL_TYPE_T type,
613                                          SMB_ACL_T theacl)
614 {
615         return -1;
616 }
617
618 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
619                                        files_struct *fsp,
620                                        SMB_ACL_T theacl)
621 {
622         return -1;
623 }
624
625 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
626                         const struct smb_filename *smb_fname)
627 {
628         return -1;
629 }
630
631 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
632                         const struct smb_filename *smb_fname,
633                         TALLOC_CTX *mem_ctx,
634                         char **blob_description,
635                         DATA_BLOB *blob)
636 {
637         return -1;
638 }
639
640 static int nfs4acl_xattr_fail__sys_acl_blob_get_fd(vfs_handle_struct *handle, files_struct *fsp, TALLOC_CTX *mem_ctx, char **blob_description, DATA_BLOB *blob)
641 {
642         return -1;
643 }
644
645 /* VFS operations structure */
646
647 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
648         .connect_fn = nfs4acl_connect,
649         .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
650         .get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
651         .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
652
653         .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
654         .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
655         .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
656         .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
657         .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
658         .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
659         .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
660 };
661
662 static_decl_vfs;
663 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
664 {
665         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
666                                 &nfs4acl_xattr_fns);
667 }