/* Created: 03.19.05 11:34:57 by Attila Nagyidai $Id: C\040Console.c,v 1.1.2.1 2003/08/13 00:38:46 neum Exp $ This file is part of IBSH (Iron Bars Shell) , a restricted Unix shell Copyright (C) 2005 Attila Nagyidai This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Attila Nagyidai Email: na@ent.hu Co-Author: Shy Email: shy@cpan.org Co-Author: Witzy Email: stazzz@altern.org URL: http://ibsh.sourceforge.net IRC: irc.freenode.net #ibsh RSS, Statistics, etc: http://sourceforge.net/projects/ibsh/ */ /* Header files */ #include "ibsh.h" extern Strng commands[MAX_ITEMS]; /* This is my version of scanf. It offers good protection against */ /* buffer overflow attacks. */ /* Technical Description: */ /* Variables: the char to read to from stdin, the sum of chars typed in, */ /* and an integer for length checking. */ /* Read characters from stdin in a loop, until Enter is pressed. */ /* The line size check wont stop accepting characters, but it will */ /* break long commands to LINE_SIZEd pieces. */ /* Update: */ /* Read only 80 characters. If the current path + this 80 chars + / */ /* are longer then 255, read less chars. */ void myscanf( char *vptr, char *abspath ) { int c; char chars[STRING_SIZE]; int i = 0, j = 0; int linesize = LINE_SIZE; fflush(stdin); if ( (strlen(abspath)) > (255 - 80 - 1) ) { linesize = 255 - strlen(abspath) - 1; /* thats for the / */ } while ( ((c = getchar()) != 10) && ( i < linesize ) ) { //printf("%d", c); if (c > 127) { c = 0; //ungetc(c, stdin); //fflush(stdin); break; } if ( c < 0 ) { ungetc(c, stdin); openlog("ibsh", LOG_PID, LOG_AUTH); syslog(LOG_INFO, "user %s has logged out.", loggedin.uname); closelog(); exit(0); } chars[i] = c; /* the user is not allowed to pass long lines of trash to ibsh */ i++; } chars[i] = '\0'; strncpy(vptr,chars,STRING_SIZE-1); vptr[STRING_SIZE-1] = '\0'; } /* Checks, if the user command, is blacklisted, a hack attempt, */ /* or it is a real and allowed command. */ /* Technical Description: */ /* Variables: pointer for the strtok, temporary strings, counters, */ /* and an integer to check, how deep is the user in the jail. That is */ /* the level of subdirectories below jail root. It is set to -1, because */ /* there is always a / in the jailpath. So only subdir /'s are counted. */ /* Check if the command contains special characters, if yes, quit. */ /* If the user is in jailroot, a ../ is not appropriate! */ /* Count the slashes in the jailpath, so if the user uses way too many */ /* ../ 's, then we will know. Split the command to particles by the spaces. */ /* Count the dirups (../); if a token starts with a /, paste the homedir path */ /* right in front of it. Thats your root booby, not / !!!! */ /* Finally check the command against the COMMANDS_LIST. */ int CommandOK( const char *thecommand, const char *rootdir, const char *jailpath, char *newcommand ) { char *tok; char temp1[STRING_SIZE], *temp2; int i = 0, j = 0; int subdirlevel = -1; /* jailpath always starts with a / */ int dirupfound = 0; int listed = 0; /* First, get the fancy stuff: */ /* ../ out of the jailroot, too many ../ out of some */ /* subdirectory in the jail, multiple commands, pipes. */ bzero(newcommand,STRING_SIZE); if ( (strstr(thecommand, ";")) != NULL ) { return 0; } if ( (strstr(thecommand, "|")) != NULL ) { return 0; } if ( (strstr(thecommand, "&")) != NULL ) { return 0; } if ( (strstr(thecommand, "&&")) != NULL ) { return 0; } if ( (strstr(thecommand, "||")) != NULL ) { return 0; } /* The user is in the jailroot. */ if ( (strcmp(jailpath, "/")) == 0 ) { /* Does the user wish to get out ? */ if ( (strstr(thecommand, "..")) != NULL ) { return 0; } } /* The user is deeper, than the jailroot, and */ /* this is a problem. How deep is he, how many */ /* ../ do we allow ?? */ else { for (i = 0; i < strlen(jailpath); i++) { if ( jailpath[i] == '/' ) { subdirlevel++; } } } /* Split the command */ for (tok = strtok((void *) thecommand, " "); tok; tok = strtok(0, " ")) { /* Separate parts of the command with a space */ if ( (strlen(newcommand)) > 0 ) { strncat(newcommand," ", STRING_SIZE-strlen(newcommand)-1); } /* He wants to get to the real root, does he ? */ /* In that case, add the jailroot to the left. */ if ( tok[0] == '/' ) { strncat(newcommand,rootdir,STRING_SIZE-strlen(newcommand)-1); } /* how many ../ are here */ /* if too many, that is more, then how deep */ /* the user in the subdirs inside the jail is, */ /* cancel the execution of the command. */ if ( (strstr(tok, "../")) != NULL ) { strncpy(temp1,tok,sizeof(temp1)-1); temp1[sizeof(temp1)-1] = '\0'; while (1) { temp2 = strstr(temp1, "../"); if ( temp2 == NULL ) { break; } LTrim3(temp2, temp1); dirupfound++; } if ( dirupfound > subdirlevel ) { return 0; } /* replace dirups with real path */ for (i = 0; i < dirupfound; i++) { PathMinusOne(jailpath, tok, subdirlevel,sizeof(tok)); } } /* if command is not listed, return 0 */ i = 0; while ( ((strlen(commands[i])) > 0) && ( j == 0 ) ) { if ( (strcmp(tok, commands[i])) == 0 ) { listed = 1; break; } i++; } j++; strncat(newcommand,tok,STRING_SIZE-strlen(newcommand)-1); } #ifdef DEBUG printf("old: %s; new: %s; ok: %d\n", thecommand, newcommand, listed); #endif return listed; }