900 lines
19 KiB
C
900 lines
19 KiB
C
/*
|
|
resolve.c - Resolve names to addresses
|
|
Copyright (C) 2002 Petr Vandrovec
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
Revision history:
|
|
|
|
1.00 2002, May 3 Petr Vandrovec <vandrove@vc.cvut.cz>
|
|
Initial release.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <unistd.h>
|
|
#include <netdb.h>
|
|
#include <signal.h>
|
|
#include <ctype.h>
|
|
#include <sys/time.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include <ncp/nwcalls.h>
|
|
#include <ncp/nwnet.h>
|
|
#include "ncplib_i.h"
|
|
#include "ncpcode.h"
|
|
#include "ncpi.h"
|
|
|
|
struct resolver {
|
|
const char* name;
|
|
NWCCODE (*start)(void **rh, NWCONN_HANDLE conn,
|
|
const char *name, nuint nameFormat, nuint transport);
|
|
void (*stop)(void *rh);
|
|
NWCCODE (*get)(void *rh, union ncp_sockaddr *addr,
|
|
enum NET_ADDRESS_TYPE *addrType);
|
|
};
|
|
|
|
static int safe_read(int fd, void* ptr, size_t ln) {
|
|
unsigned char* d = ptr;
|
|
|
|
while (ln != 0) {
|
|
int l;
|
|
|
|
l = read(fd, d, ln);
|
|
if (l == 0) {
|
|
return ln;
|
|
}
|
|
if (l < 0) {
|
|
if (errno == EINTR || errno == EAGAIN) {
|
|
continue;
|
|
}
|
|
return -1;
|
|
}
|
|
if ((size_t)l > ln) {
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
ln -= l;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void memcpy_toupper(char* dst, const char* src, size_t ln) {
|
|
while (ln--) {
|
|
*dst++ = toupper(*src++);
|
|
}
|
|
}
|
|
|
|
/* -------- */
|
|
|
|
#ifdef CONFIG_NATIVE_IPX
|
|
/* Bindery resolver can return only IPX addresses, so do not
|
|
use it in non-ipx environment at all */
|
|
|
|
struct bind_rh {
|
|
NWCONN_HANDLE startConn;
|
|
NWObjectType objType;
|
|
char objName[NW_MAX_SERVER_NAME_LEN];
|
|
NWObjectID lastObj;
|
|
unsigned int scan:1;
|
|
unsigned int done:1;
|
|
};
|
|
|
|
static NWCCODE bind_start(void **prh, NWCONN_HANDLE startConn,
|
|
const char *name, nuint nameFormat, nuint transport) {
|
|
struct bind_rh* rh;
|
|
NWCCODE err;
|
|
|
|
switch (transport) {
|
|
case NWCC_TRAN_TYPE_WILD:
|
|
case NWCC_TRAN_TYPE_IPX_old:
|
|
case NT_IPX:
|
|
break;
|
|
default:
|
|
return NWE_UNSUPPORTED_TRAN_TYPE;
|
|
}
|
|
if (!startConn) {
|
|
err = ncp_next_conn(NULL, &startConn);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
} else {
|
|
ncp_conn_use(startConn);
|
|
}
|
|
rh = malloc(sizeof(*rh));
|
|
if (!rh) {
|
|
NWCCCloseConn(startConn);
|
|
return ENOMEM;
|
|
}
|
|
rh->startConn = startConn;
|
|
rh->lastObj = 0xFFFFFFFF;
|
|
rh->scan = 0;
|
|
rh->done = 0;
|
|
if (nameFormat == NWCC_NAME_FORMAT_BIND) {
|
|
size_t ln;
|
|
|
|
if (!name) {
|
|
err = ERR_NULL_POINTER;
|
|
goto qRH;
|
|
}
|
|
ln = strnlen(name, NW_MAX_SERVER_NAME_LEN);
|
|
if (ln >= NW_MAX_SERVER_NAME_LEN) {
|
|
err = ENAMETOOLONG;
|
|
goto qRH;
|
|
}
|
|
memcpy_toupper(rh->objName, name, ln + 1);
|
|
rh->objType = OT_FILE_SERVER;
|
|
*prh = rh;
|
|
return 0;
|
|
} else if (nameFormat == NWCC_NAME_FORMAT_NDS_TREE) {
|
|
rh->objType = OT_TREE_NAME;
|
|
if (name) {
|
|
size_t ln;
|
|
|
|
ln = strnlen(name, NW_MAX_SERVER_NAME_LEN);
|
|
if (ln >= NW_MAX_SERVER_NAME_LEN) {
|
|
err = ENAMETOOLONG;
|
|
goto qRH;
|
|
}
|
|
memcpy_toupper(rh->objName, name, ln + 1);
|
|
if (ln <= 32) {
|
|
if (ln < 32) {
|
|
memset(rh->objName + ln, '_', 32 - ln);
|
|
}
|
|
strcpy(rh->objName + 32, "*");
|
|
rh->scan = 1;
|
|
}
|
|
} else {
|
|
strcpy(rh->objName, "*");
|
|
}
|
|
*prh = rh;
|
|
return 0;
|
|
} else {
|
|
err = NWE_UNSUPPORTED_NAME_FORMAT_TYP;
|
|
}
|
|
qRH:;
|
|
free(rh);
|
|
NWCCCloseConn(startConn);
|
|
return err;
|
|
}
|
|
|
|
static void bind_stop(void *arh) {
|
|
struct bind_rh *rh = arh;
|
|
|
|
if (rh) {
|
|
if (rh->startConn) {
|
|
NWCCCloseConn(rh->startConn);
|
|
rh->startConn = NULL;
|
|
}
|
|
free(rh);
|
|
}
|
|
}
|
|
|
|
static NWCCODE bind_get(void *arh, union ncp_sockaddr *addr,
|
|
enum NET_ADDRESS_TYPE *addrType) {
|
|
struct bind_rh *rh = arh;
|
|
NWCCODE err;
|
|
union {
|
|
unsigned char data[128];
|
|
struct prop_net_address addr;
|
|
} prop;
|
|
|
|
if (rh->done) {
|
|
return NWE_SCAN_COMPLETE;
|
|
}
|
|
if (rh->scan) {
|
|
char name[NCP_BINDERY_NAME_LEN + 1];
|
|
|
|
while ((err = NWScanObject(rh->startConn, rh->objName, rh->objType,
|
|
&rh->lastObj, name, NULL, NULL, NULL, NULL)) == 0) {
|
|
err = NWReadPropertyValue(rh->startConn, name, rh->objType,
|
|
"NET_ADDRESS", 1, prop.data, NULL, NULL);
|
|
if (!err) {
|
|
addr->ipx.sipx_family = AF_IPX;
|
|
addr->ipx.sipx_network = prop.addr.network;
|
|
addr->ipx.sipx_port = prop.addr.port;
|
|
addr->ipx.sipx_type = 0x11; /* NCP/IPX */
|
|
ipx_assign_node(addr->ipx.sipx_node, prop.addr.node);
|
|
*addrType = NT_IPX;
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
rh->done = 1;
|
|
err = NWReadPropertyValue(rh->startConn, rh->objName, rh->objType,
|
|
"NET_ADDRESS", 1, prop.data, NULL, NULL);
|
|
if (!err) {
|
|
addr->ipx.sipx_family = AF_IPX;
|
|
addr->ipx.sipx_network = prop.addr.network;
|
|
addr->ipx.sipx_port = prop.addr.port;
|
|
addr->ipx.sipx_type = 0x11; /* NCP/IPX */
|
|
ipx_assign_node(addr->ipx.sipx_node, prop.addr.node);
|
|
*addrType = NT_IPX;
|
|
}
|
|
}
|
|
rh->done = 1;
|
|
NWCCCloseConn(rh->startConn);
|
|
rh->startConn = NULL;
|
|
return err;
|
|
}
|
|
|
|
static struct resolver bind_resolver = {
|
|
"BIND",
|
|
bind_start,
|
|
bind_stop,
|
|
bind_get
|
|
};
|
|
|
|
#endif /* CONFIG_NATIVE_IPX */
|
|
|
|
/* -------- */
|
|
|
|
#ifdef CONFIG_NATIVE_IP
|
|
/* DNS resolver can currently return only IPv4 addresses (because of
|
|
IPv6 NCP stack is unavailable to public)... */
|
|
|
|
struct dns_rh {
|
|
size_t pos;
|
|
size_t size;
|
|
nuint transport;
|
|
unsigned int state:1;
|
|
u_int16_t port;
|
|
u_int32_t addresses[0];
|
|
};
|
|
|
|
static NWCCODE dns_start(void **prh, NWCONN_HANDLE startConn,
|
|
const char *name, nuint nameFormat, nuint transport) {
|
|
struct dns_rh* rh;
|
|
struct hostent* he;
|
|
u_int32_t** addresses;
|
|
u_int32_t** ptr;
|
|
u_int32_t* dst;
|
|
size_t addrcnt;
|
|
const char* portid;
|
|
int port;
|
|
|
|
switch (transport) {
|
|
case NWCC_TRAN_TYPE_WILD:
|
|
case NT_UDP:
|
|
case NT_TCP:
|
|
break;
|
|
default:
|
|
return NWE_UNSUPPORTED_TRAN_TYPE;
|
|
}
|
|
if (nameFormat != NWCC_NAME_FORMAT_BIND) {
|
|
return NWE_UNSUPPORTED_NAME_FORMAT_TYP;
|
|
}
|
|
if (!name) {
|
|
return ERR_NULL_POINTER;
|
|
}
|
|
portid = strrchr(name, ':');
|
|
if (portid) {
|
|
size_t nln;
|
|
char* n;
|
|
|
|
port = strtoul(portid + 1, NULL, 10);
|
|
if (!port) {
|
|
return NWE_PARAM_INVALID;
|
|
}
|
|
nln = portid - name;
|
|
n = malloc(nln + 1);
|
|
if (!n) {
|
|
return ENOMEM;
|
|
}
|
|
memcpy(n, name, nln);
|
|
n[nln] = 0;
|
|
he = gethostbyname(n);
|
|
free(n);
|
|
} else {
|
|
port = 524;
|
|
he = gethostbyname(name);
|
|
}
|
|
if (!he) {
|
|
return NWE_SERVER_UNKNOWN;
|
|
}
|
|
if (he->h_addrtype != AF_INET || he->h_length != 4) {
|
|
return NWE_SERVER_UNKNOWN;
|
|
}
|
|
addresses = (u_int32_t**)he->h_addr_list;
|
|
for (ptr = addresses; *ptr; ptr++) ;
|
|
addrcnt = ptr - addresses;
|
|
rh = malloc(sizeof(*rh) + sizeof(u_int32_t) * addrcnt);
|
|
if (!rh) {
|
|
return ENOMEM;
|
|
}
|
|
rh->pos = 0;
|
|
rh->size = addrcnt;
|
|
rh->transport = transport;
|
|
rh->state = 0;
|
|
rh->port = htons(port);
|
|
for (ptr = addresses, dst = rh->addresses; *ptr; ) {
|
|
*dst++ = **ptr++;
|
|
}
|
|
*prh = rh;
|
|
return 0;
|
|
}
|
|
|
|
static void dns_stop(void *arh) {
|
|
struct dns_rh *rh = arh;
|
|
|
|
if (rh) {
|
|
free(rh);
|
|
}
|
|
}
|
|
|
|
static NWCCODE dns_get(void *arh, union ncp_sockaddr *addr,
|
|
enum NET_ADDRESS_TYPE *addrType) {
|
|
struct dns_rh *rh = arh;
|
|
|
|
if (rh->pos >= rh->size) {
|
|
return NWE_SCAN_COMPLETE;
|
|
}
|
|
addr->inet.sin_family = AF_INET;
|
|
addr->inet.sin_addr.s_addr = rh->addresses[rh->pos];
|
|
addr->inet.sin_port = rh->port;
|
|
if (rh->transport != NWCC_TRAN_TYPE_WILD) {
|
|
rh->pos++;
|
|
*addrType = rh->transport;
|
|
return 0;
|
|
}
|
|
if (rh->state) {
|
|
rh->state = 0;
|
|
rh->pos++;
|
|
*addrType = NT_UDP;
|
|
return 0;
|
|
}
|
|
rh->state = 1;
|
|
*addrType = NT_TCP;
|
|
return 0;
|
|
}
|
|
|
|
static struct resolver dns_resolver = {
|
|
"DNS",
|
|
dns_start,
|
|
dns_stop,
|
|
dns_get
|
|
};
|
|
|
|
#endif /* CONFIG_NATIVE_IP */
|
|
|
|
/* -------- */
|
|
|
|
#ifdef CONFIG_NATIVE_IPX
|
|
/* SAP resolver can return only IPX addresses, so do not
|
|
use it in non-ipx environment at all */
|
|
|
|
struct sap_rh {
|
|
int fd;
|
|
pid_t pid;
|
|
unsigned int done:1;
|
|
};
|
|
|
|
static void sap_stop(void *arh) {
|
|
struct sap_rh *rh = arh;
|
|
|
|
if (rh) {
|
|
close(rh->fd);
|
|
rh->fd = -1;
|
|
/* send TERM to the resolver... */
|
|
kill(rh->pid, SIGTERM);
|
|
waitpid(rh->pid, NULL, 0);
|
|
free(rh);
|
|
}
|
|
}
|
|
|
|
static void sap_report(int fd, const struct sap_server_ident *ident) {
|
|
unsigned char answer[4 + 4 + 4 + (4 + 6 + 2)];
|
|
|
|
DSET_HL(answer, 0, 0);
|
|
DSET_HL(answer, 4, NT_IPX);
|
|
DSET_HL(answer, 8, 12);
|
|
memcpy(answer + 12, &ident->server_network, 4);
|
|
memcpy(answer + 16, ident->server_node, 6);
|
|
/* NDS reports some internal socket instead of NCP socket back */
|
|
if (WVAL_HL(ident, 0) == OT_TREE_NAME) {
|
|
WSET_HL(answer, 22, 0x0451);
|
|
} else {
|
|
memcpy(answer + 22, &ident->server_port, 2);
|
|
}
|
|
/* Immediately abort if write fails */
|
|
if (write(fd, answer, sizeof(answer)) != sizeof(answer)) {
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static int sap_name_cmp(const unsigned char *my, const unsigned char *net, size_t cmplen) {
|
|
if (memcmp(my, net, cmplen)) {
|
|
size_t ln;
|
|
|
|
/* If it is exact match, allow trailing spaces and garbage after
|
|
terminating zero. */
|
|
ln = strnlen(my, cmplen);
|
|
if (memcmp(my, net, ln)) {
|
|
return 1;
|
|
}
|
|
while (ln < cmplen && net[ln] != 0) {
|
|
if (net[ln] != ' ') {
|
|
return 1;
|
|
}
|
|
ln++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void sap_process(int fd, unsigned char *sap_request, size_t cmplen) {
|
|
struct sockaddr_ipx addr;
|
|
char rx_data[1024];
|
|
int sock;
|
|
size_t sendlen;
|
|
unsigned int expectedType;
|
|
static int one = 1;
|
|
u_int32_t u32;
|
|
size_t len;
|
|
struct timeval tv;
|
|
int retry;
|
|
int found = 0;
|
|
|
|
struct sap_server_ident *ident;
|
|
|
|
if ((sock = socket(PF_IPX, SOCK_DGRAM, IPXPROTO_IPX)) < 0) {
|
|
u32 = htonl(errno);
|
|
goto quit;
|
|
}
|
|
/* Permit broadcast output */
|
|
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) == -1) {
|
|
u32 = htonl(errno);
|
|
goto quitSock;
|
|
}
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.sipx_family = AF_IPX;
|
|
addr.sipx_type = IPX_SAP_PTYPE;
|
|
|
|
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
|
|
u32 = htonl(errno);
|
|
goto quitSock;
|
|
}
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.sipx_family = AF_IPX;
|
|
addr.sipx_port = htons(IPX_SAP_PORT);
|
|
addr.sipx_type = IPX_SAP_PTYPE;
|
|
addr.sipx_network = htonl(0x0);
|
|
ipx_assign_node(addr.sipx_node, IPX_BROADCAST_NODE);
|
|
|
|
ident = (struct sap_server_ident *) (rx_data + 2);
|
|
|
|
if (cmplen == 0) {
|
|
sendlen = 4;
|
|
expectedType = IPX_SAP_NEAREST_RESPONSE;
|
|
WSET_HL(sap_request, 0, IPX_SAP_NEAREST_QUERY);
|
|
} else {
|
|
sendlen = 60;
|
|
expectedType = IPX_SAP_SPECIFIC_RESPONSE;
|
|
WSET_HL(sap_request, 0, IPX_SAP_SPECIFIC_QUERY);
|
|
}
|
|
for (retry = 5; retry; retry--) {
|
|
unsigned int sendtime;
|
|
|
|
if (gettimeofday(&tv, NULL))
|
|
goto quitSock;
|
|
sendtime = tv.tv_sec * 1000 + tv.tv_usec / 1000 + 100; /* 100ms timeout */
|
|
|
|
if ((size_t)sendto(sock, sap_request, sendlen, 0,
|
|
(struct sockaddr *) &addr, sizeof(addr)) != sendlen) {
|
|
goto quitSock;
|
|
}
|
|
|
|
while (1) {
|
|
long err;
|
|
int recvtime;
|
|
|
|
if (gettimeofday(&tv, NULL))
|
|
goto quitSock;
|
|
|
|
recvtime = sendtime - tv.tv_sec * 1000 - tv.tv_usec / 1000;
|
|
|
|
if (recvtime < 0)
|
|
break;
|
|
|
|
err = x_recv(sock, rx_data, sizeof(rx_data), 0, recvtime, &len);
|
|
if (err) {
|
|
if (err == ETIMEDOUT)
|
|
break;
|
|
continue;
|
|
}
|
|
if (len < 66)
|
|
continue;
|
|
if (WVAL_HL(rx_data, 0) != expectedType)
|
|
continue;
|
|
if (memcmp(sap_request + 2, rx_data + 2, 2))
|
|
continue;
|
|
if (sap_name_cmp(sap_request + 4, ident->server_name, cmplen))
|
|
continue;
|
|
found = 1;
|
|
sap_report(fd, ident);
|
|
}
|
|
if (found) {
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
/* Specific/nearest query failed, try general one ... */
|
|
WSET_HL(sap_request, 0, IPX_SAP_GENERAL_QUERY);
|
|
|
|
for (retry = 5; retry; retry--) {
|
|
unsigned int sendtime;
|
|
|
|
if (gettimeofday(&tv, NULL))
|
|
goto quitSock;
|
|
sendtime = tv.tv_sec * 1000 + tv.tv_usec / 1000 + 100;
|
|
|
|
if (sendto(sock, sap_request, 4, 0,
|
|
(struct sockaddr *) &addr, sizeof(addr)) != 4) {
|
|
goto quitSock;
|
|
}
|
|
|
|
while (1) {
|
|
long err;
|
|
int recvtime;
|
|
int offs;
|
|
|
|
if (gettimeofday(&tv, NULL))
|
|
goto quitSock;
|
|
|
|
recvtime = sendtime - tv.tv_sec * 1000 - tv.tv_usec / 1000;
|
|
|
|
if (recvtime < 0)
|
|
break;
|
|
|
|
err = x_recv(sock, rx_data, sizeof(rx_data), 0, recvtime, &len);
|
|
if (err) {
|
|
if (err == ETIMEDOUT)
|
|
break;
|
|
continue;
|
|
}
|
|
if (len < 66)
|
|
continue;
|
|
if (WVAL_HL(rx_data, 0) != IPX_SAP_GENERAL_RESPONSE)
|
|
continue;
|
|
found = 1;
|
|
for (offs = 2; offs + 64 <= len; offs += 64) {
|
|
ident = (struct sap_server_ident *)(rx_data + offs);
|
|
if (memcmp(sap_request + 2, &ident->server_type, 2))
|
|
continue;
|
|
if (sap_name_cmp(sap_request + 4, ident->server_name, cmplen))
|
|
continue;
|
|
sap_report(fd, ident);
|
|
}
|
|
}
|
|
if (found) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
close(sock);
|
|
return;
|
|
quitSock:
|
|
close(sock);
|
|
quit:
|
|
write(fd, &u32, sizeof(u32));
|
|
}
|
|
|
|
static NWCCODE sap_start(void **prh, NWCONN_HANDLE startConn,
|
|
const char *name, nuint nameFormat, nuint transport) {
|
|
struct sap_rh* rh;
|
|
unsigned char sap_request[60];
|
|
size_t cmplen;
|
|
int fds[2];
|
|
int ec;
|
|
|
|
switch (transport) {
|
|
case NWCC_TRAN_TYPE_WILD:
|
|
case NWCC_TRAN_TYPE_IPX_old:
|
|
case NT_IPX:
|
|
break;
|
|
default:
|
|
return NWE_UNSUPPORTED_TRAN_TYPE;
|
|
}
|
|
memset(sap_request + 52, 0xFF, 8);
|
|
if (nameFormat == NWCC_NAME_FORMAT_BIND) {
|
|
WSET_HL(sap_request, 2, OT_FILE_SERVER);
|
|
if (!name) {
|
|
cmplen = 0;
|
|
} else {
|
|
size_t ln;
|
|
|
|
ln = strnlen(name, NW_MAX_SERVER_NAME_LEN);
|
|
if (ln >= NW_MAX_SERVER_NAME_LEN) {
|
|
return ENAMETOOLONG;
|
|
}
|
|
memcpy_toupper(sap_request + 4, name, ln);
|
|
if (ln < 48) {
|
|
memset(sap_request + 4 + ln, 0, 48 - ln);
|
|
}
|
|
cmplen = 48;
|
|
}
|
|
} else if (nameFormat == NWCC_NAME_FORMAT_NDS_TREE) {
|
|
WSET_HL(sap_request, 2, OT_TREE_NAME);
|
|
if (name) {
|
|
size_t ln;
|
|
|
|
ln = strnlen(name, NW_MAX_SERVER_NAME_LEN);
|
|
if (ln >= NW_MAX_SERVER_NAME_LEN) {
|
|
return ENAMETOOLONG;
|
|
}
|
|
memcpy_toupper(sap_request + 4, name, ln);
|
|
if (ln <= 32) {
|
|
if (ln < 32) {
|
|
memset(sap_request + 4 + ln, '_', 32 - ln);
|
|
}
|
|
sap_request[4 + 32] = '*';
|
|
memset(sap_request + 4 + 33, 0, 48 - 33);
|
|
cmplen = 32;
|
|
} else {
|
|
if (ln < 48) {
|
|
memset(sap_request + 4 + ln, 0, 48 - ln);
|
|
}
|
|
cmplen = 48;
|
|
}
|
|
} else {
|
|
cmplen = 0;
|
|
}
|
|
} else {
|
|
return NWE_UNSUPPORTED_NAME_FORMAT_TYP;
|
|
}
|
|
rh = malloc(sizeof(*rh));
|
|
if (!rh) {
|
|
return ENOMEM;
|
|
}
|
|
rh->done = 0;
|
|
if (pipe(fds)) {
|
|
free(rh);
|
|
return errno;
|
|
}
|
|
rh->pid = fork();
|
|
if (rh->pid == (pid_t)-1) {
|
|
close(fds[0]);
|
|
close(fds[1]);
|
|
free(rh);
|
|
return errno;
|
|
}
|
|
if (!rh->pid) {
|
|
int i;
|
|
sigset_t newsigset;
|
|
sigset_t oldsigset;
|
|
|
|
for (i = 3; i < 1024; i++) {
|
|
if (i != fds[1]) {
|
|
close(i);
|
|
}
|
|
}
|
|
|
|
sigemptyset(&newsigset);
|
|
sigaddset(&newsigset, SIGTERM);
|
|
sigaddset(&newsigset, SIGPIPE);
|
|
sigprocmask(SIG_UNBLOCK, &newsigset, &oldsigset);
|
|
signal(SIGTERM, SIG_DFL);
|
|
signal(SIGPIPE, SIG_DFL);
|
|
|
|
write(fds[1], "R", 1);
|
|
|
|
sap_process(fds[1], sap_request, cmplen);
|
|
exit(0);
|
|
}
|
|
rh->fd = fds[0];
|
|
close(fds[1]);
|
|
ec = safe_read(fds[0], sap_request, 1);
|
|
if (ec != 0 || sap_request[0] != 'R') {
|
|
sap_stop(rh);
|
|
return EIO;
|
|
}
|
|
*prh = rh;
|
|
return 0;
|
|
}
|
|
|
|
static NWCCODE sap_get(void *arh, union ncp_sockaddr *addr,
|
|
enum NET_ADDRESS_TYPE *addrType) {
|
|
struct sap_rh *rh = arh;
|
|
NWCCODE err;
|
|
unsigned char data[64];
|
|
int e;
|
|
u_int32_t len;
|
|
enum NET_ADDRESS_TYPE at;
|
|
|
|
nextOne:;
|
|
if (rh->done) {
|
|
return NWE_SCAN_COMPLETE;
|
|
}
|
|
e = safe_read(rh->fd, data, 4);
|
|
if (e == -1) {
|
|
rh->done = 1;
|
|
return errno;
|
|
}
|
|
if (e) {
|
|
rh->done = 1;
|
|
return NWE_SCAN_COMPLETE;
|
|
}
|
|
err = DVAL_HL(data, 0);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
e = safe_read(rh->fd, data, 8);
|
|
if (e == -1) {
|
|
rh->done = 1;
|
|
return errno;
|
|
}
|
|
if (e) {
|
|
rh->done = 1;
|
|
return NWE_SCAN_COMPLETE;
|
|
}
|
|
at = DVAL_HL(data, 0);
|
|
len = DVAL_HL(data, 4);
|
|
if (len > sizeof(data)) {
|
|
rh->done = 1;
|
|
return NWE_BUFFER_OVERFLOW;
|
|
}
|
|
e = safe_read(rh->fd, data, len);
|
|
if (e == -1) {
|
|
rh->done = 1;
|
|
return errno;
|
|
}
|
|
if (e) {
|
|
rh->done = 1;
|
|
return NWE_SCAN_COMPLETE;
|
|
}
|
|
if (at == NT_IPX) {
|
|
addr->ipx.sipx_family = AF_IPX;
|
|
memcpy(&addr->ipx.sipx_network, data, 4);
|
|
memcpy(&addr->ipx.sipx_port, data + 10, 2);
|
|
addr->ipx.sipx_type = 0x11; /* NCP/IPX */
|
|
ipx_assign_node(addr->ipx.sipx_node, data + 4);
|
|
} else {
|
|
goto nextOne;
|
|
}
|
|
*addrType = at;
|
|
return 0;
|
|
}
|
|
|
|
static struct resolver sap_resolver = {
|
|
"SAP",
|
|
sap_start,
|
|
sap_stop,
|
|
sap_get
|
|
};
|
|
|
|
#endif /* CONFIG_NATIVE_IPX */
|
|
|
|
/* -------- */
|
|
|
|
static struct resolver* resolvers[] = {
|
|
#ifdef CONFIG_NATIVE_IPX
|
|
&bind_resolver,
|
|
#endif
|
|
#ifdef CONFIG_NATIVE_IP
|
|
&dns_resolver,
|
|
#endif
|
|
#ifdef CONFIG_NATIVE_IPX
|
|
&sap_resolver,
|
|
#endif
|
|
NULL
|
|
};
|
|
|
|
static NWCCODE NWCCOpenConnByNameTran(NWCONN_HANDLE startConn, const char *serverName,
|
|
nuint nameFormat, nuint openState, nuint reserved,
|
|
nuint transport, NWCONN_HANDLE* pconn) {
|
|
NWCCODE err;
|
|
struct resolver** res;
|
|
|
|
if (reserved != NWCC_RESERVED)
|
|
return NWE_PARAM_INVALID;
|
|
for (res = resolvers; *res; res++) {
|
|
struct resolver *r = *res;
|
|
void* rdata;
|
|
|
|
err = r->start(&rdata, startConn, serverName, nameFormat, transport);
|
|
if (!err) {
|
|
while (1) {
|
|
union ncp_sockaddr server_addr;
|
|
enum NET_ADDRESS_TYPE at;
|
|
|
|
err = r->get(rdata, &server_addr, &at);
|
|
if (err == NWE_SCAN_COMPLETE) {
|
|
break;
|
|
}
|
|
if (err) {
|
|
continue;
|
|
}
|
|
err = NWCCOpenConnBySockAddr(&server_addr.any, at, openState, reserved, pconn);
|
|
if (!err) {
|
|
r->stop(rdata);
|
|
return 0;
|
|
}
|
|
}
|
|
r->stop(rdata);
|
|
}
|
|
}
|
|
return NWE_SERVER_NOT_FOUND;
|
|
}
|
|
|
|
NWCCODE NWCCOpenConnByName(NWCONN_HANDLE startConn, const char *serverName,
|
|
nuint nameFormat, nuint openState,
|
|
nuint reserved, NWCONN_HANDLE* pconn) {
|
|
return NWCCOpenConnByNameTran(startConn, serverName, nameFormat, openState, reserved, NWCC_TRAN_TYPE_WILD,
|
|
pconn);
|
|
}
|
|
|
|
NWCCODE ncp_find_server_addr(const char **serverName, int object_type, struct sockaddr* addr, socklen_t len, nuint transport) {
|
|
NWCCODE err;
|
|
NWCONN_HANDLE conn;
|
|
|
|
if (!serverName) {
|
|
return ERR_NULL_POINTER;
|
|
}
|
|
if (object_type == OT_TREE_NAME) {
|
|
object_type = NWCC_NAME_FORMAT_NDS_TREE;
|
|
} else {
|
|
object_type = NWCC_NAME_FORMAT_BIND;
|
|
}
|
|
err = NWCCOpenConnByNameTran(NULL, *serverName, object_type, NWCC_OPEN_NEW_CONN,
|
|
NWCC_RESERVED, transport, &conn);
|
|
if (!err) {
|
|
NWCCTranAddr ta;
|
|
unsigned char buffer[24];
|
|
static char sname[NCP_BINDERY_NAME_LEN + 1];
|
|
|
|
ta.len = sizeof(buffer);
|
|
ta.buffer = buffer;
|
|
|
|
err = NWCCGetConnInfo(conn, NWCC_INFO_TRAN_ADDR, sizeof(ta), &ta);
|
|
if (!err) {
|
|
if (ta.type == NT_IPX) {
|
|
struct sockaddr_ipx* ipx = (struct sockaddr_ipx*)addr;
|
|
|
|
ipx->sipx_family = AF_IPX;
|
|
memcpy(ipx->sipx_node, buffer + 4, 6);
|
|
memcpy(&ipx->sipx_network, buffer, 4);
|
|
memcpy(&ipx->sipx_port, buffer + 10, 2);
|
|
ipx->sipx_type = 0x11;
|
|
} else if (ta.type == NT_UDP || ta.type == NT_TCP) {
|
|
struct sockaddr_in* in = (struct sockaddr_in*)addr;
|
|
|
|
in->sin_family = AF_INET;
|
|
memcpy(&in->sin_addr.s_addr, buffer + 2, 4);
|
|
memcpy(&in->sin_port, buffer, 2);
|
|
} else {
|
|
err = EINVAL;
|
|
}
|
|
if (!err) {
|
|
err = NWGetFileServerName(conn, sname);
|
|
if (!err) {
|
|
*serverName = sname;
|
|
}
|
|
}
|
|
}
|
|
NWCCCloseConn(conn);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
long ncp_find_server(const char **serverName, int object_type, struct sockaddr* addr, socklen_t len) {
|
|
return ncp_find_server_addr(serverName, object_type, addr, len, NT_IPX);
|
|
}
|