cli.c 8.58 KB
Newer Older
1
/*******************************************************************************
2 3
    OpenAirInterface
    Copyright(c) 1999 - 2014 Eurecom
4

5 6 7 8
    OpenAirInterface 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 3 of the License, or
    (at your option) any later version.
9 10


11 12 13 14
    OpenAirInterface 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.
15

16 17 18 19
    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is
    included in this distribution in the file called "COPYING". If not,
    see <http://www.gnu.org/licenses/>.
20 21

  Contact Information
22 23
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
24
  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
25

ghaddab's avatar
ghaddab committed
26
  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
27

28
*******************************************************************************/
29 30 31
/*! \file cli.c
* \brief oai main cli core
* \author Navid Nikaein
32
* \date 2011 - 2014
33 34 35 36 37 38 39 40
* \version 0.1
* \warning This component can be runned only in user-space
* @ingroup util

*/


#include <unistd.h>
41
#include <signal.h>
42 43 44 45 46 47 48 49 50 51 52 53
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <ctype.h>

#include "cli.h"

extern cli_config *cli_cfg;



command commands[] = {
54 55 56 57 58 59 60 61
  {0, "help",NULL,com_help, NULL,"Display this text" },
  {0, "?",NULL,com_help, NULL, "help at any point" },
  {2, "prompt",NULL,prompt, prompt_usage,"Set/get cli prompt" },
  {2, "info",NULL,info, NULL,"get software information" },
  {1, "start",NULL,start, start_usage,"Start eNB/UE instance" },
  {1, "set",NULL,set, set_usage,"set log for a give component" },
  {0, "exit",NULL,com_exit, NULL,"Exit using OpenAir CLI Interface" },
  {0, (char *)NULL,NULL, NULL,NULL, (char *)NULL }
62 63 64 65
};


static uid_t real_uid;
66 67 68
void priv_init(void)
{
  real_uid = getuid();
69 70
}

71 72
void priv_up(void)
{
73 74 75 76 77
  if (seteuid(0) != 0) {
    printf("[CLI] Error setting uid to %d\n", real_uid);
  }
}

78 79
void priv_down(void)
{
80 81 82 83 84
  if (seteuid(real_uid) != 0) {
    printf("[CLI] Error setting uid to %d\n", 0);
  }
}

85 86 87
int cli_start(void)
{

88
  priv_init();
89

90 91
  priv_down();
  putenv("REMADDR=");
92

93 94 95 96
  // get username
  if ((username = getlogin()) == NULL) {
    username = getenv("USER");
  }
97

98
  set_permissions_map();
99

100 101 102 103 104
  // set login info
  cli_login(username, CLI_MAX_NODES, CLI_MAX_CMDS);
  // send welcome msg to the client
  sprintf(buffer, "%s", WELCOME_MSG);
  send(cli_cfg->cfd, buffer, strlen(buffer), 0);
105

106 107 108 109 110 111 112 113
  printf(WELCOME_MSG);
  printf("[CLI] started...\n");
  sprintf(cli_cfg->prompt,"%s%c ", cli_prompt(),  cli_cfg->promptchar);
  send(cli_cfg->cfd,cli_cfg->prompt, strlen(cli_cfg->prompt), 0);
  return 1;
}


114 115
int cli_loop(char * msg)
{
116 117

  char *s;
118

119 120 121 122
  /* 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(msg);
123

124 125 126 127
  if (*s) {
    //add_history(s);
    execute_line(s);
  }
128

129
  send(cli_cfg->cfd, cli_cfg->prompt, strlen(cli_cfg->prompt), 0);
130

131 132 133 134 135 136 137 138 139 140 141 142
  return 0;
}


/**
 * The permissions map is a bit map which defines which modes are available
 * to a user. The permissions groups map to linux groups in the following
 * way: subtract 1000. The remainder is the bit number.
 * Thus unix groups 1000, 1001, 1002 etc represent the permissions groups
 * default, config and admin respectively.
 *
 */
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
int set_permissions_map(void)
{
  gid_t group[10];
  int n, i;
  int perm_num;
  // get the number of supplementary group IDs
  n = getgroups(10, group);

  // give show permissions even if user has none
  map_permissions = ADMIN_PERMISSION;

  for (i=0; i<n; i++) {
    perm_num = group[i] - 1000;

    if (perm_num < 0 || perm_num > 31) {
      continue;
159
    }
160 161 162 163 164 165 166

    //map_permissions |= (1 << perm_num);
    map_permissions |= ((1 << (perm_num+1)) - 1);
  }

  printf("[CLI] Permissions %04x for this session\n", map_permissions);
  return 0;
167 168 169
}


170 171 172
int cli_login(const char *username, int maxnodes, int maxcmds)
{

173
  cli_set_prompt_char();
174

175
  printf("[CLI] Client initialised\n");
176

177 178 179
  // log the connection
  // telnets use REMADDR
  host = getenv("REMADDR");
180

181
  if (host) {
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
    snprintf(g_sid, MAX_SID, "%s#%s", username, host);
    printf("[CLI] login via telnet by user %s from address %s\n", username, host);
  } else {
    host = getenv("SSH_CLIENT");

    if (host) {
      char *cp;
      // format is <rem_addr> <rem_port> <local_port>
      // replace first space with ':', second terminates the string
      cp = strchr(host, ' ');

      if (cp) {
        *cp = ':';
      }

      cp = strchr(host, ' ');

      if (cp) {
        *cp = '\0';
      }

      snprintf(g_sid, MAX_SID, "%s$%s", username, host);
      printf("[CLI] login via SSH by user %s from address %s", username, host);
205
    } else {
206 207
      host = getenv("HOST");

208
      if (host) {
209 210
        snprintf(g_sid, MAX_SID, "%s$%s", username, host);
        printf("[CLI] by user %s from host %s", username, host);
211
      } else {
212
        printf("[CLI]Login by user %s from unknown destination\n", username);
213 214
      }
    }
215 216 217 218 219 220

  }

  //register an exit function
  atexit(cli_finish);
  return 0;
221 222
}

223 224 225 226 227 228
char *cli_prompt(void)
{
  static char promptstr[200];
  promptstr[0]='\0';
  snprintf(promptstr, 200,"%s@%s",username, cli_cfg->prompt);
  return promptstr;
229 230
}

231 232 233 234 235 236 237 238 239
int cli_set_prompt_char(void)
{
  if (map_permissions & ADMIN_PERMISSION) {
    cli_cfg->promptchar = '#';
  } else if (map_permissions & CONFIG_PERMISSION) {
    cli_cfg->promptchar = '%';
  } else if (map_permissions & SHOW_PERMISSION) {
    cli_cfg->promptchar = '$';
  }
240

241
  return 0;
242 243
}

244 245 246 247 248 249 250 251 252 253 254 255 256
void cli_finish(void)
{
  char *cp;

  if ((cp = strchr(g_sid, '#'))) {
    *cp = '\0';
    printf("[CLI] logout via telnet by user %s from address %s\n", g_sid, cp+1);
  } else if ((cp = strchr(g_sid, '$'))) {
    *cp = '\0';
    printf("[CLI] logout via SSH by user %s from address %s\n", g_sid, cp+1);
  } else {
    printf("[CLI] logout from %s\n", g_sid);
  }
257

258
  return;
259 260 261
}

/* Execute a command line. */
262 263
int execute_line (char *line)
{
264 265 266 267 268 269
  register int i;
  command *command;
  char *word;

  /* Isolate the command word. */
  i = 0;
270

271 272 273 274
  while (line[i] && whitespace (line[i]))
    i++;

  word = line + i;
275

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
  while (line[i] && !whitespace (line[i]))
    i++;

  if (line[i])
    line[i++] = '\0';

  command = find_command(word);

  if (!command) {
    sprintf(buffer, "%s: %s \n", word, NOCOMMAND_MSG);
    send(cli_cfg->cfd, buffer, strlen(buffer), 0);
    printf("[CLI] commnad %s does not exist !\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));
}

/* 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. */
303 304
command * find_command (char *name)
{
305
  register int i;
306 307

  for (i = 0; commands[i].name; i++) {
308 309 310
    if (strcmp (name, commands[i].name) == 0)
      return (&commands[i]);
  }
311

312 313 314 315 316
  return ((command *)NULL);
}

/* Strip whitespace from the start and end of STRING.  Return a pointer
   into STRING. */
317 318
char * stripwhite (char *string)
{
319 320 321 322
  register char *s, *t;

  for (s = string; whitespace (*s); s++)
    ;
323

324 325 326 327
  if (*s == 0)
    return (s);

  t = s + strlen (s) - 1;
328

329 330
  while (t > s && whitespace (*t))
    t--;
331

332 333 334 335 336 337 338 339 340 341 342 343 344
  *++t = '\0';

  return s;
}


/* Generator function for command completion.  STATE lets us know whether
   to start from scratch; without any state (i.e. STATE == 0), then we
   start at the top of the list. */


/* Print out help for ARG, or for all of the commands if ARG is
   not present. */
345 346
int com_help (char *arg)
{
347 348 349
  register int i;
  int printed = 0;

350
  for (i = 0; commands[i].name != NULL; i++) {
351
    //  if (!*arg || (strcmp (arg, commands[i].name) == 0)){
352 353 354 355
    sprintf (buffer,"%s\t\t<%s>\n", commands[i].name, commands[i].doc);
    send(cli_cfg->cfd, buffer, strlen(buffer), 0);
    printed++;
    // }
356
  }
357

358 359 360
  if (!printed) {
    printf("No commands match `%s'.  Possibilties are:\n", arg);

361 362 363 364
    for (i = 0; commands[i].name; i++) {
      /* Print in six columns. */
      if (printed == 6)            {
        printed = 0;
365
        printf("\n");
366 367 368 369
      }

      printf("%s\t", commands[i].name);
      printed++;
370
    }
371 372 373 374 375

    if (printed)
      printf("\n");
  }

376 377 378
  return (0);
}

379 380
int whitespace (char c)
{
381 382 383

  return (isspace((int)c));
}