View | Details | Raw Unified | Return to bug 155163 | Differences between
and this patch

Collapse All | Expand All

(-)b/bin/setfacl/setfacl.c (-156 / +226 lines)
Lines 39-44 __FBSDID("$FreeBSD$"); Link Here
39
#include <stdlib.h>
39
#include <stdlib.h>
40
#include <string.h>
40
#include <string.h>
41
#include <unistd.h>
41
#include <unistd.h>
42
#include <ftw.h>
42
43
43
#include "setfacl.h"
44
#include "setfacl.h"
44
45
Lines 70-77 uint have_mask; Link Here
70
uint need_mask;
71
uint need_mask;
71
uint have_stdin;
72
uint have_stdin;
72
uint n_flag;
73
uint n_flag;
74
static int h_flag;
75
static int R_flag;
76
static unsigned int carried_error;
77
static acl_type_t acl_type;
73
78
74
static void	add_filename(const char *filename);
79
static void	add_filename(const char *filename);
80
static acl_t	sanitize_inheritance(const struct stat *sb, acl_t acl);
81
static int	walk_path(const char *path, const struct stat *sb, int flag, struct FTW *ftwp);
75
static void	usage(void);
82
static void	usage(void);
76
83
77
static void
84
static void
Lines 88-93 add_filename(const char *filename) Link Here
88
	TAILQ_INSERT_TAIL(&filelist, file, next);
95
	TAILQ_INSERT_TAIL(&filelist, file, next);
89
}
96
}
90
97
98
static acl_t
99
sanitize_inheritance(const struct stat *sb, acl_t acl)
100
{
101
	acl_t acl_new;
102
	acl_entry_t acl_entry;
103
	acl_flagset_t acl_flagset;
104
	int acl_brand, entry_id;
105
106
	acl_get_brand_np(acl, &acl_brand);
107
	if (acl_brand != ACL_BRAND_NFS4)
108
		return (acl);
109
110
	if (S_ISDIR(sb->st_mode) != 0)
111
		return (acl);
112
113
	acl_new = acl_dup(acl);
114
115
	entry_id = ACL_FIRST_ENTRY;
116
	while (acl_get_entry(acl_new, entry_id, &acl_entry) == 1) {
117
		entry_id = ACL_NEXT_ENTRY;
118
		acl_get_flagset_np(acl_entry, &acl_flagset);
119
		if (acl_get_flag_np(acl_flagset, ACL_ENTRY_INHERIT_ONLY)) {
120
			acl_delete_entry(acl_new, acl_entry);
121
			continue;
122
		}
123
		acl_delete_flag_np(acl_flagset, ACL_ENTRY_FILE_INHERIT
124
		    | ACL_ENTRY_DIRECTORY_INHERIT
125
		    | ACL_ENTRY_NO_PROPAGATE_INHERIT);
126
	}
127
128
	return acl_new;
129
}
130
131
static int
132
walk_path(const char *path, const struct stat *sb, int flag, struct FTW *ftwp __unused)
133
{
134
	acl_t acl, acl_backup;
135
	acl_entry_t unused_entry;
136
	struct sf_entry *entry;
137
	unsigned int local_error;
138
	int ret;
139
140
	local_error = 0;
141
142
	if (acl_type == ACL_TYPE_DEFAULT && (flag & FTW_D) == 0) {
143
		warnx("%s: default ACL may only be set on a directory",
144
			path);
145
		carried_error++;
146
		return (R_flag == 0);
147
	}
148
149
	if (h_flag)
150
		ret = lpathconf(path, _PC_ACL_NFS4);
151
	else
152
		ret = pathconf(path, _PC_ACL_NFS4);
153
	if (ret > 0) {
154
		if (acl_type == ACL_TYPE_DEFAULT) {
155
			warnx("%s: there are no default entries "
156
				"in NFSv4 ACLs", path);
157
			carried_error++;
158
			return (R_flag == 0);
159
		}
160
		acl_type = ACL_TYPE_NFS4;
161
	} else if (ret == 0) {
162
		if (acl_type == ACL_TYPE_NFS4)
163
			acl_type = ACL_TYPE_ACCESS;
164
	} else if (ret < 0 && errno != EINVAL) {
165
		warn("%s: pathconf(..., _PC_ACL_NFS4) failed",
166
			path);
167
	}
168
169
	if (h_flag)
170
		acl = acl_get_link_np(path, acl_type);
171
	else
172
		acl = acl_get_file(path, acl_type);
173
	if (acl == NULL) {
174
		if (h_flag)
175
			warn("%s: acl_get_link_np() failed",
176
				path);
177
		else
178
			warn("%s: acl_get_file() failed",
179
				path);
180
		carried_error++;
181
		return (R_flag == 0);
182
	}
183
184
	/* cycle through each option */
185
	TAILQ_FOREACH(entry, &entrylist, next) {
186
		if (local_error)
187
			continue;
188
189
		switch(entry->op) {
190
		case OP_ADD_ACL:
191
			if (R_flag && acl_type == ACL_TYPE_NFS4
192
			    && (flag & FTW_D) == 0) {
193
				acl_backup = acl_dup(entry->acl);
194
				entry->acl = sanitize_inheritance(sb, entry->acl);
195
			}
196
			local_error += add_acl(entry->acl,
197
				entry->entry_number, &acl, path);
198
			if (R_flag && acl_type == ACL_TYPE_NFS4
199
			    && (flag & FTW_D) == 0) {
200
				acl_free(entry->acl);
201
				entry->acl = acl_backup;
202
			}
203
			break;
204
		case OP_MERGE_ACL:
205
			if (R_flag && acl_type == ACL_TYPE_NFS4
206
			    && (flag & FTW_D) == 0) {
207
				acl_backup = acl_dup(entry->acl);
208
				entry->acl = sanitize_inheritance(sb, entry->acl);
209
			}
210
			local_error += merge_acl(entry->acl, &acl,
211
				path);
212
			if (R_flag && acl_type == ACL_TYPE_NFS4
213
			    && (flag & FTW_D) == 0) {
214
				acl_free(entry->acl);
215
				entry->acl = acl_backup;
216
			}
217
			need_mask = 1;
218
			break;
219
		case OP_REMOVE_EXT:
220
			/*
221
				* Don't try to call remove_ext() for empty
222
				* default ACL.
223
				*/
224
			if (acl_type == ACL_TYPE_DEFAULT &&
225
				acl_get_entry(acl, ACL_FIRST_ENTRY,
226
				&unused_entry) == 0) {
227
				local_error += remove_default(&acl,
228
					path);
229
				break;
230
			}
231
			remove_ext(&acl, path);
232
			need_mask = 0;
233
			break;
234
		case OP_REMOVE_DEF:
235
			if (acl_type == ACL_TYPE_NFS4) {
236
				warnx("%s: there are no default entries in NFSv4 ACLs; "
237
					"cannot remove", path);
238
				local_error++;
239
				break;
240
			}
241
			if (acl_delete_def_file(path) == -1) {
242
				warn("%s: acl_delete_def_file() failed",
243
					path);
244
				local_error++;
245
			}
246
			if (acl_type == ACL_TYPE_DEFAULT)
247
				local_error += remove_default(&acl,
248
					path);
249
			need_mask = 0;
250
			break;
251
		case OP_REMOVE_ACL:
252
			local_error += remove_acl(entry->acl, &acl,
253
				path);
254
			need_mask = 1;
255
			break;
256
		case OP_REMOVE_BY_NUMBER:
257
			local_error += remove_by_number(entry->entry_number,
258
				&acl, path);
259
			need_mask = 1;
260
			break;
261
		}
262
	}
263
264
	/*
265
	* Don't try to set an empty default ACL; it will always fail.
266
	* Use acl_delete_def_file(3) instead.
267
	*/
268
	if (acl_type == ACL_TYPE_DEFAULT &&
269
		acl_get_entry(acl, ACL_FIRST_ENTRY, &unused_entry) == 0) {
270
		if (acl_delete_def_file(path) == -1) {
271
			warn("%s: acl_delete_def_file() failed",
272
				path);
273
			carried_error++;
274
		}
275
		return (R_flag == 0);
276
	}
277
278
	/* don't bother setting the ACL if something is broken */
279
	if (local_error) {
280
		carried_error++;
281
		return (R_flag == 0);
282
	}
283
284
	if (acl_type != ACL_TYPE_NFS4 && need_mask &&
285
		set_acl_mask(&acl, path) == -1) {
286
		warnx("%s: failed to set ACL mask", path);
287
		carried_error++;
288
	} else if (h_flag) {
289
		if (acl_set_link_np(path, acl_type,
290
			acl) == -1) {
291
			carried_error++;
292
			warn("%s: acl_set_link_np() failed",
293
				path);
294
		}
295
	} else {
296
		if (acl_set_file(path, acl_type,
297
			acl) == -1) {
298
			carried_error++;
299
			warn("%s: acl_set_file() failed",
300
				path);
301
		}
302
	}
303
304
	acl_free(acl);
305
	return (R_flag == 0);
306
}
307
91
static void
308
static void
92
usage(void)
309
usage(void)
93
{
310
{
Lines 100-125 usage(void) Link Here
100
int
317
int
101
main(int argc, char *argv[])
318
main(int argc, char *argv[])
102
{
319
{
103
	acl_t acl;
104
	acl_type_t acl_type;
105
	acl_entry_t unused_entry;
106
	char filename[PATH_MAX];
320
	char filename[PATH_MAX];
107
	int local_error, carried_error, ch, i, entry_number, ret;
321
	int ch, i, entry_number;
108
	int h_flag;
109
	struct sf_file *file;
322
	struct sf_file *file;
110
	struct sf_entry *entry;
323
	struct sf_entry *entry;
111
	const char *fn_dup;
324
	const char *fn_dup;
112
	char *end;
325
	char *end;
113
	struct stat sb;
114
326
115
	acl_type = ACL_TYPE_ACCESS;
327
	acl_type = ACL_TYPE_ACCESS;
116
	carried_error = local_error = 0;
328
	carried_error = 0;
117
	h_flag = have_mask = have_stdin = n_flag = need_mask = 0;
329
	h_flag = have_mask = have_stdin = n_flag = need_mask = 0;
330
	R_flag = 0;
118
331
119
	TAILQ_INIT(&entrylist);
332
	TAILQ_INIT(&entrylist);
120
	TAILQ_INIT(&filelist);
333
	TAILQ_INIT(&filelist);
121
334
122
	while ((ch = getopt(argc, argv, "M:X:a:bdhkm:nx:")) != -1)
335
	while ((ch = getopt(argc, argv, "M:RX:a:bdhkm:nx:")) != -1)
123
		switch(ch) {
336
		switch(ch) {
124
		case 'M':
337
		case 'M':
125
			entry = zmalloc(sizeof(struct sf_entry));
338
			entry = zmalloc(sizeof(struct sf_entry));
Lines 129-134 main(int argc, char *argv[]) Link Here
129
			entry->op = OP_MERGE_ACL;
342
			entry->op = OP_MERGE_ACL;
130
			TAILQ_INSERT_TAIL(&entrylist, entry, next);
343
			TAILQ_INSERT_TAIL(&entrylist, entry, next);
131
			break;
344
			break;
345
		case 'R':
346
			R_flag = 1;
347
			break;
132
		case 'X':
348
		case 'X':
133
			entry = zmalloc(sizeof(struct sf_entry));
349
			entry = zmalloc(sizeof(struct sf_entry));
134
			entry->acl = get_acl_from_file(optarg);
350
			entry->acl = get_acl_from_file(optarg);
Lines 227-383 main(int argc, char *argv[]) Link Here
227
443
228
	/* cycle through each file */
444
	/* cycle through each file */
229
	TAILQ_FOREACH(file, &filelist, next) {
445
	TAILQ_FOREACH(file, &filelist, next) {
230
		local_error = 0;
446
		if (nftw(file->filename, walk_path, 5, h_flag ? FTW_PHYS : 0) < 0) {
231
447
			warn("%s: nftw() failed", file->filename);
232
		if (stat(file->filename, &sb) == -1) {
233
			warn("%s: stat() failed", file->filename);
234
			carried_error++;
235
			continue;
236
		}
237
238
		if (acl_type == ACL_TYPE_DEFAULT && S_ISDIR(sb.st_mode) == 0) {
239
			warnx("%s: default ACL may only be set on a directory",
240
			    file->filename);
241
			carried_error++;
242
			continue;
243
		}
244
245
		if (h_flag)
246
			ret = lpathconf(file->filename, _PC_ACL_NFS4);
247
		else
248
			ret = pathconf(file->filename, _PC_ACL_NFS4);
249
		if (ret > 0) {
250
			if (acl_type == ACL_TYPE_DEFAULT) {
251
				warnx("%s: there are no default entries "
252
			           "in NFSv4 ACLs", file->filename);
253
				carried_error++;
254
				continue;
255
			}
256
			acl_type = ACL_TYPE_NFS4;
257
		} else if (ret == 0) {
258
			if (acl_type == ACL_TYPE_NFS4)
259
				acl_type = ACL_TYPE_ACCESS;
260
		} else if (ret < 0 && errno != EINVAL) {
261
			warn("%s: pathconf(..., _PC_ACL_NFS4) failed",
262
			    file->filename);
263
		}
264
265
		if (h_flag)
266
			acl = acl_get_link_np(file->filename, acl_type);
267
		else
268
			acl = acl_get_file(file->filename, acl_type);
269
		if (acl == NULL) {
270
			if (h_flag)
271
				warn("%s: acl_get_link_np() failed",
272
				    file->filename);
273
			else
274
				warn("%s: acl_get_file() failed",
275
				    file->filename);
276
			carried_error++;
448
			carried_error++;
277
			continue;
449
			continue;
278
		}
450
		}
279
280
		/* cycle through each option */
281
		TAILQ_FOREACH(entry, &entrylist, next) {
282
			if (local_error)
283
				continue;
284
285
			switch(entry->op) {
286
			case OP_ADD_ACL:
287
				local_error += add_acl(entry->acl,
288
				    entry->entry_number, &acl, file->filename);
289
				break;
290
			case OP_MERGE_ACL:
291
				local_error += merge_acl(entry->acl, &acl,
292
				    file->filename);
293
				need_mask = 1;
294
				break;
295
			case OP_REMOVE_EXT:
296
				/*
297
				 * Don't try to call remove_ext() for empty
298
				 * default ACL.
299
				 */
300
				if (acl_type == ACL_TYPE_DEFAULT &&
301
				    acl_get_entry(acl, ACL_FIRST_ENTRY,
302
				    &unused_entry) == 0) {
303
					local_error += remove_default(&acl,
304
					    file->filename);
305
					break;
306
				}
307
				remove_ext(&acl, file->filename);
308
				need_mask = 0;
309
				break;
310
			case OP_REMOVE_DEF:
311
				if (acl_type == ACL_TYPE_NFS4) {
312
					warnx("%s: there are no default entries in NFSv4 ACLs; "
313
					    "cannot remove", file->filename);
314
					local_error++;
315
					break;
316
				}
317
				if (acl_delete_def_file(file->filename) == -1) {
318
					warn("%s: acl_delete_def_file() failed",
319
					    file->filename);
320
					local_error++;
321
				}
322
				if (acl_type == ACL_TYPE_DEFAULT)
323
					local_error += remove_default(&acl,
324
					    file->filename);
325
				need_mask = 0;
326
				break;
327
			case OP_REMOVE_ACL:
328
				local_error += remove_acl(entry->acl, &acl,
329
				    file->filename);
330
				need_mask = 1;
331
				break;
332
			case OP_REMOVE_BY_NUMBER:
333
				local_error += remove_by_number(entry->entry_number,
334
				    &acl, file->filename);
335
				need_mask = 1;
336
				break;
337
			}
338
		}
339
340
		/*
341
		 * Don't try to set an empty default ACL; it will always fail.
342
		 * Use acl_delete_def_file(3) instead.
343
		 */
344
		if (acl_type == ACL_TYPE_DEFAULT &&
345
		    acl_get_entry(acl, ACL_FIRST_ENTRY, &unused_entry) == 0) {
346
			if (acl_delete_def_file(file->filename) == -1) {
347
				warn("%s: acl_delete_def_file() failed",
348
				    file->filename);
349
				carried_error++;
350
			}
351
			continue;
352
		}
353
354
		/* don't bother setting the ACL if something is broken */
355
		if (local_error) {
356
			carried_error++;
357
			continue;
358
		}
359
360
		if (acl_type != ACL_TYPE_NFS4 && need_mask &&
361
		    set_acl_mask(&acl, file->filename) == -1) {
362
			warnx("%s: failed to set ACL mask", file->filename);
363
			carried_error++;
364
		} else if (h_flag) {
365
			if (acl_set_link_np(file->filename, acl_type,
366
			    acl) == -1) {
367
				carried_error++;
368
				warn("%s: acl_set_link_np() failed",
369
				    file->filename);
370
			}
371
		} else {
372
			if (acl_set_file(file->filename, acl_type,
373
			    acl) == -1) {
374
				carried_error++;
375
				warn("%s: acl_set_file() failed",
376
				    file->filename);
377
			}
378
		}
379
380
		acl_free(acl);
381
	}
451
	}
382
452
383
	return (carried_error);
453
	return (carried_error);

Return to bug 155163