Commit 0d6d493 FILES: Handle files provider sources

3 files Authored by jstephen 2 months ago , Committed by jhrozek 2 months ago ,
FILES: Handle files provider sources

Setup watches on passwd and group files provided with the files provider
options passwd_files and group_files lists

Resolves:
https://pagure.io/SSSD/sssd/issue/3402

Reviewed-by: Pavel Březina <pbrezina@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>

    
  1 @@ -23,6 +23,138 @@
  2   #include "providers/files/files_private.h"
  3   #include "util/util.h"
  4   
  5 + #define DEFAULT_PASSWD_FILE "/etc/passwd"
  6 + #define DEFAULT_GROUP_FILE "/etc/group"
  7 + 
  8 + static errno_t files_init_file_sources(TALLOC_CTX *mem_ctx,
  9 +                                        struct be_ctx *be_ctx,
 10 +                                        const char ***_passwd_files,
 11 +                                        const char ***_group_files)
 12 + {
 13 +     TALLOC_CTX *tmp_ctx = NULL;
 14 +     char *conf_passwd_files;
 15 +     char *conf_group_files;
 16 +     char **passwd_list = NULL;
 17 +     char **group_list = NULL;
 18 +     int num_passwd_files = 0;
 19 +     int num_group_files = 0;
 20 +     const char **passwd_files = NULL;
 21 +     const char **group_files = NULL;
 22 +     const char *dfl_passwd_files = NULL;
 23 +     const char *env_group_files = NULL;
 24 +     int i;
 25 +     errno_t ret;
 26 + 
 27 +     tmp_ctx = talloc_new(NULL);
 28 +     if (tmp_ctx == NULL) {
 29 +         ret = ENOMEM;
 30 +         goto done;
 31 +     }
 32 + 
 33 +     dfl_passwd_files = getenv("SSS_FILES_PASSWD");
 34 +     if (dfl_passwd_files) {
 35 +         sss_log(SSS_LOG_ALERT,
 36 +                 "Defaulting to %s for the passwd file, "
 37 +                 "this should only be used for testing!\n",
 38 +                 dfl_passwd_files);
 39 +     } else {
 40 +         dfl_passwd_files = DEFAULT_PASSWD_FILE;
 41 +     }
 42 +     DEBUG(SSSDBG_TRACE_FUNC,
 43 +           "Using default passwd file: [%s].\n", dfl_passwd_files);
 44 + 
 45 +     env_group_files = getenv("SSS_FILES_GROUP");
 46 +     if (env_group_files) {
 47 +         sss_log(SSS_LOG_ALERT,
 48 +                 "Defaulting to %s for the group file, "
 49 +                 "this should only be used for testing!\n",
 50 +                 env_group_files);
 51 +     } else {
 52 +         env_group_files = DEFAULT_GROUP_FILE;
 53 +     }
 54 +     DEBUG(SSSDBG_TRACE_FUNC,
 55 +           "Using default group file: [%s].\n", DEFAULT_GROUP_FILE);
 56 + 
 57 +     ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path,
 58 +                             CONFDB_FILES_PASSWD, dfl_passwd_files,
 59 +                             &conf_passwd_files);
 60 +     if (ret != EOK) {
 61 +         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to retrieve confdb passwd files!\n");
 62 +         goto done;
 63 +     }
 64 + 
 65 +     ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path,
 66 +                             CONFDB_FILES_GROUP, env_group_files,
 67 +                             &conf_group_files);
 68 +     if (ret != EOK) {
 69 +         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to retrieve confdb group files!\n");
 70 +         goto done;
 71 +     }
 72 + 
 73 +     ret = split_on_separator(tmp_ctx, conf_passwd_files, ',', true, true,
 74 +                              &passwd_list, &num_passwd_files);
 75 +     if (ret != EOK) {
 76 +         DEBUG(SSSDBG_CRIT_FAILURE,
 77 +                 "Failed to parse passwd list!\n");
 78 +         goto done;
 79 +     }
 80 + 
 81 +     passwd_files = talloc_zero_array(tmp_ctx, const char *,
 82 +                                      num_passwd_files + 1);
 83 +     if (passwd_files == NULL) {
 84 +         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
 85 +         ret = ENOMEM;
 86 +         goto done;
 87 +     }
 88 + 
 89 +     for (i = 0; i < num_passwd_files; i++) {
 90 +         DEBUG(SSSDBG_TRACE_FUNC,
 91 +               "Using passwd file: [%s].\n", passwd_list[i]);
 92 + 
 93 +         passwd_files[i] = talloc_strdup(passwd_files, passwd_list[i]);
 94 +         if (passwd_files[i] == NULL) {
 95 +             ret = ENOMEM;
 96 +             goto done;
 97 +         }
 98 +     }
 99 + 
100 +     /* Retrieve list of group files */
101 +     ret = split_on_separator(tmp_ctx, conf_group_files, ',', true, true,
102 +                              &group_list, &num_group_files);
103 +     if (ret != EOK) {
104 +         DEBUG(SSSDBG_CRIT_FAILURE,
105 +                 "Failed to parse group files!\n");
106 +         goto done;
107 +     }
108 + 
109 +     group_files = talloc_zero_array(tmp_ctx, const char *,
110 +                                     num_group_files + 1);
111 +     if (group_files == NULL) {
112 +         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
113 +         ret = ENOMEM;
114 +         goto done;
115 +     }
116 + 
117 +     for (i = 0; i < num_group_files; i++) {
118 +         DEBUG(SSSDBG_TRACE_FUNC,
119 +               "Using group file: [%s].\n", group_list[i]);
120 +         group_files[i] = talloc_strdup(group_files, group_list[i]);
121 +         if (group_files[i] == NULL) {
122 +             ret = ENOMEM;
123 +             goto done;
124 +         }
125 +     }
126 + 
127 +     *_passwd_files = talloc_steal(mem_ctx, passwd_files);
128 +     *_group_files = talloc_steal(mem_ctx, group_files);
129 + 
130 +     ret = EOK;
131 + 
132 + done:
133 +     talloc_free(tmp_ctx);
134 +     return ret;
135 + }
136 + 
137   int sssm_files_init(TALLOC_CTX *mem_ctx,
138                       struct be_ctx *be_ctx,
139                       struct data_provider *provider,
140 @@ -30,32 +162,27 @@
141                       void **_module_data)
142   {
143       struct files_id_ctx *ctx;
144 -     int ret;
145 -     const char *passwd_file = NULL;
146 -     const char *group_file = NULL;
147 - 
148 -     /* So far this is mostly useful for tests */
149 -     passwd_file = getenv("SSS_FILES_PASSWD");
150 -     if (passwd_file == NULL) {
151 -         passwd_file = "/etc/passwd";
152 -     }
153 - 
154 -     group_file = getenv("SSS_FILES_GROUP");
155 -     if (group_file == NULL) {
156 -         group_file = "/etc/group";
157 -     }
158 +     errno_t ret;
159   
160       ctx = talloc_zero(mem_ctx, struct files_id_ctx);
161       if (ctx == NULL) {
162           return ENOMEM;
163       }
164 + 
165       ctx->be = be_ctx;
166       ctx->domain = be_ctx->domain;
167 -     ctx->passwd_file = passwd_file;
168 -     ctx->group_file = group_file;
169 + 
170 +     ret = files_init_file_sources(ctx, be_ctx,
171 +                                   &ctx->passwd_files,
172 +                                   &ctx->group_files);
173 +     if (ret != EOK) {
174 +         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize the passwd/group source files\n");
175 +         goto done;
176 +     }
177   
178       ctx->fctx = sf_init(ctx, be_ctx->ev,
179 -                         ctx->passwd_file, ctx->group_file,
180 +                         ctx->passwd_files,
181 +                         ctx->group_files,
182                           ctx);
183       if (ctx->fctx == NULL) {
184           ret = ENOMEM;
  1 @@ -44,6 +44,7 @@
  2   
  3   static errno_t enum_files_users(TALLOC_CTX *mem_ctx,
  4                                   struct files_id_ctx *id_ctx,
  5 +                                 const char *passwd_file,
  6                                   struct passwd ***_users)
  7   {
  8       errno_t ret, close_ret;
  9 @@ -53,12 +54,12 @@
 10       FILE *pwd_handle = NULL;
 11       size_t n_users = 0;
 12   
 13 -     pwd_handle = fopen(id_ctx->passwd_file, "r");
 14 +     pwd_handle = fopen(passwd_file, "r");
 15       if (pwd_handle == NULL) {
 16           ret = errno;
 17           DEBUG(SSSDBG_CRIT_FAILURE,
 18                 "Cannot open passwd file %s [%d]\n",
 19 -               id_ctx->passwd_file, ret);
 20 +               passwd_file, ret);
 21           goto done;
 22       }
 23   
 24 @@ -133,7 +134,7 @@
 25               close_ret = errno;
 26               DEBUG(SSSDBG_CRIT_FAILURE,
 27                     "Cannot close passwd file %s [%d]\n",
 28 -                   id_ctx->passwd_file, close_ret);
 29 +                   passwd_file, close_ret);
 30           }
 31       }
 32       return ret;
 33 @@ -141,6 +142,7 @@
 34   
 35   static errno_t enum_files_groups(TALLOC_CTX *mem_ctx,
 36                                    struct files_id_ctx *id_ctx,
 37 +                                  const char *group_file,
 38                                    struct group ***_groups)
 39   {
 40       errno_t ret, close_ret;
 41 @@ -150,12 +152,12 @@
 42       size_t n_groups = 0;
 43       FILE *grp_handle = NULL;
 44   
 45 -     grp_handle = fopen(id_ctx->group_file, "r");
 46 +     grp_handle = fopen(group_file, "r");
 47       if (grp_handle == NULL) {
 48           ret = errno;
 49           DEBUG(SSSDBG_CRIT_FAILURE,
 50                 "Cannot open group file %s [%d]\n",
 51 -               id_ctx->group_file, ret);
 52 +               group_file, ret);
 53           goto done;
 54       }
 55   
 56 @@ -237,7 +239,7 @@
 57               close_ret = errno;
 58               DEBUG(SSSDBG_CRIT_FAILURE,
 59                     "Cannot close group file %s [%d]\n",
 60 -                   id_ctx->group_file, close_ret);
 61 +                   group_file, close_ret);
 62           }
 63       }
 64       return ret;
 65 @@ -446,35 +448,23 @@
 66       return ret;
 67   }
 68   
 69 - static errno_t sf_enum_groups(struct files_id_ctx *id_ctx);
 70 + static errno_t sf_enum_groups(struct files_id_ctx *id_ctx,
 71 +                               const char *group_file);
 72   
 73 - errno_t sf_enum_users(struct files_id_ctx *id_ctx)
 74 + errno_t sf_enum_users(struct files_id_ctx *id_ctx,
 75 +                       const char *passwd_file)
 76   {
 77       errno_t ret;
 78 -     errno_t tret;
 79       TALLOC_CTX *tmp_ctx = NULL;
 80       struct passwd **users = NULL;
 81 -     bool in_transaction = false;
 82   
 83       tmp_ctx = talloc_new(NULL);
 84       if (tmp_ctx == NULL) {
 85           return ENOMEM;
 86       }
 87   
 88 -     ret = enum_files_users(tmp_ctx, id_ctx, &users);
 89 -     if (ret != EOK) {
 90 -         goto done;
 91 -     }
 92 - 
 93 -     ret = sysdb_transaction_start(id_ctx->domain->sysdb);
 94 -     if (ret != EOK) {
 95 -         goto done;
 96 -     }
 97 -     in_transaction = true;
 98 - 
 99 -     /* remove previous cache contents */
100 -     /* FIXME - this is terribly inefficient */
101 -     ret = delete_all_users(id_ctx->domain);
102 +     ret = enum_files_users(tmp_ctx, id_ctx, passwd_file,
103 +                            &users);
104       if (ret != EOK) {
105           goto done;
106       }
107 @@ -496,31 +486,8 @@
108                 "override values might not be available.\n");
109       }
110   
111 -     ret = sysdb_transaction_commit(id_ctx->domain->sysdb);
112 -     if (ret != EOK) {
113 -         goto done;
114 -     }
115 -     in_transaction = false;
116 - 
117 -     /* Covers the case when someone edits /etc/group, adds a group member and
118 -      * only then edits passwd and adds the user. The reverse is not needed,
119 -      * because member/memberof links are established when groups are saved.
120 -      */
121 -     ret = sf_enum_groups(id_ctx);
122 -     if (ret != EOK) {
123 -         DEBUG(SSSDBG_OP_FAILURE, "Cannot refresh groups\n");
124 -         goto done;
125 -     }
126 - 
127       ret = EOK;
128   done:
129 -     if (in_transaction) {
130 -         tret = sysdb_transaction_cancel(id_ctx->domain->sysdb);
131 -         if (tret != EOK) {
132 -             DEBUG(SSSDBG_CRIT_FAILURE,
133 -                   "Cannot cancel transaction: %d\n", ret);
134 -         }
135 -     }
136       talloc_free(tmp_ctx);
137       return ret;
138   }
139 @@ -698,13 +665,12 @@
140       return ret;
141   }
142   
143 - static errno_t sf_enum_groups(struct files_id_ctx *id_ctx)
144 + static errno_t sf_enum_groups(struct files_id_ctx *id_ctx,
145 +                               const char *group_file)
146   {
147       errno_t ret;
148 -     errno_t tret;
149       TALLOC_CTX *tmp_ctx = NULL;
150       struct group **groups = NULL;
151 -     bool in_transaction = false;
152       const char **cached_users = NULL;
153   
154       tmp_ctx = talloc_new(NULL);
155 @@ -712,7 +678,8 @@
156           return ENOMEM;
157       }
158   
159 -     ret = enum_files_groups(tmp_ctx, id_ctx, &groups);
160 +     ret = enum_files_groups(tmp_ctx, id_ctx, group_file,
161 +                             &groups);
162       if (ret != EOK) {
163           goto done;
164       }
165 @@ -722,18 +689,6 @@
166           goto done;
167       }
168   
169 -     ret = sysdb_transaction_start(id_ctx->domain->sysdb);
170 -     if (ret != EOK) {
171 -         goto done;
172 -     }
173 -     in_transaction = true;
174 - 
175 -     /* remove previous cache contents */
176 -     ret = delete_all_groups(id_ctx->domain);
177 -     if (ret != EOK) {
178 -         goto done;
179 -     }
180 - 
181       for (size_t i = 0; groups[i]; i++) {
182           ret = save_file_group(id_ctx, groups[i], cached_users);
183           if (ret != EOK) {
184 @@ -750,21 +705,8 @@
185                 "override values might not be available.\n");
186       }
187   
188 -     ret = sysdb_transaction_commit(id_ctx->domain->sysdb);
189 -     if (ret != EOK) {
190 -         goto done;
191 -     }
192 -     in_transaction = false;
193 - 
194       ret = EOK;
195   done:
196 -     if (in_transaction) {
197 -         tret = sysdb_transaction_cancel(id_ctx->domain->sysdb);
198 -         if (tret != EOK) {
199 -             DEBUG(SSSDBG_CRIT_FAILURE,
200 -                   "Cannot cancel transaction: %d\n", ret);
201 -         }
202 -     }
203       talloc_free(tmp_ctx);
204       return ret;
205   }
206 @@ -783,21 +725,17 @@
207   {
208       struct files_id_ctx *id_ctx;
209       errno_t ret;
210 +     errno_t tret;
211 +     bool in_transaction = false;
212   
213       id_ctx = talloc_get_type(pvt, struct files_id_ctx);
214       if (id_ctx == NULL) {
215 -         return EINVAL;
216 +         ret = EINVAL;
217 +         goto done;
218       }
219   
220       DEBUG(SSSDBG_TRACE_FUNC, "passwd notification\n");
221   
222 -     if (strcmp(filename, id_ctx->passwd_file) != 0) {
223 -         DEBUG(SSSDBG_CRIT_FAILURE,
224 -               "Wrong file, expected %s, got %s\n",
225 -               id_ctx->passwd_file, filename);
226 -         return EINVAL;
227 -     }
228 - 
229       id_ctx->updating_passwd = true;
230       dp_sbus_domain_inconsistent(id_ctx->be->provider, id_ctx->domain);
231   
232 @@ -805,11 +743,64 @@
233       dp_sbus_reset_users_memcache(id_ctx->be->provider);
234       dp_sbus_reset_initgr_memcache(id_ctx->be->provider);
235   
236 -     ret = sf_enum_users(id_ctx);
237 +     ret = sysdb_transaction_start(id_ctx->domain->sysdb);
238 +     if (ret != EOK) {
239 +         goto done;
240 +     }
241 +     in_transaction = true;
242 + 
243 +     ret = delete_all_users(id_ctx->domain);
244 +     if (ret != EOK) {
245 +         goto done;
246 +     }
247 + 
248 +     /* All users were deleted, therefore we need to enumerate each file again */
249 +     for (size_t i = 0; id_ctx->passwd_files[i] != NULL; i++) {
250 +         ret = sf_enum_users(id_ctx, id_ctx->passwd_files[i]);
251 +         if (ret != EOK) {
252 +             DEBUG(SSSDBG_OP_FAILURE, "Cannot enumerate users\n");
253 +             goto done;
254 +         }
255 +     }
256 + 
257 +     /* Covers the case when someone edits /etc/group, adds a group member and
258 +      * only then edits passwd and adds the user. The reverse is not needed,
259 +      * because member/memberof links are established when groups are saved.
260 +      */
261 +     ret = delete_all_groups(id_ctx->domain);
262 +     if (ret != EOK) {
263 +         goto done;
264 +     }
265 + 
266 +     /* All groups were deleted, therefore we need to enumerate each file again */
267 +     for (size_t i = 0; id_ctx->group_files[i] != NULL; i++) {
268 +         ret = sf_enum_groups(id_ctx, id_ctx->group_files[i]);
269 +         if (ret != EOK) {
270 +             DEBUG(SSSDBG_OP_FAILURE, "Cannot enumerate groups\n");
271 +             goto done;
272 +         }
273 +     }
274 + 
275 +     ret = sysdb_transaction_commit(id_ctx->domain->sysdb);
276 +     if (ret != EOK) {
277 +         goto done;
278 +     }
279 +     in_transaction = false;
280   
281       id_ctx->updating_passwd = false;
282       sf_cb_done(id_ctx);
283       files_account_info_finished(id_ctx, BE_REQ_USER, ret);
284 + 
285 +     ret = EOK;
286 + done:
287 +     if (in_transaction) {
288 +         tret = sysdb_transaction_cancel(id_ctx->domain->sysdb);
289 +         if (tret != EOK) {
290 +             DEBUG(SSSDBG_CRIT_FAILURE,
291 +                   "Cannot cancel transaction: %d\n", ret);
292 +         }
293 +     }
294 + 
295       return ret;
296   }
297   
298 @@ -817,21 +808,17 @@
299   {
300       struct files_id_ctx *id_ctx;
301       errno_t ret;
302 +     errno_t tret;
303 +     bool in_transaction = false;
304   
305       id_ctx = talloc_get_type(pvt, struct files_id_ctx);
306       if (id_ctx == NULL) {
307 -         return EINVAL;
308 +         ret = EINVAL;
309 +         goto done;
310       }
311   
312       DEBUG(SSSDBG_TRACE_FUNC, "group notification\n");
313   
314 -     if (strcmp(filename, id_ctx->group_file) != 0) {
315 -         DEBUG(SSSDBG_CRIT_FAILURE,
316 -               "Wrong file, expected %s, got %s\n",
317 -               id_ctx->group_file, filename);
318 -         return EINVAL;
319 -     }
320 - 
321       id_ctx->updating_groups = true;
322       dp_sbus_domain_inconsistent(id_ctx->be->provider, id_ctx->domain);
323   
324 @@ -839,11 +826,47 @@
325       dp_sbus_reset_groups_memcache(id_ctx->be->provider);
326       dp_sbus_reset_initgr_memcache(id_ctx->be->provider);
327   
328 -     ret = sf_enum_groups(id_ctx);
329 +     ret = sysdb_transaction_start(id_ctx->domain->sysdb);
330 +     if (ret != EOK) {
331 +         goto done;
332 +     }
333 +     in_transaction = true;
334 + 
335 +     ret = delete_all_groups(id_ctx->domain);
336 +     if (ret != EOK) {
337 +         goto done;
338 +     }
339 + 
340 +     /* All groups were deleted, therefore we need to enumerate each file again */
341 +     for (size_t i = 0; id_ctx->group_files[i] != NULL; i++) {
342 +         ret = sf_enum_groups(id_ctx, id_ctx->group_files[i]);
343 +         if (ret != EOK) {
344 +             DEBUG(SSSDBG_OP_FAILURE, "Cannot enumerate groups\n");
345 +             goto done;
346 +         }
347 +     }
348 + 
349 +     ret = sysdb_transaction_commit(id_ctx->domain->sysdb);
350 +     if (ret != EOK) {
351 +         goto done;
352 +     }
353 +     in_transaction = false;
354   
355       id_ctx->updating_groups = false;
356       sf_cb_done(id_ctx);
357       files_account_info_finished(id_ctx, BE_REQ_GROUP, ret);
358 + 
359 +     ret = EOK;
360 + 
361 + done:
362 +     if (in_transaction) {
363 +         tret = sysdb_transaction_cancel(id_ctx->domain->sysdb);
364 +         if (tret != EOK) {
365 +             DEBUG(SSSDBG_CRIT_FAILURE,
366 +                   "Cannot cancel transaction: %d\n", ret);
367 +         }
368 +     }
369 + 
370       return ret;
371   }
372   
373 @@ -853,19 +876,62 @@
374   {
375       struct files_id_ctx *id_ctx = talloc_get_type(pvt, struct files_id_ctx);
376       errno_t ret;
377 +     errno_t tret;
378 +     bool in_transaction = false;
379   
380       talloc_zfree(imm);
381   
382 -     ret = sf_enum_users(id_ctx);
383 +     ret = sysdb_transaction_start(id_ctx->domain->sysdb);
384       if (ret != EOK) {
385 -         DEBUG(SSSDBG_CRIT_FAILURE,
386 -               "Enumerating users failed, data might be inconsistent!\n");
387 +         goto done;
388       }
389 +     in_transaction = true;
390   
391 -     ret = sf_enum_groups(id_ctx);
392 +     ret = delete_all_users(id_ctx->domain);
393       if (ret != EOK) {
394 -         DEBUG(SSSDBG_CRIT_FAILURE,
395 -               "Enumerating groups failed, data might be inconsistent!\n");
396 +         goto done;
397 +     }
398 + 
399 +     ret = delete_all_groups(id_ctx->domain);
400 +     if (ret != EOK) {
401 +         goto done;
402 +     }
403 + 
404 +     for (size_t i = 0; id_ctx->passwd_files[i] != NULL; i++) {
405 +         DEBUG(SSSDBG_TRACE_FUNC,
406 +               "Startup user enumeration of [%s]\n", id_ctx->passwd_files[i]);
407 +         ret = sf_enum_users(id_ctx, id_ctx->passwd_files[i]);
408 +         if (ret != EOK) {
409 +             DEBUG(SSSDBG_CRIT_FAILURE,
410 +                   "Enumerating users failed, data might be inconsistent!\n");
411 +             goto done;
412 +         }
413 +     }
414 + 
415 +     for (size_t i = 0; id_ctx->group_files[i] != NULL; i++) {
416 +         DEBUG(SSSDBG_TRACE_FUNC,
417 +               "Startup group enumeration of [%s]\n", id_ctx->group_files[i]);
418 +         ret = sf_enum_groups(id_ctx, id_ctx->group_files[i]);
419 +         if (ret != EOK) {
420 +             DEBUG(SSSDBG_CRIT_FAILURE,
421 +                   "Enumerating groups failed, data might be inconsistent!\n");
422 +             goto done;
423 +         }
424 +     }
425 + 
426 +     ret = sysdb_transaction_commit(id_ctx->domain->sysdb);
427 +     if (ret != EOK) {
428 +         goto done;
429 +     }
430 +     in_transaction = false;
431 + 
432 + done:
433 +     if (in_transaction) {
434 +         tret = sysdb_transaction_cancel(id_ctx->domain->sysdb);
435 +         if (tret != EOK) {
436 +             DEBUG(SSSDBG_CRIT_FAILURE,
437 +                   "Cannot cancel transaction: %d\n", ret);
438 +         }
439       }
440   }
441   
442 @@ -884,22 +950,29 @@
443   
444   struct files_ctx *sf_init(TALLOC_CTX *mem_ctx,
445                             struct tevent_context *ev,
446 -                           const char *passwd_file,
447 -                           const char *group_file,
448 +                           const char **passwd_files,
449 +                           const char **group_files,
450                             struct files_id_ctx *id_ctx)
451   {
452       struct files_ctx *fctx;
453       struct tevent_immediate *imm;
454 +     int i;
455   
456       fctx = talloc(mem_ctx, struct files_ctx);
457       if (fctx == NULL) {
458           return NULL;
459       }
460   
461 -     fctx->pwd_watch = sf_setup_watch(fctx, ev, passwd_file,
462 -                                      sf_passwd_cb, id_ctx);
463 -     fctx->grp_watch = sf_setup_watch(fctx, ev, group_file,
464 -                                      sf_group_cb, id_ctx);
465 +     for (i = 0; passwd_files[i]; i++) {
466 +         fctx->pwd_watch = sf_setup_watch(fctx, ev, passwd_files[i],
467 +                                          sf_passwd_cb, id_ctx);
468 +         }
469 + 
470 +     for (i = 0; group_files[i]; i++) {
471 +         fctx->grp_watch = sf_setup_watch(fctx, ev, group_files[i],
472 +                                          sf_group_cb, id_ctx);
473 +     }
474 + 
475       if (fctx->pwd_watch == NULL || fctx->grp_watch == NULL) {
476           talloc_free(fctx);
477           return NULL;
 1 @@ -39,8 +39,8 @@
 2       struct sss_domain_info *domain;
 3       struct files_ctx *fctx;
 4   
 5 -     const char *passwd_file;
 6 -     const char *group_file;
 7 +     const char **passwd_files;
 8 +     const char **group_files;
 9   
10       bool updating_passwd;
11       bool updating_groups;
12 @@ -53,8 +53,8 @@
13   /* files_ops.c */
14   struct files_ctx *sf_init(TALLOC_CTX *mem_ctx,
15                             struct tevent_context *ev,
16 -                           const char *passwd_file,
17 -                           const char *group_file,
18 +                           const char **passwd_files,
19 +                           const char **group_files,
20                             struct files_id_ctx *id_ctx);
21   
22   /* files_id.c */