/* * Secure Network Transport Layer Library v2 implementation. * (sntllv2) it superseed all versions before due to the: * - memory consumption * - new features such as pulse emitting * - performance optimization * * This is a proprietary software. See COPYING for further details. * * (c) Askele Group 2013-2015 * */ #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #define EBADE 1 #define NETDB_SUCCESS 0 #else #include #include #include #include #endif #include #include #include #include #include static int __insert_rpc_function(usrtc_t *tree, const char *name, int (*rpcf)(void *, sexp_t *)) { cx_rpc_t *ent = malloc(sizeof(cx_rpc_t)); usrtc_node_t *node; if(!ent) return ENOMEM; else node = &ent->node; if(!(ent->name = strdup(name))) { free(ent); return ENOMEM; } else ent->rpcf = rpcf; usrtc_node_init(node, ent); usrtc_insert(tree, node, ent->name); return 0; } static void __destroy_rpc_list_tree(usrtc_t *tree) { usrtc_node_t *node; cx_rpc_t *ent; for(node = usrtc_first(tree); node != NULL; node = usrtc_first(tree)) { ent = (cx_rpc_t *)usrtc_node_getdata(node); usrtc_delete(tree, node); free(ent->name); free(ent); } return; } /* negotiation functions */ /** * Proto: (auth-set-credentials "" "") * Return - message return; opcode as a return of this function. * in batch mode message with 0 index used always */ static int __set_credentials(void *cctx, sexp_t *sx) { register int idx; conn_t *co = (conn_t *)cctx; conn_sys_t *ssys = co->ssys; sexp_t *isx; char *login = NULL; char *passwd = NULL; /* take a deal with S-exp */ SEXP_ITERATE_LIST(sx, isx, idx) { if(isx->ty == SEXP_LIST) return SNE_BADPROTO; if(idx > 0 && isx->aty != SEXP_DQUOTE) return SNE_BADPROTO; if(idx == 1) login = isx->val; else if(idx == 2) passwd = isx->val; else if(idx > 2) return SNE_BADPROTO; } if(!login || !passwd) return SNE_BADPROTO; co->pctx->login = strdup(login); co->pctx->passwd = strdup(passwd); if(!co->pctx->login || !co->pctx->passwd) { if(co->pctx->login) free(co->pctx->login); if(co->pctx->passwd) free(co->pctx->passwd); return SNE_ENOMEM; } if(ssys->secure_check) return ssys->secure_check(co); else return SNE_SUCCESS; } static int __get_channels_list(void *cctx, sexp_t *sx) { conn_t *co = (conn_t *)cctx; conn_sys_t *ssys = co->ssys; sxmsg_t *msg = co->messages[0]; char *buf = msg->payload; usrtc_node_t *node; rpc_typed_list_t *list_ent; size_t maxlen = 65535 - sizeof(sntllv2_head_t); size_t ulen = 0; /* we will avoid S-exp scanning here */ /* call the function */ if(ssys->get_rpc_typed_list_tree) co->rpc_list = ssys->get_rpc_typed_list_tree(co); if(!co->rpc_list) return SNE_EPERM; buf += sizeof(sntllv2_head_t); ulen += snprintf(buf + ulen, maxlen - ulen, "(set-channels-list "); for(node = usrtc_first(co->rpc_list); node != NULL; node = usrtc_next(co->rpc_list, node)) { /* fill the list */ list_ent = (rpc_typed_list_t *)usrtc_node_getdata(node); ulen += snprintf(buf + ulen, maxlen - ulen, "(:%d \"%s\")", list_ent->type_id, list_ent->description); } ulen += snprintf(buf + ulen, maxlen - ulen, ")"); msg->mhead.payload_length = ulen + sizeof(sntllv2_head_t); /* we're ready for messaging mode */ co->flags |= SNSX_MESSAGINGMODE; return SNE_SUCCESS; } static int __set_channels_list(void *cctx, sexp_t *sx) { register int idx; conn_t *co = (conn_t *)cctx; conn_sys_t *ssys = co->ssys; sexp_t *isx, *iisx; int id, r; SEXP_ITERATE_LIST(sx, isx, idx) { if(!idx) continue; if(isx->ty != SEXP_LIST) return SNE_BADPROTO; if(sexp_list_length(isx) != 2) return SNE_BADPROTO; /* get id */ sexp_list_car(isx, &iisx); if(iisx->ty == SEXP_LIST) return SNE_BADPROTO; if(iisx->aty != SEXP_BASIC) return SNE_BADPROTO; if(iisx->val[0] != ':') return SNE_BADPROTO; id = atoi(iisx->val + sizeof(char)); /* get short description */ sexp_list_cdr(isx, &iisx); if(iisx->ty == SEXP_LIST) return SNE_BADPROTO; if(iisx->aty != SEXP_DQUOTE) return SNE_BADPROTO; /* ok, here we go */ if(ssys->set_typed_list_callback) { r = ssys->set_typed_list_callback(co, id, iisx->val); if(r != SNE_SUCCESS) return r; } } /* we're ready for messaging mode */ co->flags |= SNSX_MESSAGINGMODE; return SNE_SUCCESS; } static int __init_systemrpc_tree(usrtc_t *rtree) { /* batch mode negotiation context functions */ if(__insert_rpc_function(rtree, "auth-set-credentials", __set_credentials)) goto __fail; if(__insert_rpc_function(rtree, "get-channels-list", __get_channels_list)) goto __fail; if(__insert_rpc_function(rtree, "set-channels-list", __set_channels_list)) goto __fail; return 0; __fail: __destroy_rpc_list_tree(rtree); return ENOMEM; } static long __cmp_cstr(const void *a, const void *b) { return (long)strcmp((const char *)a, (const char *)b); } int connections_init(conn_sys_t *ssys) { int r = 0; if(!ssys) return EINVAL; else memset(ssys, 0, sizeof(conn_sys_t)); if(!(ssys->connections = malloc(sizeof(usrtc_t)))) return ENOMEM; /* init connections list */ usrtc_init(ssys->connections, USRTC_REDBLACK, MAX_CONNECTIONS, __cmp_cstr); if((r = pthread_rwlock_init(&(ssys->rwlock), NULL))) goto __fini; /* init RPC list related functions */ if(!(ssys->system_rpc = malloc(sizeof(cx_rpc_list_t)))) { r = ENOMEM; goto __lfini; } else { if(!(ssys->system_rpc->rpc_tree = malloc(sizeof(usrtc_t)))) { r = ENOMEM; goto __lfini; } usrtc_init(ssys->system_rpc->rpc_tree, USRTC_SPLAY, 256, __cmp_cstr); r = __init_systemrpc_tree(ssys->system_rpc->rpc_tree); if(r) { free(ssys->system_rpc->rpc_tree); goto __lfini; } } return 0; __lfini: if(ssys->system_rpc) free(ssys->system_rpc); pthread_rwlock_destroy(&(ssys->rwlock)); __fini: if(ssys->connections) free(ssys->connections); return r; } conn_sys_t *connections_create(void) { int r = 0; conn_sys_t *nsys = malloc(sizeof(conn_sys_t)); if(!nsys) { errno = ENOMEM; return NULL; } r = connections_init(nsys); if(r) { errno = r; free(nsys); return NULL; } return nsys; }