261 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			261 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 
 | |
| 	Mode Muncher -- modemuncher.c
 | |
| 	961110 Claudio Terra
 | |
| 
 | |
| 	munch vb
 | |
| 	[ME monchen, perh. influenced by MF mangier to eat --more at MANGER]
 | |
| 	:to chew with a crunching sound: eat with relish
 | |
| 	:to chew food with a crunching sound: eat food with relish
 | |
| 	--munch-er n
 | |
| 		
 | |
| 	The NeXT Digital Edition of Webster's Ninth New Collegiate Dictionary
 | |
| 	and Webster's Collegiate Thesaurus
 | |
| */
 | |
| 
 | |
| /* struct for rwx <-> POSIX constant lookup tables */
 | |
| struct modeLookup
 | |
| {
 | |
| 	char rwx;
 | |
| 	mode_t bits;
 | |
| };
 | |
| 
 | |
| typedef struct modeLookup modeLookup;
 | |
| 
 | |
| static modeLookup modesel[] =
 | |
| {
 | |
| 	/* RWX char				Posix Constant */
 | |
| 	{'r',					S_IRUSR},
 | |
| 	{'w',					S_IWUSR},
 | |
| 	{'x',					S_IXUSR},
 | |
| 	
 | |
| 	{'r',					S_IRGRP},
 | |
| 	{'w',					S_IWGRP},
 | |
| 	{'x',					S_IXGRP},
 | |
| 	
 | |
| 	{'r',					S_IROTH},
 | |
| 	{'w',					S_IWOTH},
 | |
| 	{'x',					S_IXOTH},
 | |
| 	{0, 					(mode_t)-1} /* do not delete this line */
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| static int rwxrwxrwx(mode_t *mode, const char *p)
 | |
| {
 | |
| 	int count;
 | |
| 	mode_t tmp_mode = *mode;
 | |
| 	
 | |
| 	tmp_mode &= ~(S_ISUID | S_ISGID); /* turn off suid and sgid flags */
 | |
| 	for (count=0; count<9; count ++)
 | |
| 	{
 | |
| 		if (*p == modesel[count].rwx) tmp_mode |= modesel[count].bits;	/* set a bit */
 | |
| 		else if (*p == '-') tmp_mode &= ~modesel[count].bits;			/* clear a bit */
 | |
| 		else if (*p=='s') switch(count)
 | |
| 		{
 | |
| 			case 2: /* turn on suid flag */
 | |
| 			tmp_mode |= S_ISUID | S_IXUSR;
 | |
| 			break;
 | |
| 			
 | |
| 			case 5: /* turn on sgid flag */
 | |
| 			tmp_mode |= S_ISGID | S_IXGRP;
 | |
| 			break;
 | |
| 
 | |
| 			default:
 | |
| 			return -4; /* failed! -- bad rwxrwxrwx mode change */
 | |
| 			break;
 | |
| 		}
 | |
| 		p++;
 | |
| 	}
 | |
| 	*mode = tmp_mode;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void modechopper(mode_t mode, char *p)
 | |
| {
 | |
| 	/* requires char p[10] */
 | |
| 	int count;
 | |
| 	char *pp;
 | |
| 	
 | |
| 	pp=p;
 | |
| 	
 | |
| 	for (count=0; count<9; count ++)
 | |
| 	{
 | |
| 		if (mode & modesel[count].bits) *p = modesel[count].rwx;
 | |
| 		else *p='-';
 | |
| 		
 | |
| 		p++;
 | |
| 	}
 | |
| 	*p=0; /* to finish the string */
 | |
| 	
 | |
| 	/* dealing with suid and sgid flags */
 | |
| 	if (mode & S_ISUID) pp[2] = (mode & S_IXUSR) ? 's' : 'S';
 | |
| 	if (mode & S_ISGID) pp[5] = (mode & S_IXGRP) ? 's' : 'S';
 | |
| 
 | |
| }
 | |
| 
 | |
| static int mode_munch(mode_t *mode, const char* p)
 | |
| {
 | |
| 
 | |
| 	char op=0;
 | |
| 	mode_t affected_bits, ch_mode;
 | |
| 	int doneFlag = 0;
 | |
| #ifdef DEBUG
 | |
| char tmp[10];
 | |
| #endif
 | |
| 
 | |
| #ifdef DEBUG
 | |
| modechopper(*mode, tmp);
 | |
| printf("modemuncher: got base mode = %s\n", tmp);
 | |
| #endif
 | |
| 
 | |
| 	while (!doneFlag)
 | |
| 	{
 | |
| 		/* step 0 -- clear temporary variables */
 | |
| 		affected_bits=0;
 | |
| 		ch_mode=0;
 | |
| 		
 | |
| 		/* step 1 -- who's affected? */
 | |
| 
 | |
| #ifdef DEBUG
 | |
| printf("modemuncher step 1\n");
 | |
| #endif
 | |
| 		
 | |
| 		/* mode string given in rwxrwxrwx format */
 | |
| 		if (*p== 'r' || *p == '-') return rwxrwxrwx(mode, p);
 | |
| 		
 | |
| 		/* mode string given in ugoa+-=rwx format */
 | |
| 		for ( ; ; p++)
 | |
| 			switch (*p)
 | |
| 			{
 | |
| 				case 'u':
 | |
| 				affected_bits |= 04700;
 | |
| 				break;
 | |
| 				
 | |
| 				case 'g':
 | |
| 				affected_bits |= 02070;
 | |
| 				break;
 | |
| 				
 | |
| 				case 'o':
 | |
| 				affected_bits |= 01007;
 | |
| 				break;
 | |
| 				
 | |
| 				case 'a':
 | |
| 				affected_bits |= 07777;
 | |
| 				break;
 | |
| 				
 | |
| 				/* ignore spaces */
 | |
| 				case ' ':
 | |
| 				break;
 | |
| 				
 | |
| 				
 | |
| 				default:
 | |
| 				goto no_more_affected;
 | |
| 			}
 | |
| 
 | |
| 		no_more_affected:
 | |
| 		/* If none specified, affect all bits. */
 | |
| 		if (affected_bits == 0) affected_bits = 07777;
 | |
| 
 | |
| 		/* step 2 -- how is it changed? */
 | |
| 		
 | |
| #ifdef DEBUG
 | |
| printf("modemuncher step 2 (*p='%c')\n", *p);
 | |
| #endif
 | |
| 
 | |
| 		switch (*p)
 | |
| 		{
 | |
| 			case '+':
 | |
| 			case '-':
 | |
| 			case '=':
 | |
| 			op = *p;
 | |
| 			break;
 | |
| 			
 | |
| 			/* ignore spaces */
 | |
| 			case ' ':
 | |
| 			break;
 | |
| 			
 | |
| 			default:
 | |
| 			return -1; /* failed! -- bad operator */
 | |
| 		}
 | |
| 		
 | |
| 		
 | |
| 		/* step 3 -- what are the changes? */
 | |
| 		
 | |
| #ifdef DEBUG
 | |
| printf("modemuncher step 3\n");
 | |
| #endif
 | |
| 
 | |
| 		for (p++ ; *p!=0 ; p++)
 | |
| 			switch (*p)
 | |
| 			{
 | |
| 				case 'r':
 | |
| 				ch_mode |= 00444;
 | |
| 				break;
 | |
| 				
 | |
| 				case 'w':
 | |
| 				ch_mode |= 00222;
 | |
| 				break;
 | |
| 				
 | |
| 				case 'x':
 | |
| 				ch_mode |= 00111;
 | |
| 				break;
 | |
| 				
 | |
| 				case 's':
 | |
| 				/* Set the setuid/gid bits if `u' or `g' is selected. */
 | |
| 				ch_mode |= 06000;
 | |
| 				break;
 | |
| 			
 | |
| 				/* ignore spaces */
 | |
| 				case ' ':
 | |
| 				break;
 | |
| 				
 | |
| 				default:
 | |
| 				goto specs_done;
 | |
| 			}
 | |
| 
 | |
| 		specs_done:
 | |
| 		/* step 4 -- apply the changes */
 | |
| 
 | |
| #ifdef DEBUG
 | |
| 		printf("modemuncher step 4\n");
 | |
| #endif
 | |
| 		if (*p != ',') doneFlag = 1;
 | |
| 		if (*p != 0 && *p != ' ' && *p != ',')
 | |
| 		{
 | |
| 		
 | |
| #ifdef DEBUG
 | |
| printf("modemuncher: comma error!\n");
 | |
| printf("modemuncher: doneflag = %u\n", doneFlag);
 | |
| #endif
 | |
| 			return -2; /* failed! -- bad mode change */
 | |
| 		
 | |
| 		}
 | |
| 		p++;
 | |
| 		/*if (!ch_mode) return -2;*/ /* failed! -- bad mode change */
 | |
| 		if (ch_mode) switch (op)
 | |
| 		{
 | |
| 			case '+':
 | |
| 			*mode = *mode |= ch_mode & affected_bits;
 | |
| 			break;
 | |
| 
 | |
| 			case '-':
 | |
| 			*mode = *mode &= ~(ch_mode & affected_bits);
 | |
| 			break;
 | |
| 
 | |
| 			case '=':
 | |
| 			*mode = ch_mode & affected_bits;
 | |
| 			break;
 | |
| 		
 | |
| 			default:
 | |
| 			return -3; /* failed! -- unknown error */
 | |
| 		}
 | |
| 	}
 | |
| #ifdef DEBUG
 | |
| modechopper(*mode, tmp);
 | |
| printf("modemuncher: returning mode = %s\n", tmp);
 | |
| #endif
 | |
| 
 | |
| 	return 0; /* successful call */
 | |
| }
 | |
| 
 | |
| 
 |