s3/utils: Add support to smbcacls to restore dacls from file
authorNoel Power <noel.power@suse.com>
Tue, 14 Nov 2023 09:12:01 +0000 (09:12 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 15 Nov 2023 04:05:34 +0000 (04:05 +0000)
Allow smbcacls to restore dacls to a directory from file created by
with smbcacls '--save' or icalcs /save

Signed-off-by: Noel Power <noel.power@suse.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source3/utils/smbcacls.c

index 40f71fbdbb6ce884e6e78ddef94d1904108feb3c..0575a254c29bdddead09f340ee02772bdbc254ab 100644 (file)
@@ -2001,6 +2001,164 @@ out:
        return result;
 }
 
+struct restore_dacl {
+       const char *path;
+       struct security_descriptor *sd;
+};
+
+/*
+ * Restore dacls from 'savefile' produced by
+ * 'icacls name /save' or 'smbcacls --save'
+ */
+static int cacl_restore(struct cli_state *cli,
+                       struct cli_credentials *creds,
+                       bool numeric, const char *restorefile)
+{
+       int restore_fd;
+       int result;
+       struct save_restore_stats stats = { 0 };
+
+       char **lines = NULL;
+       char *content = NULL;
+       char *convert_content = NULL;
+       size_t content_size;
+       struct restore_dacl *entries = NULL;
+       int numlines, i = 0;
+       bool ok;
+       struct dom_sid *sid = NULL;
+
+       if (restorefile == NULL) {
+               DBG_ERR("No restore file specified\n");
+               result = EXIT_FAILED;
+               goto out;
+       }
+
+       if (test_args) {
+               result = EXIT_OK;
+               goto out;
+       }
+
+       restore_fd = open(restorefile, O_RDONLY, S_IRUSR | S_IWUSR);
+       if (restore_fd < 0) {
+               DBG_ERR("Failed to open %s.\n", restorefile);
+               result = EXIT_FAILED;
+               goto out;
+       }
+
+       content = fd_load(restore_fd, &content_size, 0, talloc_tos());
+
+       close(restore_fd);
+
+       if (content == NULL) {
+               DBG_ERR("Failed to load content from %s.\n", restorefile);
+               result = EXIT_FAILED;
+               goto out;
+       }
+
+       ok = convert_string_talloc(talloc_tos(),
+                                  CH_UTF16,
+                                  CH_UNIX,
+                                  content,
+                                  utf16_len_n(content, content_size),
+                                  (void **)(void *)&convert_content,
+                                  &content_size);
+
+       TALLOC_FREE(content);
+
+       if (!ok) {
+               DBG_ERR("Failed to convert content from %s "
+                       "to CH_UNIX.\n", restorefile);
+               result = EXIT_FAILED;
+               goto out;
+       }
+
+       lines = file_lines_parse(convert_content,
+                                content_size, &numlines, talloc_tos());
+
+       if (lines == NULL) {
+               DBG_ERR("Failed to parse lines from content of %s.",
+                       restorefile);
+               result = EXIT_FAILED;
+               goto out;
+       }
+
+       entries = talloc_zero_array(lines, struct restore_dacl, numlines / 2);
+
+       if (entries == NULL) {
+               DBG_ERR("error processing %s, out of memory\n", restorefile);
+               result = EXIT_FAILED;
+               goto out;
+       }
+
+       sid = get_domain_sid(cli);
+
+       while (i < numlines) {
+               int index = i / 2;
+               int first_line = (i % 2) == 0;
+
+               if (first_line) {
+                       char *tmp = NULL;
+                       tmp = lines[i];
+                       /* line can be blank if root of share */
+                       if (strlen(tmp) == 0) {
+                               entries[index].path = talloc_strdup(lines,
+                                                                   "\\");
+                       } else {
+                               entries[index].path = lines[i];
+                       }
+               } else {
+                       entries[index].sd = sddl_decode(lines, lines[i], sid);
+                       entries[index].sd->type |=
+                           SEC_DESC_DACL_AUTO_INHERIT_REQ;
+                       entries[index].sd->type |= SEC_DESC_SACL_AUTO_INHERITED;
+               }
+               i++;
+       }
+       for (i = 0; i < (numlines / 2); i++) {
+               int mode = SMB_ACL_SET;
+               int set_result;
+               struct cli_state *targetcli = NULL;
+               char *targetpath = NULL;
+               NTSTATUS status;
+
+               /* check for dfs */
+               status = cli_resolve_path(talloc_tos(),
+                                         "",
+                                         creds,
+                                         cli,
+                                         entries[i].path,
+                                         &targetcli, &targetpath);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("Error failed to process file: %s\n",
+                              entries[i].path);
+                       stats.failure += 1;
+                       continue;
+               }
+
+               set_result = cacl_set_from_sd(targetcli,
+                                             targetpath,
+                                             entries[i].sd, mode, numeric);
+
+               if (set_result == EXIT_OK) {
+                       printf("Successfully processed file: %s\n",
+                              entries[i].path);
+                       stats.success += 1;
+               } else {
+                       printf("Error failed to process file: %s\n",
+                              entries[i].path);
+                       stats.failure += 1;
+               }
+       }
+
+       result = EXIT_OK;
+out:
+       TALLOC_FREE(lines);
+       fprintf(stdout, "Successfully processed %d files: "
+               "Failed processing %d files\n", stats.success, stats.failure);
+       return result;
+}
+
 /****************************************************************************
   main program
 ****************************************************************************/
@@ -2382,9 +2540,15 @@ int main(int argc, char *argv[])
                                           numeric);
                }
        } else {
-               if (save_file) {
+               if (save_file || restore_file) {
                        sddl = 1;
-                       result = cacl_dump_dacl(cli, creds, filename);
+                       if (save_file) {
+                               result = cacl_dump_dacl(cli, creds, filename);
+                       } else {
+                               result = cacl_restore(targetcli,
+                                                     creds,
+                                                     numeric, restore_file);
+                       }
                } else {
                        result = cacl_dump(targetcli, targetfile, numeric);
                }