|
|
|
/*
|
|
|
|
* Secure X Message Passing Library v2 examples.
|
|
|
|
*
|
|
|
|
* (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 is a client example for filelister implemented
|
|
|
|
* using builtin streams, available since 0.4.2
|
|
|
|
*
|
|
|
|
* 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 "filelist.h"
|
|
|
|
#include "../config.h"
|
|
|
|
|
|
|
|
#define FULL_PROGRAM_NAME "File lister client (builtin streams based)"
|
|
|
|
#include "helpers.h"
|
|
|
|
|
|
|
|
struct _remote_host {
|
|
|
|
char *root_x509;
|
|
|
|
char *user_x509;
|
|
|
|
char *hostname;
|
|
|
|
char *login;
|
|
|
|
char *password;
|
|
|
|
int port;
|
|
|
|
sxhub_t *hub;
|
|
|
|
sxlink_t *link;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _astream {
|
|
|
|
int tid;
|
|
|
|
char *longcmd;
|
|
|
|
char *short_option;
|
|
|
|
char *description;
|
|
|
|
void (*print_head)(FILE *);
|
|
|
|
void (*print_op)(FILE *, list_head_t *);
|
|
|
|
int (*exefoo)(FILE *, struct _remote_host *, struct _astream *, const char *);
|
|
|
|
};
|
|
|
|
|
|
|
|
static void __dirlist_headout(FILE *);
|
|
|
|
static void __dirlist_out(FILE *, list_head_t *);
|
|
|
|
static int __dirlist(FILE *, struct _remote_host *, struct _astream *, const char *);
|
|
|
|
|
|
|
|
struct _astream streams_source[] = {
|
|
|
|
{ .tid = DIRLIST_ID, .longcmd = "dir-list", .short_option = "e", .print_head = __dirlist_headout,
|
|
|
|
.print_op = __dirlist_out, .exefoo = __dirlist,
|
|
|
|
.description = "List directory contents on remote host" },
|
|
|
|
{ .tid = 0, .longcmd = NULL, .short_option = NULL, .print_head = NULL, .print_op = NULL,
|
|
|
|
.exefoo = NULL, .description = NULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dir listing from remote host goes below.
|
|
|
|
*/
|
|
|
|
/* printing */
|
|
|
|
static void __dirlist_headout(FILE *f)
|
|
|
|
{
|
|
|
|
fprintf(f, "%-24s | %-12s\n", "Name", "Type");
|
|
|
|
fprintf(f, "---------------------------------------\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __dirlist_out(FILE *f, list_head_t *list)
|
|
|
|
{
|
|
|
|
char *dname = NULL, *dtype = NULL;
|
|
|
|
list_node_t *iter, *siter;
|
|
|
|
struct _nn_stream_entry_node *entry;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
list_for_each_safe(list, iter, siter) {
|
|
|
|
entry = list_entry(iter, struct _nn_stream_entry_node, node);
|
|
|
|
if(!i) dname = entry->value;
|
|
|
|
else if(i == 1) dtype = entry->value;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
fprintf(f, "%-24s | %-12s\n", dname, dtype);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* command itself */
|
|
|
|
static int __dirlist(FILE *f, struct _remote_host *remote, struct _astream *rstream,
|
|
|
|
const char *opt)
|
|
|
|
{
|
|
|
|
sxlink_t *link = remote->link;
|
|
|
|
int stream_tid = rstream->tid;
|
|
|
|
sxstream_t *stream;
|
|
|
|
list_head_t *list;
|
|
|
|
|
|
|
|
rstream->print_head(f);
|
|
|
|
|
|
|
|
stream = sxstream_open(link, opt, stream_tid, SXE_O_READ);
|
|
|
|
if(!stream) {
|
|
|
|
fprintf(stderr, "Failed to open stream with %d ID (%d).\n", stream_tid, errno);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while((list = sxstream_read(stream)) != NULL)
|
|
|
|
rstream->print_op(f, list);
|
|
|
|
|
|
|
|
if(errno != SXE_EOS) {
|
|
|
|
fprintf(stderr, "Reading failed (%d)\n", errno);
|
|
|
|
}
|
|
|
|
|
|
|
|
sxstream_close(stream);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sxmp stuff below */
|
|
|
|
static int __rpcscheck_onclient(sxlink_t *l, int ch_tid, char *description)
|
|
|
|
{
|
|
|
|
return SXE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __remote_host_connect(struct _remote_host *rh)
|
|
|
|
{
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
sxhub_set_channelcall(rh->hub, __rpcscheck_onclient);
|
|
|
|
|
|
|
|
/* here we go, connect to the hist i.e. create a link to it */
|
|
|
|
rh->link = sxlink_connect(rh->hub, rh->hostname, rh->port, rh->user_x509,
|
|
|
|
rh->login, rh->password);
|
|
|
|
if(!rh->link) r = errno;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* standard output helpers */
|
|
|
|
static void __help_print(FILE *fso, const char *fmtname)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
fprintf(fso, "\n%s\n\n", FULL_PROGRAM_NAME);
|
|
|
|
|
|
|
|
/* usage options */
|
|
|
|
fprintf(fso, "Usage:\n");
|
|
|
|
for(i = 0; streams_source[i].longcmd != NULL; i++) {
|
|
|
|
fprintf(fso, "\t%s -r | --root-x509 <path> -u | --user-x509 <path> -H | --hostname <ip or hostname>"
|
|
|
|
" -l | --login <login> -P | --password <password> -%s | --%s <options>"
|
|
|
|
" [-p | --port <port>]\n", fmtname, streams_source[i].short_option,
|
|
|
|
streams_source[i].longcmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 user X.509 public and private certificate.\n",
|
|
|
|
"-u | --user-x509 <path>");
|
|
|
|
fprintf(fso, "\t%-33s Hostname or IP address of the remote host.\n", "-H | --hostname <ip or hostname>");
|
|
|
|
fprintf(fso, "\t%-33s Set remote login name.\n", "-l | --login <login>");
|
|
|
|
fprintf(fso, "\t%-33s Set remote user password.\n", "-P | --password <password>");
|
|
|
|
fprintf(fso, "\t%-33s Remote host listening port number [default: %d].\n",
|
|
|
|
"-p | --port <port>", DEFAULT_PORT);
|
|
|
|
for(i = 0; streams_source[i].longcmd != NULL; i++) {
|
|
|
|
fprintf(fso, "\t-%-2s| --%-26s %s.\n", streams_source[i].short_option,
|
|
|
|
streams_source[i].longcmd, streams_source[i].description);
|
|
|
|
}
|
|
|
|
fprintf(fso, "\t%-33s Show help screen.\n", "-h | --help");
|
|
|
|
fprintf(fso, "\t%-33s Print version information.\n", "-v | --version");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define GENERIC_OPTS "hvr:u:H:p:l:P:"
|
|
|
|
|
|
|
|
static struct option o_help = {"help", no_argument, NULL, 'h'};
|
|
|
|
static struct option o_version = {"version", no_argument, NULL, 'v'};
|
|
|
|
static struct option o_rootx509 = {"root-x509", required_argument, NULL, 'r'};
|
|
|
|
static struct option o_userx509 = {"user-x509", required_argument, NULL, 'u'};
|
|
|
|
static struct option o_hostname = {"hostname", required_argument, NULL, 'H'};
|
|
|
|
static struct option o_port = {"port", required_argument, NULL, 'p'};
|
|
|
|
static struct option o_login = {"login", required_argument, NULL, 'l'};
|
|
|
|
static struct option o_password = {"password", required_argument, NULL, 'P'};
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
char *rootca, *cert, *host, *login, *password;
|
|
|
|
char *options, *argument = NULL;
|
|
|
|
int port = DEFAULT_PORT, opt, i = 0, opt_len = 9, r = 0;
|
|
|
|
struct _remote_host *rh = malloc(sizeof(struct _remote_host));
|
|
|
|
sxhub_t *lhub;
|
|
|
|
struct _astream *src = NULL;
|
|
|
|
int (*execution)(FILE *, struct _remote_host *, struct _astream *, const char *);
|
|
|
|
static struct option *long_options;
|
|
|
|
|
|
|
|
if(!rh) return ENOMEM;
|
|
|
|
else memset(rh, 0, sizeof(struct _remote_host));
|
|
|
|
|
|
|
|
rootca = cert = host = login = password = NULL;
|
|
|
|
execution = NULL;
|
|
|
|
|
|
|
|
/* amount of builtin commands */
|
|
|
|
for(i = 0; streams_source[i].longcmd != NULL; i++) ;;
|
|
|
|
opt_len += i;
|
|
|
|
|
|
|
|
/* generate options string */
|
|
|
|
if(!(options = malloc(strlen(GENERIC_OPTS) + sizeof(char)*((i*2) + 1)))) {
|
|
|
|
free(rh);
|
|
|
|
return ENOMEM;
|
|
|
|
} else memset(options, 0, strlen(GENERIC_OPTS) + sizeof(char)*((i*2) + 1));
|
|
|
|
|
|
|
|
strcat(options, GENERIC_OPTS);
|
|
|
|
for(i = 0; streams_source[i].longcmd != NULL; i++) {
|
|
|
|
strcat(options, streams_source[i].short_option);
|
|
|
|
strcat(options, ":");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate long options */
|
|
|
|
long_options = malloc(sizeof(struct option)*opt_len);
|
|
|
|
if(!long_options) {
|
|
|
|
free(options);
|
|
|
|
free(rh);
|
|
|
|
return ENOMEM;
|
|
|
|
} else memset(long_options, 0, sizeof(struct option)*opt_len);
|
|
|
|
|
|
|
|
for(i = 0; i < opt_len; i++) {
|
|
|
|
switch(i) {
|
|
|
|
case 0: long_options[i] = o_help; break;
|
|
|
|
case 1: long_options[i] = o_version; break;
|
|
|
|
case 2: long_options[i] = o_rootx509; break;
|
|
|
|
case 3: long_options[i] = o_userx509; break;
|
|
|
|
case 4: long_options[i] = o_hostname; break;
|
|
|
|
case 5: long_options[i] = o_port; break;
|
|
|
|
case 6: long_options[i] = o_login; break;
|
|
|
|
case 7: long_options[i] = o_password; break;
|
|
|
|
default:
|
|
|
|
if(i == (opt_len - 1)) memset(&long_options[i], 0, sizeof(struct option));
|
|
|
|
else {
|
|
|
|
long_options[i].name = streams_source[i - 8].longcmd;
|
|
|
|
long_options[i].has_arg = required_argument;
|
|
|
|
long_options[i].flag = NULL;
|
|
|
|
long_options[i].val = *(streams_source[i - 8].short_option);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = ENOMEM;
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
int option_index = 0;
|
|
|
|
if((opt = getopt_long(argc, argv, (const char *)options, 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))) goto __failsafe;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
if(!(cert = strdup(optarg))) goto __failsafe;
|
|
|
|
break;
|
|
|
|
case 'H':
|
|
|
|
if(!(host = strdup(optarg))) goto __failsafe;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
if(!(login = strdup(optarg))) goto __failsafe;
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
if(!(password = strdup(optarg))) goto __failsafe;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
port = atoi(optarg);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
for(i = 0; streams_source[i].longcmd != NULL; i++) {
|
|
|
|
if(*(streams_source[i].short_option) == (char)opt) {
|
|
|
|
if(!execution) {
|
|
|
|
src = &streams_source[i];
|
|
|
|
argument = strdup(optarg);
|
|
|
|
execution = streams_source[i].exefoo;
|
|
|
|
} else {
|
|
|
|
r = EINVAL;
|
|
|
|
fprintf(stderr, "One command at once only.\n");
|
|
|
|
__help_print(stderr, argv[0]);
|
|
|
|
__failsafe:
|
|
|
|
free(options);
|
|
|
|
if(argument) free(argument);
|
|
|
|
free(long_options);
|
|
|
|
free(rh);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!execution) { r = EINVAL; goto __failsafe; }
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ok validate all before doing any stuff */
|
|
|
|
if(!rootca || !cert) {
|
|
|
|
fprintf(stderr, "One or more x.509 certificates files not pointed.\n");
|
|
|
|
__help_print(stderr, argv[0]);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
if(!login || !password) {
|
|
|
|
fprintf(stderr, "Login or password not pointed.\n");
|
|
|
|
__help_print(stderr, argv[0]);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
if(port <= 0) {
|
|
|
|
fprintf(stderr, "Port number has invalid value.\n");
|
|
|
|
__help_print(stderr, argv[0]);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
if(!execution) {
|
|
|
|
fprintf(stderr, "No command given.\n");
|
|
|
|
__help_print(stderr, argv[0]);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* looks good */
|
|
|
|
sxmp_init(); /* init library */
|
|
|
|
lhub = sxhub_create(); /* create sxhub for link creation */
|
|
|
|
if(!lhub) { r = ENOMEM; goto __failsafe; }
|
|
|
|
r = sxhub_setsslserts(lhub, rootca, cert, cert);
|
|
|
|
if(r) goto __failsafe;
|
|
|
|
|
|
|
|
/* ok setup our structure */
|
|
|
|
rh->port = port;
|
|
|
|
rh->root_x509 = rootca;
|
|
|
|
rh->user_x509 = cert;
|
|
|
|
rh->hostname = host;
|
|
|
|
rh->login = login;
|
|
|
|
rh->password = password;
|
|
|
|
rh->hub = lhub;
|
|
|
|
|
|
|
|
if((r = __remote_host_connect(rh))) {
|
|
|
|
fprintf(stderr, "Failed to create link to %s@%s:%d with %d.\n", rh->login, rh->hostname,
|
|
|
|
rh->port, r);
|
|
|
|
} else {
|
|
|
|
r = execution(stdout, rh, src, argument);
|
|
|
|
sxlink_close(rh->link);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* free all stuff */
|
|
|
|
free(options);
|
|
|
|
free(long_options);
|
|
|
|
if(rh->root_x509) free(rh->root_x509);
|
|
|
|
if(rh->user_x509) free(rh->user_x509);
|
|
|
|
if(rh->hostname) free(rh->hostname);
|
|
|
|
if(rh->password) free(rh->password);
|
|
|
|
if(rh->login) free(rh->login);
|
|
|
|
free(rh);
|
|
|
|
|
|
|
|
if(lhub) sxhub_destroy(lhub);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|