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

Collapse All | Expand All

(-)b/bin/setfacl/setfacl.1 (+3 lines)
Lines 115-120 the input is taken from stdin. Link Here
115
.It Fl n
115
.It Fl n
116
Do not recalculate the permissions associated with the ACL
116
Do not recalculate the permissions associated with the ACL
117
mask entry.  This option is not applicable to NFSv4 ACLs.
117
mask entry.  This option is not applicable to NFSv4 ACLs.
118
.It Fl R
119
Recurse the specified directories. NFSv4 inheritance flags that
120
are meant for directories are removed for files.
118
.It Fl x Ar entries | position
121
.It Fl x Ar entries | position
119
If
122
If
120
.Ar entries
123
.Ar entries
(-)b/bin/setfacl/setfacl.c (-157 / +233 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-98 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
	if (acl_new == (acl_t)NULL)
115
		return ((acl_t)NULL);
116
117
	entry_id = ACL_FIRST_ENTRY;
118
	while (acl_get_entry(acl_new, entry_id, &acl_entry) == 1) {
119
		entry_id = ACL_NEXT_ENTRY;
120
		acl_get_flagset_np(acl_entry, &acl_flagset);
121
		if (acl_get_flag_np(acl_flagset, ACL_ENTRY_INHERIT_ONLY)) {
122
			acl_delete_entry(acl_new, acl_entry);
123
			continue;
124
		}
125
		acl_delete_flag_np(acl_flagset, ACL_ENTRY_FILE_INHERIT
126
		    | ACL_ENTRY_DIRECTORY_INHERIT
127
		    | ACL_ENTRY_NO_PROPAGATE_INHERIT);
128
	}
129
130
	return acl_new;
131
}
132
133
static int
134
walk_path(const char *path, const struct stat *sb, int flag, struct FTW *ftwp __unused)
135
{
136
	acl_t acl, acl_backup=NULL;
137
	acl_entry_t unused_entry;
138
	struct sf_entry *entry;
139
	unsigned int local_error;
140
	int ret;
141
142
	local_error = 0;
143
144
	if (acl_type == ACL_TYPE_DEFAULT && (flag & FTW_D) == 0) {
145
		warnx("%s: default ACL may only be set on a directory",
146
			path);
147
		carried_error++;
148
		return (R_flag == 0);
149
	}
150
151
	if (h_flag)
152
		ret = lpathconf(path, _PC_ACL_NFS4);
153
	else
154
		ret = pathconf(path, _PC_ACL_NFS4);
155
	if (ret > 0) {
156
		if (acl_type == ACL_TYPE_DEFAULT) {
157
			warnx("%s: there are no default entries "
158
				"in NFSv4 ACLs", path);
159
			carried_error++;
160
			return (R_flag == 0);
161
		}
162
		acl_type = ACL_TYPE_NFS4;
163
	} else if (ret == 0) {
164
		if (acl_type == ACL_TYPE_NFS4)
165
			acl_type = ACL_TYPE_ACCESS;
166
	} else if (ret < 0 && errno != EINVAL) {
167
		warn("%s: pathconf(..., _PC_ACL_NFS4) failed",
168
			path);
169
	}
170
171
	if (h_flag)
172
		acl = acl_get_link_np(path, acl_type);
173
	else
174
		acl = acl_get_file(path, acl_type);
175
	if (acl == NULL) {
176
		if (h_flag)
177
			warn("%s: acl_get_link_np() failed",
178
				path);
179
		else
180
			warn("%s: acl_get_file() failed",
181
				path);
182
		carried_error++;
183
		return (R_flag == 0);
184
	}
185
186
	/* cycle through each option */
187
	TAILQ_FOREACH(entry, &entrylist, next) {
188
		if (local_error)
189
			continue;
190
191
		switch(entry->op) {
192
		case OP_ADD_ACL:
193
			if (R_flag && acl_type == ACL_TYPE_NFS4
194
			    && (flag & FTW_D) == 0) {
195
				acl_backup = acl_dup(entry->acl);
196
				entry->acl = sanitize_inheritance(sb, entry->acl);
197
				if (entry->acl == (acl_t)NULL) {
198
					local_error++;
199
					break;
200
				}
201
			}
202
			local_error += add_acl(entry->acl,
203
				entry->entry_number, &acl, path);
204
			if (R_flag && acl_type == ACL_TYPE_NFS4
205
			    && (flag & FTW_D) == 0) {
206
				acl_free(entry->acl);
207
				entry->acl = acl_backup;
208
			}
209
			break;
210
		case OP_MERGE_ACL:
211
			if (R_flag && acl_type == ACL_TYPE_NFS4
212
			    && (flag & FTW_D) == 0) {
213
				acl_backup = acl_dup(entry->acl);
214
				entry->acl = sanitize_inheritance(sb, entry->acl);
215
			}
216
			local_error += merge_acl(entry->acl, &acl,
217
				path);
218
			if (R_flag && acl_type == ACL_TYPE_NFS4
219
			    && (flag & FTW_D) == 0) {
220
				acl_free(entry->acl);
221
				entry->acl = acl_backup;
222
			}
223
			need_mask = 1;
224
			break;
225
		case OP_REMOVE_EXT:
226
			/*
227
				* Don't try to call remove_ext() for empty
228
				* default ACL.
229
				*/
230
			if (acl_type == ACL_TYPE_DEFAULT &&
231
				acl_get_entry(acl, ACL_FIRST_ENTRY,
232
				&unused_entry) == 0) {
233
				local_error += remove_default(&acl,
234
					path);
235
				break;
236
			}
237
			remove_ext(&acl, path);
238
			need_mask = 0;
239
			break;
240
		case OP_REMOVE_DEF:
241
			if (acl_type == ACL_TYPE_NFS4) {
242
				warnx("%s: there are no default entries in NFSv4 ACLs; "
243
					"cannot remove", path);
244
				local_error++;
245
				break;
246
			}
247
			if (acl_delete_def_file(path) == -1) {
248
				warn("%s: acl_delete_def_file() failed",
249
					path);
250
				local_error++;
251
			}
252
			if (acl_type == ACL_TYPE_DEFAULT)
253
				local_error += remove_default(&acl,
254
					path);
255
			need_mask = 0;
256
			break;
257
		case OP_REMOVE_ACL:
258
			local_error += remove_acl(entry->acl, &acl,
259
				path);
260
			need_mask = 1;
261
			break;
262
		case OP_REMOVE_BY_NUMBER:
263
			local_error += remove_by_number(entry->entry_number,
264
				&acl, path);
265
			need_mask = 1;
266
			break;
267
		}
268
	}
269
270
	/*
271
	* Don't try to set an empty default ACL; it will always fail.
272
	* Use acl_delete_def_file(3) instead.
273
	*/
274
	if (acl_type == ACL_TYPE_DEFAULT &&
275
		acl_get_entry(acl, ACL_FIRST_ENTRY, &unused_entry) == 0) {
276
		if (acl_delete_def_file(path) == -1) {
277
			warn("%s: acl_delete_def_file() failed",
278
				path);
279
			carried_error++;
280
		}
281
		return (R_flag == 0);
282
	}
283
284
	/* don't bother setting the ACL if something is broken */
285
	if (local_error) {
286
		carried_error++;
287
		return (R_flag == 0);
288
	}
289
290
	if (acl_type != ACL_TYPE_NFS4 && need_mask &&
291
		set_acl_mask(&acl, path) == -1) {
292
		warnx("%s: failed to set ACL mask", path);
293
		carried_error++;
294
	} else if (h_flag) {
295
		if (acl_set_link_np(path, acl_type,
296
			acl) == -1) {
297
			carried_error++;
298
			warn("%s: acl_set_link_np() failed",
299
				path);
300
		}
301
	} else {
302
		if (acl_set_file(path, acl_type,
303
			acl) == -1) {
304
			carried_error++;
305
			warn("%s: acl_set_file() failed",
306
				path);
307
		}
308
	}
309
310
	acl_free(acl);
311
	return (R_flag == 0);
312
}
313
91
static void
314
static void
92
usage(void)
315
usage(void)
93
{
316
{
94
317
95
	fprintf(stderr, "usage: setfacl [-bdhkn] [-a position entries] "
318
	fprintf(stderr, "usage: setfacl [-bdhknR] [-a position entries] "
96
	    "[-m entries] [-M file] [-x entries] [-X file] [file ...]\n");
319
	    "[-m entries] [-M file] [-x entries] [-X file] [file ...]\n");
97
	exit(1);
320
	exit(1);
98
}
321
}
Lines 100-125 usage(void) Link Here
100
int
323
int
101
main(int argc, char *argv[])
324
main(int argc, char *argv[])
102
{
325
{
103
	acl_t acl;
104
	acl_type_t acl_type;
105
	acl_entry_t unused_entry;
106
	char filename[PATH_MAX];
326
	char filename[PATH_MAX];
107
	int local_error, carried_error, ch, i, entry_number, ret;
327
	int ch, i, entry_number;
108
	int h_flag;
109
	struct sf_file *file;
328
	struct sf_file *file;
110
	struct sf_entry *entry;
329
	struct sf_entry *entry;
111
	const char *fn_dup;
330
	const char *fn_dup;
112
	char *end;
331
	char *end;
113
	struct stat sb;
114
332
115
	acl_type = ACL_TYPE_ACCESS;
333
	acl_type = ACL_TYPE_ACCESS;
116
	carried_error = local_error = 0;
334
	carried_error = 0;
117
	h_flag = have_mask = have_stdin = n_flag = need_mask = 0;
335
	h_flag = have_mask = have_stdin = n_flag = need_mask = 0;
336
	R_flag = 0;
118
337
119
	TAILQ_INIT(&entrylist);
338
	TAILQ_INIT(&entrylist);
120
	TAILQ_INIT(&filelist);
339
	TAILQ_INIT(&filelist);
121
340
122
	while ((ch = getopt(argc, argv, "M:X:a:bdhkm:nx:")) != -1)
341
	while ((ch = getopt(argc, argv, "M:RX:a:bdhkm:nx:")) != -1)
123
		switch(ch) {
342
		switch(ch) {
124
		case 'M':
343
		case 'M':
125
			entry = zmalloc(sizeof(struct sf_entry));
344
			entry = zmalloc(sizeof(struct sf_entry));
Lines 129-134 main(int argc, char *argv[]) Link Here
129
			entry->op = OP_MERGE_ACL;
348
			entry->op = OP_MERGE_ACL;
130
			TAILQ_INSERT_TAIL(&entrylist, entry, next);
349
			TAILQ_INSERT_TAIL(&entrylist, entry, next);
131
			break;
350
			break;
351
		case 'R':
352
			R_flag = 1;
353
			break;
132
		case 'X':
354
		case 'X':
133
			entry = zmalloc(sizeof(struct sf_entry));
355
			entry = zmalloc(sizeof(struct sf_entry));
134
			entry->acl = get_acl_from_file(optarg);
356
			entry->acl = get_acl_from_file(optarg);
Lines 227-383 main(int argc, char *argv[]) Link Here
227
449
228
	/* cycle through each file */
450
	/* cycle through each file */
229
	TAILQ_FOREACH(file, &filelist, next) {
451
	TAILQ_FOREACH(file, &filelist, next) {
230
		local_error = 0;
452
		if (nftw(file->filename, walk_path, 5, h_flag ? FTW_PHYS : 0) < 0) {
231
453
			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++;
454
			carried_error++;
277
			continue;
455
			continue;
278
		}
456
		}
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
	}
457
	}
382
458
383
	return (carried_error);
459
	return (carried_error);

Return to bug 155163