/* * slush SSL remote shell * Copyright (c) 1999 Damien Miller * All Rights Reserved * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* SSL headers */ #include #include #include #include #include "common.h" /* Set up a new SSL context */ SSL_CTX *setup_ssl_context(char *cert_file, char *key_file, int verify, int method_flag, char *error_buf, int error_len) { SSL_CTX *ctx; /* Allocate new SSL context */ switch (method_flag) { case CLIENT: ctx = SSL_CTX_new(SSLv23_client_method()); break; case SERVER: ctx = SSL_CTX_new(SSLv23_server_method()); break; default: if (error_buf != NULL) snprintf(error_buf, error_len, "Invalid method_flag"); return(NULL); } if (ctx == NULL) { if (error_buf != NULL) snprintf(error_buf, error_len, "Could not create context"); return(NULL); } /* Set path to CA certs */ SSL_CTX_set_default_verify_paths(ctx); /* Set certificate verification level */ SSL_CTX_set_verify(ctx, verify, NULL); /* Assign private key, if any */ if ((key_file != NULL) && (key_file[0] != '\0')) { if (SSL_CTX_use_RSAPrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) == -1) { if (error_buf != NULL) snprintf(error_buf, error_len, "Could not assign private key"); return(NULL); } } /* Assign certificate, if any */ if ((cert_file != NULL) && (cert_file[0] != '\0')) { if (SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM) == -1) { if (error_buf != NULL) snprintf(error_buf, error_len, "Could not assign certificate"); return(NULL); } } return(ctx); } /* Initialise SSL */ void init_ssl(void) { /* Load error messages */ SSL_load_error_strings(); /* Load crypto algorithms pertinent to SSL */ SSLeay_add_ssl_algorithms(); } /* Connect to remote host */ int connect_to_remote(char *host, int port, char *error_buf, int error_len) { struct sockaddr_in sa; struct hostent *h; int server_sock; /* Initialise socket address structure */ memset(&sa, '\0', sizeof(sa)); sa.sin_family = AF_INET; /* Specify target port */ sa.sin_port = htons(port); /* If 'host' is a valid IP address, then use it */ if (inet_aton(host, &(sa.sin_addr)) == 0) { /* Otherwise 'host' might be a hostname, try to look it up */ h = gethostbyname(host); if (h == NULL) { if (error_buf) snprintf(error_buf, error_len, "Can't find address for server \'%s\'", host); return(-1); } if (h->h_addrtype != AF_INET) { if (error_buf) snprintf(error_buf, error_len, "Unsupported address family %i", h->h_addrtype); return(-1); } memcpy(&(sa.sin_addr), h->h_addr_list[0], h->h_length); } server_sock = socket(AF_INET, SOCK_STREAM, 0); if (server_sock == -1) { if (error_buf) snprintf(error_buf, error_len, "Couldn't create socket: %s", strerror(errno)); return(-1); } if (connect(server_sock, (struct sockaddr*) &sa, sizeof(sa)) == -1) { if (error_buf) snprintf(error_buf, error_len, "Couldn't connect: %s", strerror(errno)); return(-1); } return(server_sock); } /* Find and open a pty master, return slave pty name */ int get_pty_master(char **slave_name, char *error_msg, int error_len) { static char pty[32]; int c; int d; int fd; /* Template for name */ strcpy(pty, "/dev/pty**"); /* Try every pty master */ for(c = 0; c < 16; c++) { pty[8] = "pqrstuvwxyzPQRST"[c]; for(d = 0; d < 16; d++) { pty[9] = "0123456789abcdef"[d]; /* Attempt to open master */ fd = open(pty, O_RDWR); if (fd < 0) { if (errno == EIO) { continue; /* pty already in use */ } else if (errno == ENOENT) { snprintf(error_msg, error_len, "Out of ptys"); return(-1); } else { snprintf(error_msg, error_len, "Couldn't open pty master '%s': %s", pty, strerror(errno)); return(-1); } } /* Open succeeded, make tty slave name from master name */ pty[5] = 't'; *slave_name = pty; return(fd); } } snprintf(error_msg, error_len, "Out of ptys"); return(-1); } /* Open and set up ownership of slave pty */ int get_pty_slave(char *slave_name, int uid, char *error_msg, int error_len) { struct group *grp; int tty_gid; int fd; /* Get tty group name */ grp = getgrnam("tty"); if (grp == NULL) tty_gid = -1; else tty_gid = grp->gr_gid; /* Change ownership and mode of tty slave */ chown(slave_name, uid, tty_gid); chmod(slave_name, 0620); fd = open(slave_name, O_RDWR); if (fd == -1) { snprintf(error_msg, error_len, "Couldn't open pty slave '%s': %s", slave_name, strerror(errno)); return(-1); } return(fd); }