#include <sys/types.h>
#include <sys/socket.h>
#include <rpc/rpc.h>
#include <rpc/svc_dg.h>
#include <netconfig.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "rpcbind.h"
struct fdlist {
int fd;
struct netconfig *nconf;
struct fdlist *next;
int check_binding;
};
static struct fdlist *fdhead;
static struct fdlist *fdtail;
static char nullstring[] = "";
static bool_t check_bound(struct fdlist *, const char *uaddr);
static bool_t
check_bound(struct fdlist *fdl, const char *uaddr)
{
int fd;
struct netbuf *na;
int ans;
if (fdl->check_binding == FALSE)
return (TRUE);
na = uaddr2taddr(fdl->nconf, uaddr);
if (!na)
return (TRUE);
fd = __rpc_nconf2fd(fdl->nconf);
if (fd < 0) {
free(na->buf);
free(na);
return (TRUE);
}
ans = bind(fd, (struct sockaddr *)na->buf, na->len);
close(fd);
free(na->buf);
free(na);
return (ans == 0 ? FALSE : TRUE);
}
int
add_bndlist(const struct netconfig *nconf, struct netbuf *baddr __unused)
{
struct fdlist *fdl;
struct netconfig *newnconf;
newnconf = getnetconfigent(nconf->nc_netid);
if (newnconf == NULL)
return (-1);
fdl = malloc(sizeof(*fdl));
if (fdl == NULL) {
freenetconfigent(newnconf);
syslog(LOG_ERR, "no memory!");
return (-1);
}
fdl->nconf = newnconf;
fdl->next = NULL;
if (fdhead == NULL) {
fdhead = fdl;
fdtail = fdl;
} else {
fdtail->next = fdl;
fdtail = fdl;
}
fdl->check_binding = FALSE;
return 0;
}
bool_t
is_bound(const char *netid, const char *uaddr)
{
struct fdlist *fdl;
for (fdl = fdhead; fdl; fdl = fdl->next)
if (strcmp(fdl->nconf->nc_netid, netid) == 0)
break;
if (fdl == NULL)
return (TRUE);
return (check_bound(fdl, uaddr));
}
char *
mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
{
struct fdlist *fdl;
struct netbuf *callee;
char *c_uaddr, *s_uaddr, *m_uaddr, *allocated_uaddr = NULL;
for (fdl = fdhead; fdl; fdl = fdl->next)
if (strcmp(fdl->nconf->nc_netid, netid) == 0)
break;
if (fdl == NULL)
return (NULL);
if (check_bound(fdl, uaddr) == FALSE)
return (nullstring);
callee = svc_getrpccallee(xprt);
if (callee != NULL && callee->buf != NULL) {
c_uaddr = taddr2uaddr(fdl->nconf, callee);
allocated_uaddr = c_uaddr;
} else if (saddr != NULL) {
c_uaddr = saddr;
} else {
c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
allocated_uaddr = c_uaddr;
}
if (c_uaddr == NULL) {
syslog(LOG_ERR, "taddr2uaddr failed for %s",
fdl->nconf->nc_netid);
return (NULL);
}
#ifdef RPCBIND_DEBUG
if (debugging) {
if (saddr == NULL) {
fprintf(stderr, "mergeaddr: client uaddr = %s\n",
c_uaddr);
} else {
fprintf(stderr, "mergeaddr: contact uaddr = %s\n",
c_uaddr);
}
}
#endif
s_uaddr = uaddr;
m_uaddr = addrmerge(svc_getrpccaller(xprt), s_uaddr, c_uaddr, netid);
#ifdef RPCBIND_DEBUG
if (debugging)
fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n",
uaddr, m_uaddr);
#endif
free(allocated_uaddr);
return (m_uaddr);
}
struct netconfig *
rpcbind_get_conf(const char *netid)
{
struct fdlist *fdl;
for (fdl = fdhead; fdl; fdl = fdl->next)
if (strcmp(fdl->nconf->nc_netid, netid) == 0)
break;
if (fdl == NULL)
return (NULL);
return (fdl->nconf);
}