#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include char *progname; /* The name of this program, as taken from argv[0]. */ int done; /* When non-zero, this global means the user is done using this program. */ char pwd[PATH_MAX], home[PATH_MAX]; static sigset_t blockmask; COMMAND top_admin_list[] = { { "help", com_help, "Display this text" }, { "?", com_help, "Synonym for `help'" }, { "shell", com_shell, "Activate submenu shell" }, { "users", com_users, "Activate submenu users" }, { "quit", com_quit, "Quit using SILA Shell" }, { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL } }; COMMAND top_operator_list[] = { { "help", com_help, "Display this text" }, { "?", com_help, "Synonym for `help'" }, { "shell", com_shell, "Activate submenu shell" }, { "users", com_users, "Activate submenu users" }, { "quit", com_quit, "Quit using SILA Shell" }, { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL } }; COMMAND top_user_list[] = { { "help", com_help, "Display this text" }, { "?", com_help, "Synonym for `help'" }, { "shell", com_shell, "Activate submenu shell" }, { "quit", com_quit, "Quit using SILA Shell" }, { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL } }; COMMAND_LIST top; COMMAND shell_admin_list[] = { { "help", com_help, "Display this text" }, { "?", com_help, "Synonym for `help'" }, { "cd", com_cd, "Change to directory DIR" }, { "delete", com_delete, "Delete FILE" }, { "list", com_ls, "List files in DIR" }, { "ls", com_ls, "Synonym for `list'" }, { "id", com_id, "Print user identity" }, { "ping", com_ping, "Ping some host" }, { "pwd", com_pwd, "Print the current working directory" }, { "rename", com_rename, "Rename FILE to NEWNAME" }, { "stat", com_stat, "Print out statistics on FILE" }, { "more", com_more, "View the contents of FILE" }, { "vi", com_vi, "Edit the contents of text FILE" }, { "..", com_top, "Return to top menu" }, { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL } }; COMMAND shell_operator_list[] = { { "help", com_help, "Display this text" }, { "?", com_help, "Synonym for `help'" }, { "cd", com_cd, "Change to directory DIR" }, { "delete", com_delete, "Delete FILE" }, { "list", com_ls, "List files in DIR" }, { "ls", com_ls, "Synonym for `list'" }, { "id", com_id, "Print user identity" }, { "ping", com_ping, "Ping some host" }, { "pwd", com_pwd, "Print the current working directory" }, { "rename", com_rename, "Rename FILE to NEWNAME" }, { "stat", com_stat, "Print out statistics on FILE" }, { "more", com_more, "View the contents of FILE" }, { "vi", com_vi, "Edit the contents of text FILE" }, { "..", com_top, "Return to top menu" }, { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL } }; COMMAND shell_user_list[] = { { "help", com_help, "Display this text" }, { "?", com_help, "Synonym for `help'" }, { "cd", com_cd, "Change to directory DIR" }, { "delete", com_delete, "Delete FILE" }, { "list", com_ls, "List files in DIR" }, { "ls", com_ls, "Synonym for `list'" }, { "id", com_id, "Print user identity" }, { "ping", com_ping, "Ping some host" }, { "pwd", com_pwd, "Print the current working directory" }, { "rename", com_rename, "Rename FILE to NEWNAME" }, { "stat", com_stat, "Print out statistics on FILE" }, { "more", com_more, "View the contents of FILE" }, { "vi", com_vi, "Edit the contents of text FILE" }, { "..", com_top, "Return to top menu" }, { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL } }; COMMAND_LIST shell; COMMAND users_admin_list[] = { { "help", com_help, "Display this text" }, { "?", com_help, "Synonym for `help'" }, { "useradd", com_useradd, "Register new user" }, { "userdel", com_userdel, "Delete user" }, { "list", com_userlist, "List users" }, { "..", com_top, "Return to top menu" }, { "quit", com_quit, "Quit using SILA Shell" }, { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL } }; COMMAND users_operator_list[] = { { "help", com_help, "Display this text" }, { "?", com_help, "Synonym for `help'" }, { "useradd", com_useradd, "Register new user" }, { "userdel", com_userdel, "Delete user" }, { "list", com_userlist, "List users" }, { "..", com_top, "Return to top menu" }, { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL } }; COMMAND users_user_list[] = { { "help", com_help, "Display this text" }, { "?", com_help, "Synonym for `help'" }, { "list", com_userlist, "List users" }, { "..", com_top, "Return to top menu" }, { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL } }; COMMAND_LIST users; COMMAND_LIST *current; enum priv { ADMIN, OPERATOR, USER }; enum priv user_privileges() { enum priv ret = USER; gid_t *groups = NULL; int ng = 0; uid_t uid = getuid(); struct passwd *pw = getpwuid( uid ); if( !pw ) return ret; (void)getgrouplist( pw->pw_name, pw->pw_gid, NULL, &ng ); /* allocate groups[] */ if( ng == 0 ) { fprintf( stderr, "Cannot get user groups list\n" ); exit( 1 ); } groups = (gid_t *)malloc( sizeof(gid_t)* ng ); if( !groups ) { fprintf( stderr, "Cannot allocate memory\n" ); exit( 1 ); } if( getgrouplist( pw->pw_name, pw->pw_gid, groups, &ng ) == -1 ) { free( groups ); fprintf( stderr, "getgrouplist() returned -1; ngroups = %d\n", ng ); exit( 1 ); } for( int i = 0; i < ng; i++ ) { struct group *gr = getgrgid(groups[i]); if( gr ) { if( !strncmp( gr->gr_name, "priv-operator", 10 ) ) ret = OPERATOR; } } for( int i = 0; i < ng; i++ ) { struct group *gr = getgrgid(groups[i]); if( gr ) { if( !strncmp( gr->gr_name, "priv-admin", 10 ) ) ret = ADMIN; } } free( groups ); return ret; } void cmd_lists_init( gid_t gid ) { enum priv privileges = USER; privileges = user_privileges(); top.name = "top"; shell.name = "shell"; users.name = "users"; if( privileges == ADMIN || gid == 0 ) { top.list = &top_admin_list[0]; shell.list = &shell_admin_list[0]; users.list = &users_admin_list[0]; } else if( privileges == OPERATOR ) { top.list = &top_operator_list[0]; shell.list = &shell_operator_list[0]; users.list = &users_operator_list[0]; } else { top.list = &top_user_list[0]; shell.list = &shell_user_list[0]; users.list = &users_user_list[0]; } current = ⊤ } /* Strip whitespace from the start and end of STRING. Return a pointer into STRING. */ char *stripwhite( char *string ) { register char *s, *t; for( s = string; whitespace (*s); ++s ) ; if( *s == 0 ) return( s ); t = s + strlen( s ) - 1; while( t > s && whitespace( *t ) ) t--; *++t = '\0'; return s; } /* Look up NAME as the name of a command, and return a pointer to that command. Return a NULL pointer if NAME isn't a command name. */ COMMAND *find_command( char *name ) { register int i; for( i = 0; current->list[i].name; i++ ) if( strcmp( name, current->list[i].name ) == 0 ) return( ¤t->list[i] ); return( (COMMAND *)NULL ); } /* Execute a command line. */ int execute_line( char *line ) { register int i; COMMAND *command; char *word; /* Isolate the command word. */ i = 0; while( line[i] && whitespace( line[i] ) ) i++; word = line + i; while( line[i] && !whitespace( line[i] ) ) i++; if( line[i] ) line[i++] = '\0'; command = find_command( word ); if( !command ) { if( strcmp( current->name, "top" ) ) fprintf( stderr, "%s: No such command for SILA[%s] Shell.\n", word, current->name ); else fprintf( stderr, "%s: No such command for SILA Shell.\n", word ); return( -1 ); } /* Get argument to command, if any. */ while( whitespace( line[i] ) ) i++; word = line + i; /* Call the function. */ return( (*(command->func))(word) ); } void sigint( int signum ) { if( signum == SIGTERM ) { /* free resourses and exit */ exit( 0 ); } else { /* Ignore SIGINT */ return; } } static void set_signal_handlers() { struct sigaction sa; sigset_t set; memset( &sa, 0, sizeof( sa ) ); sa.sa_handler = sigint; /* TERM, INT */ sa.sa_flags = SA_RESTART; sigemptyset( &set ); sigaddset( &set, SIGTERM ); sigaddset( &set, SIGINT ); sa.sa_mask = set; sigaction( SIGTERM, &sa, NULL ); sigaction( SIGINT, &sa, NULL ); /* на случай блокировки сигналов с помощью sigprocmask(): */ sigemptyset( &blockmask ); sigaddset( &blockmask, SIGTERM ); sigaddset( &blockmask, SIGINT ); } int main( int argc, char **argv ) { char *line, *s, *home, *curdir; char prompt[PATH_MAX]; set_signal_handlers(); cmd_lists_init( getgid() ); progname = argv[0]; initialize_readline(); /* Bind our completer. */ /* Loop reading and executing lines until the user quits. */ for( ; done == 0; ) { home = getenv( "HOME" ); curdir = getcwd( pwd, PATH_MAX ); if( home && curdir == strstr( curdir, home ) ) { curdir[strlen( home ) - 1] = '~'; curdir += strlen( home ) - 1; } if( strcmp( current->name, "top" ) ) sprintf( prompt, "%s[%s]:%s$ ", "sila", current->name, curdir ); else sprintf( prompt, "%s:%s$ ", "sila", curdir ); line = readline( prompt ); if( !line ) { break; } /* Remove leading and trailing whitespace from the line. Then, if there is anything left, add it to the history list and execute it. */ s = stripwhite( line ); if( *s ) { add_history( s ); execute_line( s ); } free( line ); } exit( 0 ); }