Logo Search packages:      
Sourcecode: gadmin-dhcpd version File versions  Download package

handle_ssh.c

/* GADMIN-DHCPD - An easy to use GTK+ frontend for ISC DHCPD.
 * Copyright (C) 2004 - 2008 Magnus Loef <magnus-swe@telia.com> 
 *
 * 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 3 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
*/


#include "../config.h"

/* Must be declared before gtk+ */
#define _GNU_SOURCE
#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "handle_ssh.h"



char ** create_scp_upload_cmd(char *user, char *port, char *file_path, char *dest_path)
{
    /* Setup argv for SCP:ing file(s) to a remote host.
       IE: scp -P 22 /tmp/dhcpd.conf root@192.168.0.100:/etc/ */
    char **new_argv;
    new_argv = malloc((6) * sizeof(char *));

    new_argv[0] = SCP_BINARY;
    new_argv[1] = "-P";
    new_argv[2] = port;
    new_argv[3] = file_path;
    new_argv[4] = dest_path;
    new_argv[5] = NULL;

    return new_argv;
}

char ** create_ssh_cmd(char *user, char *host, char *port, char *ssh_cmd)
{
    /* Setup argv for SSH:ing to a remote host and running a command.
       IE: ssh -l root -p 22 localhost killall -HUP dhcpd */
    char **new_argv;
    new_argv = malloc((8) * sizeof(char *));

    new_argv[0] = SSH_BINARY;
    new_argv[1] = "-l";
    new_argv[2] = user;
    new_argv[3] = "-p";
    new_argv[4] = port;
    new_argv[5] = host;
    new_argv[6] = ssh_cmd;
    new_argv[7] = NULL;

    return new_argv;
}


int run_ssh_cmd(char *new_argv[], char *password)
{
    /* Create a pseudo terminal and fork the process */
    int i, masterpty, slavepty, childpid, child_status = 0;
    int retval_select =  0; /* -1 = Error */
    int child_exit    =  0; /*  1 = Child exited */
    pid_t wait_pid;
    const char *slave_pty_name;
    const char *askpass = "SSH_ASKPASS";
    const char *display = "DISPLAY";

    masterpty = getpt();
    if( masterpty == -1 )
    {
      perror("Can not open a pseudo-terminal master");
      return 0;
    }

    if( grantpt(masterpty) !=0 )
    {
      perror("Can not change permission of the pseudo terminal");
      return 0;
    }
    if( unlockpt(masterpty) !=0 )
    {
      perror("Can not unlock pseudo terminal");
      return 0;
    }

    childpid = fork();
    if( childpid == 0 )
    {
      /* This is the child process. */

      /* Create a new session. */
      setsid();

      /* Get the name of the slave pty */ 
      slave_pty_name = (const char *) ptsname(masterpty);

      /* Open the slave pty */
      slavepty = open(slave_pty_name, O_RDWR);
      close(masterpty);
      
      /* Show command to run. The password is not shown. */
      for(i=0; new_argv[i]!=NULL; i++)
         fprintf(stderr, "%s ", new_argv[i]);
      fprintf(stderr, "\n");

      /* Unset SSH_ASKPASS and DISPLAY to disable GNOME ssh-askpass popup. */
      if( unsetenv(askpass) == -1 )
          fprintf(stderr, "Unable to unset SSH_ASKPASS environment variable.\n");
      if( unsetenv(display) == -1 )
          fprintf(stderr, "Unable to unset DISPLAY environment variable.\n");

      /* Run the command */
      execvp(new_argv[0], new_argv);

      fprintf(stderr, "Can not run command.\n");

      exit(errno);
    }
    else
    if( childpid < 0 )
    {
      fprintf(stderr, "Can not create child process.\n");
      return 0;
    }
      
    /* We are the parent */
    do
    {
      if( ! child_exit )
      {
          fd_set readfd;

          FD_ZERO(&readfd);
          FD_SET(masterpty, &readfd);

          retval_select = select(masterpty+1, &readfd, NULL, NULL, NULL);
          if( retval_select > 0 )
          {
            if( FD_ISSET(masterpty, &readfd) )
            {
                if( ! handle_output(masterpty, password) )
                {
                  /* Process error. Close the master control pty for the process. */
                  close(masterpty);
                  child_exit = 1;
                }
            }
          }
          wait_pid = waitpid(childpid, &child_status, WNOHANG);
      }
      else
        wait_pid = waitpid(childpid, &child_status, 0);

    } while( wait_pid == 0 || (! WIFEXITED(child_status) && ! WIFSIGNALED(child_status)) );

    /* Child has exited, return child status */

    /* Command successful. */
    if( WIFEXITED(child_status) )
        return 1;

    /* Command failed or timed out. */
    return 0;
}


int write_string(int fd, char *string)
{
    int retval = 0;
    ssize_t bytes_written = 0;

    if( ! strcmp(string, "\n") )
      bytes_written =  write(fd, "\n", 1);
    else
    {
        bytes_written = write(fd, string, strlen(string));
        write(fd, "\n", 1);
    }

    if( bytes_written == -1 )
    {
      retval = 0;
        fprintf(stderr, "Error: No bytes written.\n");
    }
    else
    {
      retval = 1;
        fprintf(stderr, "Bytes written: %d\n", bytes_written);
    }

    return retval;
}


int handle_output(int fd, char *password)
{
    /* Answer process output. */
    char auth_line[]="ant to continue connecting";
    char pass_line[]="assword:";
    char pass_phrase_line[]="passphrase";
    char key_overwrite_line[]="verwrite (y/n)";
    int  retval = 1; /* 0 = Exit child process due to read or write error */
    char output[128]="";
    char line[128]="";
    int i=0, x=0, bytes_read=0;
    
    bytes_read = read(fd, output, sizeof(output));

    /* Read error */
    if( bytes_read == -1 )
      return 0;


    for(i=0; i<=129; i++)
    {
      line[x]=output[i];
      x++;
      
      if( output[i]!='\0' && output[i]!='\r' && output[i]!='\n' )
          continue;

      if( strlen(line) < 7 )
        continue;

      if( strstr(line, key_overwrite_line) )
      {
          fprintf(stderr, "Overwriting old keys.\n");
          if( ! write_string(fd, "yes") )
            retval = 0;
      }

      if( strstr(line, pass_phrase_line) )
      {
          fprintf(stderr, "Writing empty key phrase.\n");
          if( ! write_string(fd, "\n") )
            retval = 0;
      }

      if( strstr(line, auth_line) )
      {
          fprintf(stderr, "Allowing authentication to proceed.\n");
          if( ! write_string(fd, "yes") )
            retval = 0;
      }

      if( strstr(line, pass_line) )
      {
          fprintf(stderr, "Supplying password.\n");
          if( ! write_string(fd, password) )
            retval = 0;
      }

      x = 0;
      line[x]='\0';
    }

    return retval;
}

Generated by  Doxygen 1.6.0   Back to index