|
|
|
@ -76,10 +76,6 @@ 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.
|
|
|
|
|
*/
|
|
|
|
@ -89,11 +85,6 @@ static usrtc_t *__rettlist(sxlink_t *l)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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)
|
|
|
|
@ -102,16 +93,32 @@ static int __validate_sslpem(sxlink_t *l)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* To be more paranoic, sxmp also allow to
|
|
|
|
|
* check up username and password.
|
|
|
|
|
* We don't overview this tuff here, just
|
|
|
|
|
* always allow.
|
|
|
|
|
* don't check password and login,
|
|
|
|
|
* but assign session info for each link.
|
|
|
|
|
*/
|
|
|
|
|
static int __secure_check(sxlink_t *l)
|
|
|
|
|
{
|
|
|
|
|
struct mp_session *session;
|
|
|
|
|
|
|
|
|
|
if(!(session = malloc(sizeof(struct mp_session))))
|
|
|
|
|
return SXE_ENOMEM;
|
|
|
|
|
|
|
|
|
|
session->link = l;
|
|
|
|
|
strcpy(session->cwd, daemon_ctx.root_dir);
|
|
|
|
|
sxlink_setpriv(l, session);
|
|
|
|
|
|
|
|
|
|
return SXE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void __session_free(sxlink_t *l)
|
|
|
|
|
{
|
|
|
|
|
struct mp_session *session = (struct mp_session *)sxlink_getpriv(l);
|
|
|
|
|
|
|
|
|
|
if(session) free(session);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* remote functions implementation */
|
|
|
|
|
/* misc functions */
|
|
|
|
|
static int __ping(void *m, sexp_t *sx)
|
|
|
|
@ -155,6 +162,188 @@ static void __version_print(FILE *fso)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* control operations */
|
|
|
|
|
static int __setcwd(void *m, sexp_t *sx)
|
|
|
|
|
{
|
|
|
|
|
sxmsg_t *msg = (sxmsg_t*)m;
|
|
|
|
|
sxlink_t *link = sxmsg_link(msg);
|
|
|
|
|
char *dirname = NULL, *odir = NULL;
|
|
|
|
|
sexp_t *isx;
|
|
|
|
|
int r = SXE_SUCCESS, idx, olen = 0;
|
|
|
|
|
struct mp_session *session = (struct mp_session *)sxlink_getpriv(link);
|
|
|
|
|
|
|
|
|
|
SEXP_ITERATE_LIST(sx, isx, idx) {
|
|
|
|
|
if(isx->ty == SEXP_LIST) r = SXE_BADPROTO;
|
|
|
|
|
if(idx > 1) r = SXE_BADPROTO;
|
|
|
|
|
|
|
|
|
|
if(idx) dirname = isx->val;
|
|
|
|
|
}
|
|
|
|
|
if(r != SXE_SUCCESS || !dirname) goto __fini;
|
|
|
|
|
if(!strcmp(dirname, "./")) goto __fini;
|
|
|
|
|
if(!strlen(dirname) || !strcmp(dirname, ".")) goto __fini;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(*dirname == '/') odir = strdup(dirname);
|
|
|
|
|
else {
|
|
|
|
|
olen = strlen(session->cwd) + strlen(dirname) + 2*sizeof(char);
|
|
|
|
|
odir = malloc(olen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!odir) {
|
|
|
|
|
r = SXE_ENOMEM;
|
|
|
|
|
goto __fini;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(olen) snprintf(odir, olen, "%s/%s", session->cwd, dirname);
|
|
|
|
|
|
|
|
|
|
if(normalize_path(odir)) r = SXE_FAILED;
|
|
|
|
|
else strcpy(session->cwd, odir);
|
|
|
|
|
|
|
|
|
|
__fini:
|
|
|
|
|
if(odir) free(odir);
|
|
|
|
|
return sxmsg_return(msg, r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* readonly operations */
|
|
|
|
|
static int __getcwd(void *m, sexp_t *sx)
|
|
|
|
|
{
|
|
|
|
|
sxmsg_t *msg = (sxmsg_t*)m;
|
|
|
|
|
sxlink_t *link = sxmsg_link(msg);
|
|
|
|
|
char *rbuf = sxmsg_rapidbuf(msg);
|
|
|
|
|
size_t rbuf_len = 0;
|
|
|
|
|
struct mp_session *session = (struct mp_session *)sxlink_getpriv(link);
|
|
|
|
|
|
|
|
|
|
rbuf_len = snprintf(rbuf, MAX_RBBUF_LEN, "(\"%s\")", session->cwd);
|
|
|
|
|
|
|
|
|
|
return sxmsg_rreply(msg, rbuf_len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* stream, simple entry nonamed streams */
|
|
|
|
|
/* dir listing stream */
|
|
|
|
|
typedef struct __dirlist_type {
|
|
|
|
|
DIR *dp;
|
|
|
|
|
struct dirent dent;
|
|
|
|
|
struct dirent *dres;
|
|
|
|
|
} dirlist_t;
|
|
|
|
|
|
|
|
|
|
static int dirlist_open(sxlink_t *link, struct sxstream_opened *stream,
|
|
|
|
|
const char *dirname)
|
|
|
|
|
{
|
|
|
|
|
dirlist_t *pslist = malloc(sizeof(dirlist_t));
|
|
|
|
|
char *odir = NULL;
|
|
|
|
|
struct mp_session *session = (struct mp_session *)sxlink_getpriv(link);
|
|
|
|
|
int olen = 0;
|
|
|
|
|
|
|
|
|
|
if(!pslist) return SXE_ENOMEM;
|
|
|
|
|
else memset(pslist, 0, sizeof(dirlist_t));
|
|
|
|
|
|
|
|
|
|
if(!dirname) odir = session->cwd;
|
|
|
|
|
else if(*dirname == '/') odir = (char *)dirname;
|
|
|
|
|
else {
|
|
|
|
|
olen = strlen(dirname) + strlen(session->cwd) + 2*sizeof(char);
|
|
|
|
|
if(!(odir = malloc(olen))) {
|
|
|
|
|
free(pslist);
|
|
|
|
|
return SXE_ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snprintf(odir, olen, "%s/%s", session->cwd, dirname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!(pslist->dp = opendir(odir))) {
|
|
|
|
|
if(dirname && *dirname != '/') free(odir);
|
|
|
|
|
free(pslist);
|
|
|
|
|
return SXE_FAILED;
|
|
|
|
|
} else sxstream_opened_setpriv(stream, pslist);
|
|
|
|
|
|
|
|
|
|
if(dirname && *dirname != '/') free(odir);
|
|
|
|
|
|
|
|
|
|
return SXE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dirlist_close(struct sxstream_opened *stream)
|
|
|
|
|
{
|
|
|
|
|
dirlist_t *pslist = sxstream_opened_getpriv(stream);
|
|
|
|
|
list_head_t *llist = sxstream_opened_getelist(stream);
|
|
|
|
|
|
|
|
|
|
if(!pslist) return SXE_FAILED;
|
|
|
|
|
if(llist) sxstream_generic_slist_free(llist);
|
|
|
|
|
|
|
|
|
|
/* close dir and free strcuture */
|
|
|
|
|
if(pslist->dp) closedir(pslist->dp);
|
|
|
|
|
free(pslist);
|
|
|
|
|
|
|
|
|
|
return SXE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline const char *dump_type(struct dirent *d)
|
|
|
|
|
{
|
|
|
|
|
if(!d) return "nil";
|
|
|
|
|
|
|
|
|
|
switch(d->d_type) {
|
|
|
|
|
case DT_REG: return "regular";
|
|
|
|
|
case DT_DIR: return "directory";
|
|
|
|
|
case DT_BLK: return "block";
|
|
|
|
|
case DT_CHR: return "char";
|
|
|
|
|
case DT_FIFO: return "fifo";
|
|
|
|
|
case DT_LNK: return "link";
|
|
|
|
|
case DT_UNKNOWN: return "unknown";
|
|
|
|
|
default: return "another";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "nil";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static size_t dirlist_read(struct sxstream_opened *stream, size_t sz, uint64_t off,
|
|
|
|
|
list_head_t **rlist)
|
|
|
|
|
{
|
|
|
|
|
dirlist_t *pslist = sxstream_opened_getpriv(stream);
|
|
|
|
|
list_head_t *llist_prev = sxstream_opened_getelist(stream);
|
|
|
|
|
list_head_t *llist_new = NULL;
|
|
|
|
|
|
|
|
|
|
if(!pslist) return -1;
|
|
|
|
|
|
|
|
|
|
/* read and fill new list */
|
|
|
|
|
if(readdir_r(pslist->dp, &(pslist->dent), &(pslist->dres))) return -1;
|
|
|
|
|
|
|
|
|
|
/* if finished return 0 */
|
|
|
|
|
if(!pslist->dres) {
|
|
|
|
|
if(llist_prev) sxstream_generic_slist_free(llist_prev);
|
|
|
|
|
stream->ent_buf = NULL;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* allocate a new */
|
|
|
|
|
if(!(llist_new = sxstream_generic_slist_alloc())) return -1;
|
|
|
|
|
else { /* fill this list */
|
|
|
|
|
if(sxstream_generic_slist_additem(llist_new, pslist->dres->d_name)) {
|
|
|
|
|
__fail:
|
|
|
|
|
sxstream_generic_slist_free(llist_new);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if(sxstream_generic_slist_additem(llist_new, dump_type(pslist->dres)))
|
|
|
|
|
goto __fail;
|
|
|
|
|
}
|
|
|
|
|
/* otherwise destroy last list */
|
|
|
|
|
if(llist_prev) sxstream_generic_slist_free(llist_prev);
|
|
|
|
|
*rlist = llist_new; /* assign new list */
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct sxstream_ops dirlist_ops = {
|
|
|
|
|
.s_open = dirlist_open,
|
|
|
|
|
.s_close = dirlist_close,
|
|
|
|
|
.s_eread = dirlist_read,
|
|
|
|
|
.s_ewrite = NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct sxstream_description dirlist_stream = {
|
|
|
|
|
.stid = DIRLIST_ID,
|
|
|
|
|
.pcid = READONLY_CHANNEL,
|
|
|
|
|
.type = 0, /* just a simple one */
|
|
|
|
|
.flags = SXE_O_READ | SXE_O_TRUNC,
|
|
|
|
|
.ops = &dirlist_ops,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
char *rootca = NULL, *cert = NULL;
|
|
|
|
@ -241,11 +430,17 @@ int main(int argc, char **argv)
|
|
|
|
|
/* clean up */
|
|
|
|
|
free(rootca);
|
|
|
|
|
free(cert);
|
|
|
|
|
free(root_dir);
|
|
|
|
|
|
|
|
|
|
/* set context */
|
|
|
|
|
daemon_ctx.root_dir = root_dir;
|
|
|
|
|
daemon_ctx.root = NULL;
|
|
|
|
|
daemon_ctx.hostname = nodehostname();
|
|
|
|
|
|
|
|
|
|
/* set important callbacks to do the security checking */
|
|
|
|
|
sxhub_set_authcheck(sxmphub, __secure_check);
|
|
|
|
|
sxhub_set_sslvalidate(sxmphub, __validate_sslpem);
|
|
|
|
|
/* we using our internal session info */
|
|
|
|
|
sxhub_set_ondestroy(sxmphub, __session_free);
|
|
|
|
|
|
|
|
|
|
/* ok, now we need to construct RPC lists (channels) */
|
|
|
|
|
if(!(fulist = malloc(sizeof(usrtc_t)))) {
|
|
|
|
@ -258,26 +453,59 @@ int main(int argc, char **argv)
|
|
|
|
|
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);
|
|
|
|
|
/*
|
|
|
|
|
* Public channel
|
|
|
|
|
*/
|
|
|
|
|
opt = sxmp_rpclist_add(fulist, PUBLIC_CHANNEL, "Public channel", NULL);
|
|
|
|
|
if(opt) {
|
|
|
|
|
__failaddchannel:
|
|
|
|
|
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);
|
|
|
|
|
opt = sxmp_rpclist_add_function(fulist, PUBLIC_CHANNEL, PING_CMD, __ping);
|
|
|
|
|
if(opt) {
|
|
|
|
|
__failaddrpc:
|
|
|
|
|
fprintf(stderr, "Failed to add functions to typed RPC channel\n Failure.\n");
|
|
|
|
|
return opt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Readonly channel
|
|
|
|
|
*/
|
|
|
|
|
opt = sxmp_rpclist_add(fulist, READONLY_CHANNEL, "Read only operations", NULL);
|
|
|
|
|
if(opt) goto __failaddchannel;
|
|
|
|
|
|
|
|
|
|
/* ok, let's add read functions */
|
|
|
|
|
opt = sxmp_rpclist_add_function(fulist, READONLY_CHANNEL, CWD_CMD, __setcwd);
|
|
|
|
|
if(opt) goto __failaddrpc;
|
|
|
|
|
opt = sxmp_rpclist_add_function(fulist, READONLY_CHANNEL, GETCWD_CMD, __getcwd);
|
|
|
|
|
if(opt) goto __failaddrpc;
|
|
|
|
|
opt = sxmp_rpclist_add_function(fulist, READONLY_CHANNEL, STAT_CMD, __ping);
|
|
|
|
|
if(opt) goto __failaddrpc;
|
|
|
|
|
|
|
|
|
|
/* streams */
|
|
|
|
|
sxhub_stream_register(sxmphub, &dirlist_stream);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Write channel
|
|
|
|
|
*/
|
|
|
|
|
opt = sxmp_rpclist_add(fulist, WRITEONLY_CHANNEL, "Write only operations", NULL);
|
|
|
|
|
if(opt) goto __failaddchannel;
|
|
|
|
|
|
|
|
|
|
/* functions */
|
|
|
|
|
opt = sxmp_rpclist_add_function(fulist, WRITEONLY_CHANNEL, CREAT_CMD, __ping);
|
|
|
|
|
if(opt) goto __failaddrpc;
|
|
|
|
|
opt = sxmp_rpclist_add_function(fulist, WRITEONLY_CHANNEL, MKDIR_CMD, __ping);
|
|
|
|
|
if(opt) goto __failaddrpc;
|
|
|
|
|
opt = sxmp_rpclist_add_function(fulist, WRITEONLY_CHANNEL, RMDIR_CMD, __ping);
|
|
|
|
|
if(opt) goto __failaddrpc;
|
|
|
|
|
opt = sxmp_rpclist_add_function(fulist, WRITEONLY_CHANNEL, UNLINK_CMD, __ping);
|
|
|
|
|
if(opt) goto __failaddrpc;
|
|
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
|