// Copyright (c) Vitaliy Filippov, 2019+ // License: VNPL-1.1 (see README.md for details) // // Portmap service for NFS proxy #include #include #include "nfs_portmap.h" #include "libnfs-raw-portmap.h" #include "sha256.h" #include "base64.h" /* * The NULL procedure. All protocols/versions must provide a NULL procedure * as index 0. * It is used by clients, and rpcinfo, to "ping" a service and verify that * the service is available and that it does support the indicated version. */ static int pmap2_null_proc(struct rpc_context *rpc, struct rpc_msg *call, void *opaque) { rpc_send_reply(rpc, call, NULL, (zdrproc_t)zdr_void, 0); return 0; } /* * v2 GETPORT. * This is the lookup function for portmapper version 2. * A client provides program, version and protocol (tcp or udp) * and portmapper returns which port that service is available on, * (or 0 if no such program is registered.) */ static int pmap2_getport_proc(struct rpc_context *rpc, struct rpc_msg *call, void *opaque) { portmap_service_t *self = (portmap_service_t *)opaque; PMAP2GETPORTargs *args = (PMAP2GETPORTargs *)call->body.cbody.args; uint32_t port = 0; auto it = self->reg_ports.lower_bound((portmap_id_t){ .prog = args->prog, .vers = args->vers, .udp = args->prot == IPPROTO_UDP, .ipv6 = false, }); if (it != self->reg_ports.end() && it->prog == args->prog && it->vers == args->vers && it->udp == (args->prot == IPPROTO_UDP)) { port = it->port; } rpc_send_reply(rpc, call, &port, (zdrproc_t)zdr_uint32_t, sizeof(uint32_t)); return 0; } /* * v2 DUMP. * This RPC returns a list of all endpoints that are registered with * portmapper. */ static int pmap2_dump_proc(struct rpc_context *rpc, struct rpc_msg *call, void *opaque) { portmap_service_t *self = (portmap_service_t *)opaque; pmap2_mapping_list *list = new pmap2_mapping_list[self->reg_ports.size()]; int i = 0; for (auto it = self->reg_ports.begin(); it != self->reg_ports.end(); it++) { if (it->ipv6) continue; list[i] = { .map = { .prog = it->prog, .vers = it->vers, .prot = it->udp ? IPPROTO_UDP : IPPROTO_TCP, .port = it->port, }, .next = list+i+1, }; i++; } list[i-1].next = NULL; // Send reply PMAP2DUMPres reply; reply.list = list; rpc_send_reply(rpc, call, &reply, (zdrproc_t)zdr_PMAP2DUMPres, sizeof(PMAP2DUMPres)); reply.list = NULL; delete list; return 0; } /* * v3 GETADDR. * This is the lookup function for portmapper version 3. */ static int pmap3_getaddr_proc(struct rpc_context *rpc, struct rpc_msg *call, void *opaque) { portmap_service_t *self = (portmap_service_t *)opaque; PMAP3GETADDRargs *args = (PMAP3GETADDRargs *)call->body.cbody.args; portmap_id_t ref = (portmap_id_t){ .prog = args->prog, .vers = args->vers, .udp = !strcmp(args->netid, "udp") || !strcmp(args->netid, "udp6"), .ipv6 = !strcmp(args->netid, "tcp6") || !strcmp(args->netid, "udp6"), }; auto it = self->reg_ports.lower_bound(ref); PMAP3GETADDRres reply; if (it != self->reg_ports.end() && it->prog == ref.prog && it->vers == ref.vers && it->udp == ref.udp && it->ipv6 == ref.ipv6) { reply.addr = (char*)it->addr.c_str(); } rpc_send_reply(rpc, call, &reply, (zdrproc_t)zdr_PMAP3GETADDRres, sizeof(PMAP3GETADDRres)); return 0; } /* * v3 DUMP. * This RPC returns a list of all endpoints that are registered with * portmapper. */ static int pmap3_dump_proc(struct rpc_context *rpc, struct rpc_msg *call, void *opaque) { portmap_service_t *self = (portmap_service_t *)opaque; pmap3_mapping_list *list = new pmap3_mapping_list[self->reg_ports.size()]; int i = 0; for (auto it = self->reg_ports.begin(); it != self->reg_ports.end(); it++) { list[i] = (pmap3_mapping_list){ .map = { .prog = it->prog, .vers = it->vers, .netid = (char*)(it->ipv6 ? (it->udp ? "udp6" : "tcp6") : (it->udp ? "udp" : "tcp")), .addr = (char*)it->addr.c_str(), // 0.0.0.0.port .owner = (char*)it->owner.c_str(), }, .next = list+i+1, }; i++; } list[i-1].next = NULL; // Send reply PMAP3DUMPres reply; reply.list = list; rpc_send_reply(rpc, call, &reply, (zdrproc_t)zdr_PMAP3DUMPres, sizeof(PMAP3DUMPres)); reply.list = NULL; delete list; return 0; } portmap_service_t::portmap_service_t() { pmap2_pt.push_back((service_proc){PMAP2_NULL, pmap2_null_proc, (zdrproc_t)zdr_void, 0, this}); pmap2_pt.push_back((service_proc){PMAP2_GETPORT, pmap2_getport_proc, (zdrproc_t)zdr_PMAP2GETPORTargs, sizeof(PMAP2GETPORTargs), this}); pmap2_pt.push_back((service_proc){PMAP2_DUMP, pmap2_dump_proc, (zdrproc_t)zdr_void, 0, this}); pmap3_pt.push_back((service_proc){PMAP3_NULL, pmap2_null_proc, (zdrproc_t)zdr_void, 0, this}); pmap3_pt.push_back((service_proc){PMAP3_GETADDR, pmap3_getaddr_proc, (zdrproc_t)zdr_PMAP3GETADDRargs, sizeof(PMAP3GETADDRargs), this}); pmap3_pt.push_back((service_proc){PMAP3_DUMP, pmap3_dump_proc, (zdrproc_t)zdr_void, 0, this}); } std::string sha256(const std::string & str) { std::string hash; hash.resize(32); SHA256_CTX ctx; sha256_init(&ctx); sha256_update(&ctx, (uint8_t*)str.data(), str.size()); sha256_final(&ctx, (uint8_t*)hash.data()); return hash; }