(root)/
acl-2.3.1/
tools/
chacl.c
       1  /*
       2   * Copyright (c) 2001-2002 Silicon Graphics, Inc.
       3   * All Rights Reserved.
       4   *
       5   * This program is free software; you can redistribute it and/or modify it
       6   * under the terms of the GNU General Public License as published by
       7   * the Free Software Foundation, either version 2 of the License, or
       8   * (at your option) any later version.
       9   *
      10   * This program is distributed in the hope that it would be useful,
      11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13   * GNU General Public License for more details.
      14   *
      15   * You should have received a copy of the GNU General Public License
      16   * along with this program; if not, write the Free Software Foundation,
      17   * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      18   */
      19  
      20  #include "config.h"
      21  #include <stdlib.h>
      22  #include <string.h>
      23  #include <unistd.h>
      24  #include <getopt.h>
      25  #include <libgen.h>
      26  #include <stdio.h>
      27  #include <errno.h>
      28  #include <dirent.h>
      29  #include <sys/types.h>
      30  #include <sys/stat.h>
      31  #include <sys/acl.h>
      32  #include <acl/libacl.h>
      33  #include "misc.h"
      34  
      35  static int acl_delete_file (const char * path, acl_type_t type);
      36  static int list_acl(char *file);
      37  static int set_acl(acl_t acl, acl_t dacl, const char *fname);
      38  static int walk_dir(acl_t acl, acl_t dacl, const char *fname);
      39  
      40  static char *program;
      41  static int rflag;
      42  
      43  static void
      44  usage(void)
      45  {
      46  	fprintf(stderr, _("Usage:\n"));
      47  	fprintf(stderr, _("\t%s acl pathname...\n"), program);
      48  	fprintf(stderr, _("\t%s -b acl dacl pathname...\n"), program);
      49  	fprintf(stderr, _("\t%s -d dacl pathname...\n"), program);
      50  	fprintf(stderr, _("\t%s -R pathname...\n"), program);
      51  	fprintf(stderr, _("\t%s -D pathname...\n"), program);
      52  	fprintf(stderr, _("\t%s -B pathname...\n"), program);
      53  	fprintf(stderr, _("\t%s -l pathname...\t[not IRIX compatible]\n"),
      54  			program);
      55  	fprintf(stderr, _("\t%s -r pathname...\t[not IRIX compatible]\n"),
      56  			program);
      57  	exit(1);
      58  }
      59  
      60  int
      61  main(int argc, char *argv[])
      62  {
      63  	char *file;
      64  	int switch_flag = 0;            /* ensure only one switch is used */
      65  	int args_required = 2;	
      66  	int failed = 0;			/* exit status */
      67  	int c;				/* For use by getopt(3) */
      68  	int dflag = 0;			/* a Default ACL is desired */
      69  	int bflag = 0;			/* a both ACLs are desired */
      70  	int Rflag = 0;			/* set to true to remove an acl */
      71  	int Dflag = 0;			/* set to true to remove default acls */
      72  	int Bflag = 0;			/* set to true to remove both acls */
      73  	int lflag = 0;			/* set to true to list acls */
      74  	acl_t acl = NULL;		/* File ACL */
      75  	acl_t dacl = NULL;		/* Directory Default ACL */
      76  
      77  	program = basename(argv[0]);
      78  
      79  	setlocale(LC_CTYPE, "");
      80  	setlocale(LC_MESSAGES, "");
      81  	bindtextdomain(PACKAGE, LOCALEDIR);
      82  	textdomain(PACKAGE);
      83  
      84  	/* parse arguments */
      85  	while ((c = getopt(argc, argv, "bdlRDBr")) != -1) {
      86  		if (switch_flag) 
      87  			usage();
      88  		switch_flag = 1;
      89  
      90  		switch (c) {
      91  			case 'b':
      92  				bflag = 1;
      93  				args_required = 3;
      94  				break;
      95  			case 'd':
      96  				dflag = 1;
      97  				args_required = 2;
      98  				break;
      99  			case 'R':
     100  				Rflag = 1;
     101  				args_required = 1;
     102  				break;
     103  			case 'D':
     104  				Dflag = 1;
     105  				args_required = 1;
     106  				break;
     107  			case 'B':
     108  				Bflag = 1;
     109  				args_required = 1;
     110  				break;
     111  			case 'l':
     112  				lflag = 1;
     113  				args_required = 1;
     114  				break;
     115  			case 'r':
     116  				rflag = 1;
     117  				args_required = 1;
     118  				break;
     119  			default:
     120  				usage();
     121  				break;
     122  		}
     123  	}
     124  
     125  	/* if not enough arguments quit */
     126  	if ((argc - optind) < args_required)
     127  		usage();
     128  
     129          /* list the acls */
     130  	if (lflag) {
     131  		for (; optind < argc; optind++) {	
     132  			file = argv[optind];
     133  			if (!list_acl(file))
     134  				failed++;
     135  		}
     136  		return(failed);
     137  	}
     138  
     139  	/* remove the acls */
     140  	if (Rflag || Dflag || Bflag) {
     141  		for (; optind < argc; optind++) {	
     142  			file = argv[optind];
     143  			if (!Dflag &&
     144  			    (acl_delete_file(file, ACL_TYPE_ACCESS) == -1)) {
     145  				fprintf(stderr, _(
     146  			"%s: error removing access acl on \"%s\": %s\n"),
     147  					program, file, strerror(errno));
     148  				failed++;
     149  			}
     150  			if (!Rflag &&
     151  			    (acl_delete_file(file, ACL_TYPE_DEFAULT) == -1)) {
     152  				fprintf(stderr, _(
     153  			"%s: error removing default acl on \"%s\": %s\n"),
     154  					program, file, strerror(errno));
     155  				failed++;
     156  			}
     157  		}
     158  		return(failed);
     159  	}
     160  
     161  	/* file access acl */
     162  	if (! dflag) { 
     163  		acl = acl_from_text(argv[optind]);
     164  		failed = acl_check(acl, &c);
     165  		if (failed < 0) {
     166  			fprintf(stderr, "%s: %s - %s\n",
     167  				program, argv[optind], strerror(errno));
     168  			return 1;
     169  		}
     170  		else if (failed > 0) {
     171  			fprintf(stderr, _(
     172  				"%s: access ACL '%s': %s at entry %d\n"),
     173  				program, argv[optind], acl_error(failed), c);
     174  			return 1;
     175  		}
     176  		optind++;
     177  	}
     178  
     179  
     180  	/* directory default acl */
     181  	if (bflag || dflag) {
     182  		dacl = acl_from_text(argv[optind]);
     183  		failed = acl_check(dacl, &c);
     184  		if (failed < 0) {
     185  			fprintf(stderr, "%s: %s - %s\n",
     186  				program, argv[optind], strerror(errno));
     187  			return 1;
     188  		}
     189  		else if (failed > 0) {
     190  			fprintf(stderr, _(
     191  				"%s: access ACL '%s': %s at entry %d\n"),
     192  				program, argv[optind], acl_error(failed), c);
     193  			return 1;
     194  		}
     195  		optind++;
     196  	}
     197  
     198  	/* place acls on files */
     199  	for (; optind < argc; optind++)
     200  		failed += set_acl(acl, dacl, argv[optind]);
     201  
     202  	if (acl)
     203  		acl_free(acl);
     204  	if (dacl)
     205  		acl_free(dacl);
     206  
     207  	return(failed);
     208  }
     209  
     210  /* 
     211   *   deletes an access acl or directory default acl if one exists
     212   */ 
     213  static int 
     214  acl_delete_file(const char *path, acl_type_t type)
     215  {
     216  	int error = 0;
     217  
     218  	/* converts access ACL to a minimal ACL */
     219  	if (type == ACL_TYPE_ACCESS) {
     220  		acl_t acl;
     221  		acl_entry_t entry;
     222  		acl_tag_t tag;
     223  
     224  		acl = acl_get_file(path, ACL_TYPE_ACCESS);
     225  		if (!acl)
     226  			return -1;
     227  		error = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
     228  		while (error == 1) {
     229  			acl_get_tag_type(entry, &tag);
     230  			switch(tag) {
     231  				case ACL_USER:
     232  				case ACL_GROUP:
     233  				case ACL_MASK:
     234  					acl_delete_entry(acl, entry);
     235  					break;
     236  			 }
     237  			error = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
     238  		}
     239  		if (!error)
     240  			error = acl_set_file(path, ACL_TYPE_ACCESS, acl);
     241  	} else
     242  		error = acl_delete_def_file(path);
     243  	return(error);
     244  }
     245  
     246  /*
     247   *    lists the acl for a file/dir in short text form
     248   *    return 0 on failure
     249   *    return 1 on success
     250   */
     251  static int
     252  list_acl(char *file)
     253  {
     254  	acl_t acl = NULL;
     255  	acl_t dacl = NULL;
     256  	char *acl_text, *dacl_text = NULL;
     257  
     258  	if ((acl = acl_get_file(file, ACL_TYPE_ACCESS)) == NULL) {
     259  		fprintf(stderr, _("%s: cannot get access ACL on '%s': %s\n"),
     260  			program, file, strerror(errno));
     261  		return 0;
     262  	}
     263  	if ((dacl = acl_get_file(file, ACL_TYPE_DEFAULT)) == NULL &&
     264  	    (errno != EACCES)) {	/* EACCES given if not a directory */
     265  		fprintf(stderr, _("%s: cannot get default ACL on '%s': %s\n"),
     266  			program, file, strerror(errno));
     267  		return 0;
     268  	}
     269  	acl_text = acl_to_any_text(acl, NULL, ',', TEXT_ABBREVIATE);
     270  	if (acl_text == NULL) {
     271  		fprintf(stderr, _("%s: cannot get access ACL text on "
     272  			"'%s': %s\n"), program, file, strerror(errno));
     273  		return 0;
     274  	}
     275  	if (acl_entries(dacl) > 0) {
     276  		dacl_text = acl_to_any_text(dacl, NULL, ',', TEXT_ABBREVIATE);
     277  		if (dacl_text == NULL) {
     278  			fprintf(stderr, _("%s: cannot get default ACL text on "
     279  				"'%s': %s\n"), program, file, strerror(errno));
     280  			return 0;
     281  		}
     282  	}
     283  	if (dacl_text) {
     284  		printf("%s [%s/%s]\n", file, acl_text, dacl_text);
     285  		acl_free(dacl_text);
     286  	} else
     287  		printf("%s [%s]\n", file, acl_text);
     288  	acl_free(acl_text);
     289  	acl_free(acl);
     290  	acl_free(dacl);
     291  	return 1;
     292  }
     293  
     294  static int
     295  set_acl(acl_t acl, acl_t dacl, const char *fname)
     296  {
     297  	int failed = 0;
     298  
     299  	if (rflag)
     300  		failed += walk_dir(acl, dacl, fname);
     301  
     302  	/* set regular acl */
     303  	if (acl && acl_set_file(fname, ACL_TYPE_ACCESS, acl) == -1) {
     304  		fprintf(stderr, _("%s: cannot set access acl on \"%s\": %s\n"),
     305  			program, fname, strerror(errno));
     306  		failed++;
     307  	}
     308  	/* set default acl */
     309  	if (dacl && acl_set_file(fname, ACL_TYPE_DEFAULT, dacl) == -1) {
     310  		fprintf(stderr, _("%s: cannot set default acl on \"%s\": %s\n"),
     311  			program, fname, strerror(errno));
     312  		failed++;
     313  	}
     314  
     315  	return(failed);
     316  }
     317  
     318  static int
     319  walk_dir(acl_t acl, acl_t dacl, const char *fname)
     320  {
     321  	int failed = 0;
     322  	DIR *dir;
     323  	struct dirent64 *d;
     324  	char *name;
     325  
     326  	if ((dir = opendir(fname)) == NULL) {
     327  		if (errno != ENOTDIR) {
     328  			fprintf(stderr, _("%s: opendir failed: %s\n"),
     329  				program, strerror(errno));
     330  			return(1);
     331  		}
     332  		return(0);	/* got a file, not an error */
     333  	}
     334  
     335  	while ((d = readdir64(dir)) != NULL) {
     336  		/* skip "." and ".." entries */
     337  		if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
     338  			continue;
     339  		
     340  		name = malloc(strlen(fname) + strlen(d->d_name) + 2);
     341  		if (name == NULL) {
     342  			fprintf(stderr, _("%s: malloc failed: %s\n"),
     343  				program, strerror(errno));
     344  			exit(1);
     345  		}
     346  		sprintf(name, "%s/%s", fname, d->d_name);
     347  
     348  		failed += set_acl(acl, dacl, name);
     349  		free(name);
     350  	}
     351  	closedir(dir);
     352  
     353  	return(failed);
     354  }