304 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			304 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Secure X Message Passing Library v2 examples.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * (c) Alexander Vdolainen 2013-2015 <avdolainen@gmail.com>
							 | 
						||
| 
								 | 
							
								 * (c) Alexander Vdolainen 2016 <avdolainen@zoho.com>
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * libsxmp is free software: you can redistribute it and/or modify it
							 | 
						||
| 
								 | 
							
								 * under the terms of the GNU Lesser General Public License as published
							 | 
						||
| 
								 | 
							
								 * by the Free Software Foundation, either version 3 of the License, or
							 | 
						||
| 
								 | 
							
								 * (at your option) any later version.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * libsxmp 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 Lesser General Public License for more details.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * You should have received a copy of the GNU General Public License
							 | 
						||
| 
								 | 
							
								 * along with this program.  If not, see <http://www.gnu.org/licenses/>.";
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * This is an example of sxmp usage.
							 | 
						||
| 
								 | 
							
								 * NOTE: It was developed quite fast within one day,
							 | 
						||
| 
								 | 
							
								 * btw - this the reason of some ugly code here.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This implements a simple client-server topology, to see
							 | 
						||
| 
								 | 
							
								 * more advanced technics check out other examples.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * NOTE(win32): don't have a time to test it or fix it to
							 | 
						||
| 
								 | 
							
								 * make it works on windows, if you can - u're welcome.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <dirent.h>
							 | 
						||
| 
								 | 
							
								#define __USE_GNU
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <stdarg.h>
							 | 
						||
| 
								 | 
							
								#include <sys/types.h>
							 | 
						||
| 
								 | 
							
								#include <limits.h>
							 | 
						||
| 
								 | 
							
								#include <sys/select.h>
							 | 
						||
| 
								 | 
							
								#include <sys/wait.h>
							 | 
						||
| 
								 | 
							
								#include <sys/socket.h>
							 | 
						||
| 
								 | 
							
								#include <sys/resource.h>
							 | 
						||
| 
								 | 
							
								#include <netdb.h>
							 | 
						||
| 
								 | 
							
								#include <unistd.h>
							 | 
						||
| 
								 | 
							
								#include <uuid/uuid.h>
							 | 
						||
| 
								 | 
							
								#include <execinfo.h>
							 | 
						||
| 
								 | 
							
								#include <netinet/in.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <tdata/usrtc.h>
							 | 
						||
| 
								 | 
							
								#include <tdata/list.h>
							 | 
						||
| 
								 | 
							
								#include <sexpr/sexp.h>
							 | 
						||
| 
								 | 
							
								#include <sxmp/limits.h>
							 | 
						||
| 
								 | 
							
								#include <sxmp/sxmp.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <pthread.h>
							 | 
						||
| 
								 | 
							
								#include <stdint.h>
							 | 
						||
| 
								 | 
							
								#include <getopt.h>
							 | 
						||
| 
								 | 
							
								#include <errno.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "helpers.h"
							 | 
						||
| 
								 | 
							
								#include "smpf.h"
							 | 
						||
| 
								 | 
							
								#include "smpfd_defs.h"
							 | 
						||
| 
								 | 
							
								#include "../config.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define FULL_PROGRAM_NAME        "SMPF (secure message passing file) daemon"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static struct smpfd_ctx daemon_ctx;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* firstly we need to take an rpc calls data,
							 | 
						||
| 
								 | 
							
								 * sxmp uses usrtc from libtdata to store it
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								static usrtc_t *fulist;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* ok, here we will define out sxmp specific functions */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * RPC list contain groups of RPC calls called channel types
							 | 
						||
| 
								 | 
							
								 * for each sxmp link depends on access rules you can change
							 | 
						||
| 
								 | 
							
								 * available channel types.
							 | 
						||
| 
								 | 
							
								 * To do so you must provide a special callback returning this list.
							 | 
						||
| 
								 | 
							
								 * Since we haven't any access restrictions in our example, just
							 | 
						||
| 
								 | 
							
								 * create a fake.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								static usrtc_t *__rettlist(sxlink_t *l)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  return fulist;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Each sxmp link validated by certificate ID,
							 | 
						||
| 
								 | 
							
								 * i.e. when basic checking is done, you can also
							 | 
						||
| 
								 | 
							
								 * review the certificate ID, for example you need
							 | 
						||
| 
								 | 
							
								 * to disable certificate for a time being.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Here we don't have those checks, just always accept
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								static int __validate_sslpem(sxlink_t *l)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * To be more paranoic, sxmp also allow to
							 | 
						||
| 
								 | 
							
								 * check up username and password.
							 | 
						||
| 
								 | 
							
								 * We don't overview this tuff here, just
							 | 
						||
| 
								 | 
							
								 * always allow.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								static int __secure_check(sxlink_t *l)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  return SXE_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* remote functions implementation */
							 | 
						||
| 
								 | 
							
								/* misc functions */
							 | 
						||
| 
								 | 
							
								static int __ping(void *m, sexp_t *sx)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  return sxmsg_return((sxmsg_t*)m, SXE_SUCCESS);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* command line options helpers */
							 | 
						||
| 
								 | 
							
								static void __help_print(FILE *fso, const char *fmtname)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\n%s\n\n", FULL_PROGRAM_NAME);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* usage options */
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "Usage:\n");
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\t%s -r | --root-x509 <path> -u | --master-x509 <path> "
							 | 
						||
| 
								 | 
							
								          " [-p | --listen-port <port>] [-R | --root-dir <directory>]\n", fmtname);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* defaults */
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\t%s -h | --help\n", fmtname);
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\t%s -v | --version\n", fmtname);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* options description */
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\nOptions:\n");
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\t%-33s Set pathname of the remote root X.509 public certificate.\n",
							 | 
						||
| 
								 | 
							
								          "-r | --root-x509 <path>");
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\t%-33s Set pathname of the host X.509 public and private certificate.\n",
							 | 
						||
| 
								 | 
							
								          "-m | --master-x509 <path>");
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\t%-33s Remote host listening port number [default: %d].\n",
							 | 
						||
| 
								 | 
							
								          "-p | --listen-port <port>", DEFAULT_PORT);
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\t%-33s Remote directory becoming root for user [default: %s].\n",
							 | 
						||
| 
								 | 
							
								          "-R | --root-dir <directory>", DEFAULT_ROOT_DIR);
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\t%-33s Show help screen.\n", "-h | --help");
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\t%-33s Print version information.\n", "-v | --version");
							 | 
						||
| 
								 | 
							
								  return;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void __version_print(FILE *fso)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "\n%s.\n", FULL_PROGRAM_NAME);
							 | 
						||
| 
								 | 
							
								  fprintf(fso, "Examples bundle for %s %s.\n", PACKAGE_NAME, PACKAGE_VERSION);
							 | 
						||
| 
								 | 
							
								  return;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int main(int argc, char **argv)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  char *rootca = NULL, *cert = NULL;
							 | 
						||
| 
								 | 
							
								  char *root_dir = NULL;
							 | 
						||
| 
								 | 
							
								  sxhub_t *sxmphub = sxhub_create();
							 | 
						||
| 
								 | 
							
								  int port = DEFAULT_PORT;
							 | 
						||
| 
								 | 
							
								  int opt;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while(1) {
							 | 
						||
| 
								 | 
							
								    int option_index = 0;
							 | 
						||
| 
								 | 
							
								    static struct option long_options[] = {
							 | 
						||
| 
								 | 
							
								      /* These options a generic ones. */
							 | 
						||
| 
								 | 
							
								      {"help", no_argument, NULL, 'h'}, /* print out help and version info */
							 | 
						||
| 
								 | 
							
								      {"version", no_argument, NULL, 'v'}, /* just out a version info */
							 | 
						||
| 
								 | 
							
								      /*  The following options about settings . */
							 | 
						||
| 
								 | 
							
								      {"root-x509", required_argument, NULL, 'r'},
							 | 
						||
| 
								 | 
							
								      {"master-x509", required_argument, NULL, 'm'},
							 | 
						||
| 
								 | 
							
								      {"root-dir", required_argument, NULL, 'R'},
							 | 
						||
| 
								 | 
							
								      {"listen-port", required_argument, NULL, 'p'},
							 | 
						||
| 
								 | 
							
								      { NULL, 0, NULL, 0 },
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if((opt = getopt_long(argc, argv, "hvr:m:R:p:", long_options,
							 | 
						||
| 
								 | 
							
								                          &option_index)) == -1) break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switch(opt) {
							 | 
						||
| 
								 | 
							
								    case 'h':
							 | 
						||
| 
								 | 
							
								      __help_print(stdout, argv[0]);
							 | 
						||
| 
								 | 
							
								      return 0;
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case 'v':
							 | 
						||
| 
								 | 
							
								      __version_print(stdout);
							 | 
						||
| 
								 | 
							
								      return 0;
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case 'r':
							 | 
						||
| 
								 | 
							
								      if(!(rootca = strdup(optarg))) return ENOMEM;
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case 'm':
							 | 
						||
| 
								 | 
							
								      if(!(cert = strdup(optarg))) return ENOMEM;
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case 'p':
							 | 
						||
| 
								 | 
							
								      port = atoi(optarg);
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case 'R':
							 | 
						||
| 
								 | 
							
								      root_dir = strdup(optarg);
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if(!rootca) {
							 | 
						||
| 
								 | 
							
								    fprintf(stderr, "Root CA not pointed.\n Failure.\n");
							 | 
						||
| 
								 | 
							
								    __help_print(stderr, argv[0]);
							 | 
						||
| 
								 | 
							
								    return EINVAL;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if(!cert) {
							 | 
						||
| 
								 | 
							
								    fprintf(stderr, "User certificate not pointed.\n Failure.\n");
							 | 
						||
| 
								 | 
							
								    __help_print(stderr, argv[0]);
							 | 
						||
| 
								 | 
							
								    return EINVAL;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  sxmp_init();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* all is fine let's init connection subsystem */
							 | 
						||
| 
								 | 
							
								  if(!sxmphub) {
							 | 
						||
| 
								 | 
							
								    fprintf(stderr, "Subsystem init failed: %d\n", opt);
							 | 
						||
| 
								 | 
							
								    return 2;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  /* root directory */
							 | 
						||
| 
								 | 
							
								  if(!root_dir) {
							 | 
						||
| 
								 | 
							
								    root_dir = strdup(DEFAULT_ROOT_DIR);
							 | 
						||
| 
								 | 
							
								    if(!root_dir) {
							 | 
						||
| 
								 | 
							
								      fprintf(stderr, "Not enough memory.\n");
							 | 
						||
| 
								 | 
							
								      return 2;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  /* set working certificates */
							 | 
						||
| 
								 | 
							
								  opt = sxhub_setsslserts(sxmphub, rootca, cert, cert);
							 | 
						||
| 
								 | 
							
								  if(opt) {
							 | 
						||
| 
								 | 
							
								    fprintf(stderr, "Subsystem init failed (set SSL x.509 pems): %d\n", opt);
							 | 
						||
| 
								 | 
							
								    return opt;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* clean up */
							 | 
						||
| 
								 | 
							
								  free(rootca);
							 | 
						||
| 
								 | 
							
								  free(cert);
							 | 
						||
| 
								 | 
							
								  free(root_dir);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* set important callbacks to do the security checking */
							 | 
						||
| 
								 | 
							
								  sxhub_set_authcheck(sxmphub, __secure_check);
							 | 
						||
| 
								 | 
							
								  sxhub_set_sslvalidate(sxmphub, __validate_sslpem);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* ok, now we need to construct RPC lists (channels) */
							 | 
						||
| 
								 | 
							
								  if(!(fulist = malloc(sizeof(usrtc_t)))) {
							 | 
						||
| 
								 | 
							
								    fprintf(stderr, "Cannot allocate memory for RPC lists\n Failure.\n");
							 | 
						||
| 
								 | 
							
								    return ENOMEM;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  opt = sxmp_rpclist_init(fulist);
							 | 
						||
| 
								 | 
							
								  if(opt) {
							 | 
						||
| 
								 | 
							
								    fprintf(stderr, "Failed to init rpc list\n Failure.\n");
							 | 
						||
| 
								 | 
							
								    return opt;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* we will add one channel with type id READONLY_CHANNEL for read only operations */
							 | 
						||
| 
								 | 
							
								  opt = sxmp_rpclist_add(fulist, READONLY_CHANNEL, "Read only operations", NULL);
							 | 
						||
| 
								 | 
							
								  if(opt) {
							 | 
						||
| 
								 | 
							
								    fprintf(stderr, "Failed to add typed RPC channel\n Failure.\n");
							 | 
						||
| 
								 | 
							
								    return opt;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* ok, let's add stream functions */
							 | 
						||
| 
								 | 
							
								  opt = sxmp_rpclist_add_function(fulist, READONLY_CHANNEL, "ping", __ping);
							 | 
						||
| 
								 | 
							
								  if(opt) {
							 | 
						||
| 
								 | 
							
								    fprintf(stderr, "Failed to add functions to typed RPC channel\n Failure.\n");
							 | 
						||
| 
								 | 
							
								    return opt;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* ok, setup it */
							 | 
						||
| 
								 | 
							
								  sxhub_set_rpcvalidator(sxmphub, __rettlist);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* setup our stream */
							 | 
						||
| 
								 | 
							
								  //  sxhub_stream_register(sxmphub, &dirlist_stream);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  signal(SIGPIPE, SIG_IGN);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* now we're ready to run the listen process */
							 | 
						||
| 
								 | 
							
								  int srv = openlistener_socket(port);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while(1) {
							 | 
						||
| 
								 | 
							
								    struct sockaddr_in addr;
							 | 
						||
| 
								 | 
							
								    socklen_t len = sizeof(addr);
							 | 
						||
| 
								 | 
							
								    sxlink_t *link;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    int client = accept(srv, (struct sockaddr*)&addr, &len); /* accept connection as usual */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    link = sxlink_master_accept(sxmphub, client, NULL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if(!link) fprintf(stderr, "Cannot create sxmp link (%d)\n", errno);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  sxhub_destroy(sxmphub);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  sxmp_finalize();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return 0;
							 | 
						||
| 
								 | 
							
								}
							 |