aboutsummaryrefslogtreecommitdiff
path: root/lib/libncp
diff options
context:
space:
mode:
authorBoris Popov <bp@FreeBSD.org>1999-10-12 11:56:41 +0000
committerBoris Popov <bp@FreeBSD.org>1999-10-12 11:56:41 +0000
commitefef966da8db50f4da90b4bed651b4421d6c82f5 (patch)
tree5df7367bbf1788b36cc6e008c01b2b3fe1e5f0e9 /lib/libncp
parentcff51c813aa71405702445d52489e82674d59f08 (diff)
downloadsrc-efef966da8db50f4da90b4bed651b4421d6c82f5.tar.gz
src-efef966da8db50f4da90b4bed651b4421d6c82f5.zip
Initial import of ncp library sources.
Reviewed by: jdp, mdodd
Notes
Notes: svn path=/head/; revision=52153
Diffstat (limited to 'lib/libncp')
-rw-r--r--lib/libncp/CREDITS27
-rw-r--r--lib/libncp/Makefile24
-rw-r--r--lib/libncp/ipx.c351
-rw-r--r--lib/libncp/ipxsap.h95
-rw-r--r--lib/libncp/ncp_cfg.h9
-rw-r--r--lib/libncp/ncp_file.h92
-rw-r--r--lib/libncp/ncp_lib.h258
-rw-r--r--lib/libncp/ncp_mod.h16
-rw-r--r--lib/libncp/ncp_rcfile.h64
-rw-r--r--lib/libncp/ncpl_bind.c263
-rw-r--r--lib/libncp/ncpl_conn.c517
-rw-r--r--lib/libncp/ncpl_crypt.c137
-rw-r--r--lib/libncp/ncpl_file.c263
-rw-r--r--lib/libncp/ncpl_misc.c289
-rw-r--r--lib/libncp/ncpl_msg.c131
-rw-r--r--lib/libncp/ncpl_net.c150
-rw-r--r--lib/libncp/ncpl_nls.c272
-rw-r--r--lib/libncp/ncpl_queue.c214
-rw-r--r--lib/libncp/ncpl_rcfile.c407
-rw-r--r--lib/libncp/ncpl_rpc.c136
-rw-r--r--lib/libncp/ncpl_subr.c470
-rw-r--r--lib/libncp/sap.c302
22 files changed, 4487 insertions, 0 deletions
diff --git a/lib/libncp/CREDITS b/lib/libncp/CREDITS
new file mode 100644
index 000000000000..43380553e8f9
--- /dev/null
+++ b/lib/libncp/CREDITS
@@ -0,0 +1,27 @@
+# $FreeBSD$
+
+In the development of NetWare client for FreeBSD next sources was used:
+
+ncpfs for Linux - written by Volker Lendecke (lendecke@math.uni-goettingen.de),
+ thanks to him for giving a permission to publish his code under BSD-style
+ license.
+
+"Interrupt List" from Ralf Brown,
+
+Many files from the /sys directory.
+
+NDK documentation from Novell Inc.
+
+
+Also thanks to thouse who gets time to testing, reporting problems and give
+a good suggestions (in alphabet order):
+
+Anatoly A. Orehovsky
+Andrew Petrenko
+Jesus Rodriguez
+Matthew N. Dodd
+Mike Pitt
+Vadim Mikhailov
+
+
+Author - Boris Popov <bp@butya.kz>, <bp@freebsd.org>
diff --git a/lib/libncp/Makefile b/lib/libncp/Makefile
new file mode 100644
index 000000000000..b1170ba02cf9
--- /dev/null
+++ b/lib/libncp/Makefile
@@ -0,0 +1,24 @@
+# $FreeBSD$
+
+NCPLIB=${.CURDIR}
+
+LIB= ncp
+
+SHLIB_MAJOR= 1
+SHLIB_MINOR= 0
+
+NOMAN=
+
+SRCS= ncpl_subr.c ncpl_bind.c ncpl_queue.c ncpl_file.c ncpl_misc.c \
+ ncpl_net.c ncpl_rcfile.c ncpl_conn.c ncpl_nls.c ncpl_msg.c \
+ ncpl_rpc.c ncpl_crypt.c ipx.c sap.c
+
+HEADERS=ncp_cfg.h ncp_lib.h ncp_file.h ncp_rcfile.h
+
+beforeinstall:
+.for hdr in ${HEADERS}
+ install -c -o ${BINOWN} -g ${BINGRP} -m 0444 \
+ ${.CURDIR}/${hdr} ${DESTDIR}/usr/include/netncp
+.endfor
+
+.include <bsd.lib.mk>
diff --git a/lib/libncp/ipx.c b/lib/libncp/ipx.c
new file mode 100644
index 000000000000..9284d08469b6
--- /dev/null
+++ b/lib/libncp/ipx.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+/* IPX */
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netncp/ncp_lib.h>
+
+#define IPX_NODE_LEN 6
+
+typedef u_long IPXNet;
+typedef u_short IPXPort;
+typedef union ipx_host IPXNode;
+
+
+void
+ipx_fprint_node(FILE * file, IPXNode node){
+ fprintf(file, "%02X%02X%02X%02X%02X%02X",
+ (unsigned char) node.c_host[0],
+ (unsigned char) node.c_host[1],
+ (unsigned char) node.c_host[2],
+ (unsigned char) node.c_host[3],
+ (unsigned char) node.c_host[4],
+ (unsigned char) node.c_host[5]
+ );
+}
+
+void
+ipx_fprint_network(FILE * file, const IPXNet net){
+ fprintf(file, "%08X", (u_int32_t)ntohl(net));
+}
+
+void
+ipx_fprint_port(FILE * file, IPXPort port)
+{
+ fprintf(file, "%04X", ntohs(port));
+}
+
+void
+ipx_fprint_addr(FILE * file, struct ipx_addr *ipx)
+{
+ ipx_fprint_network(file, ipx_netlong(*ipx));
+ fprintf(file, ":");
+ ipx_fprint_node(file, ipx->x_host);
+ fprintf(file, ":");
+ ipx_fprint_port(file, ipx->x_port);
+}
+
+void
+ipx_print_node(IPXNode node)
+{
+ ipx_fprint_node(stdout, node);
+}
+
+void
+ipx_print_network(IPXNet net)
+{
+ ipx_fprint_network(stdout, net);
+}
+
+void
+ipx_print_port(IPXPort port)
+{
+ ipx_fprint_port(stdout, port);
+}
+
+void
+ipx_print_addr(struct ipx_addr *ipx)
+{
+ ipx_fprint_addr(stdout, ipx);
+}
+
+int
+ipx_sscanf_node(char *buf, unsigned char node[6])
+{
+ int i;
+ int n[6];
+
+ if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x",
+ &(n[0]), &(n[1]), &(n[2]),
+ &(n[3]), &(n[4]), &(n[5]))) != 6)
+ {
+ return i;
+ }
+ for (i = 0; i < 6; i++)
+ {
+ node[i] = n[i];
+ }
+ return 6;
+}
+
+int
+ipx_sscanf_saddr(char *buf, struct sockaddr_ipx *target)
+{
+ char *p;
+ struct sockaddr_ipx addr;
+ unsigned long sipx_net;
+
+ addr.sipx_family = AF_IPX;
+/*!! addr.sipx_type = NCP_PTYPE;*/
+
+ if (sscanf(buf, "%lx", &sipx_net) != 1)
+ {
+ return 1;
+ }
+ ((union ipx_net_u*)(&addr.sipx_addr.x_net))->long_e = htonl(sipx_net);
+ if ((p = strchr(buf, ':')) == NULL){
+ return 1;
+ }
+ p += 1;
+ if (ipx_sscanf_node(p, addr.sipx_node) != 6)
+ {
+ return 1;
+ }
+ if ((p = strchr(p, ':')) == NULL)
+ {
+ return 1;
+ }
+ p += 1;
+ if (sscanf(p, "%hx", &addr.sipx_port) != 1)
+ {
+ return 1;
+ }
+ addr.sipx_port = htons(addr.sipx_port);
+ *target = addr;
+ return 0;
+}
+
+
+void ipx_assign_node(IPXNode *dest, IPXNode *src) {
+ memcpy(dest, src, IPX_NODE_LEN);
+}
+
+
+static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
+static int if_ipxscan __P((int addrcount, struct sockaddr_dl *sdl, struct if_msghdr *ifm,
+ struct ifa_msghdr *ifam,struct ipx_addr *addr));
+
+/*
+ * Find an IPX interface.
+ * ifname specifies interface name, if NULL search for all interfaces
+ * if ifname[0]='0', also all interfaces, but return its name
+ * addr on input preferred net address can be specified or 0 for any,
+ * on return contains full address (except port)
+ * returns 0 if interface was found
+ */
+int
+ipx_iffind(char *ifname,struct ipx_addr *addr){
+ char name[32];
+ int all=0, flags, foundit = 0, addrcount;
+ struct if_msghdr *ifm, *nextifm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr_dl *sdl;
+ char *buf, *lim, *next;
+ size_t needed;
+ int mib[6];
+
+ if( ifname!=NULL ) {
+ strncpy(name,ifname,sizeof(name)-1);
+ if( name[0]==0 )
+ all=1;
+ } else
+ all = 1;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_IPX;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ return(1);
+ if ((buf = malloc(needed)) == NULL)
+ return(1);
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ free(buf);
+ return(1);
+ }
+ lim = buf + needed;
+
+ next = buf;
+ while (next < lim) {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ flags = ifm->ifm_flags;
+ } else {
+ fprintf(stderr, "if_ipxfind: out of sync parsing NET_RT_IFLIST\n");
+ fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, ifm->ifm_type);
+ fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen);
+ fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, lim);
+ free(buf);
+ return(1);
+ }
+
+ next += ifm->ifm_msglen;
+ ifam = NULL;
+ addrcount = 0;
+ while (next < lim) {
+ nextifm = (struct if_msghdr *)next;
+ if (nextifm->ifm_type != RTM_NEWADDR)
+ break;
+ if (ifam == NULL)
+ ifam = (struct ifa_msghdr *)nextifm;
+ addrcount++;
+ next += nextifm->ifm_msglen;
+ }
+
+ if (all) {
+ if ((flags & IFF_UP) == 0)
+ continue; /* not up */
+ strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
+ name[sdl->sdl_nlen] = '\0';
+ } else {
+ if (strlen(name) != sdl->sdl_nlen)
+ continue; /* not same len */
+ if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
+ continue; /* not same name */
+ }
+
+ foundit=if_ipxscan(addrcount, sdl, ifm, ifam, addr);
+ if( foundit ) {
+ if( ifname!=NULL && ifname[0]==0) {
+ strncpy(ifname,sdl->sdl_data, sdl->sdl_nlen);
+ ifname[sdl->sdl_nlen]=0;
+ }
+ break;
+ }
+ }
+ free(buf);
+
+ return foundit ? 0:1;
+}
+
+
+int
+if_ipxscan(addrcount, sdl, ifm, ifam, addr)
+ int addrcount;
+ struct sockaddr_dl *sdl;
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ struct ipx_addr *addr;
+{
+ struct rt_addrinfo info;
+ struct sockaddr_ipx *sipx;
+ int s;
+
+ if ((s = socket(AF_IPX, SOCK_DGRAM, 0)) < 0) {
+ perror("ifconfig: socket");
+ return 0;
+ }
+
+ while (addrcount > 0) {
+ info.rti_addrs = ifam->ifam_addrs;
+ /* Expand the compacted addresses */
+ rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
+ addrcount--;
+ ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
+ if (info.rti_info[RTAX_IFA]->sa_family == AF_IPX) {
+ sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_IFA];
+ if( ipx_nullnet(sipx->sipx_addr) ) continue;
+ if( ipx_nullnet(*addr) ||
+ ipx_neteq(sipx->sipx_addr,*addr) ) {
+ *addr=sipx->sipx_addr;
+ close(s);
+ return(1);
+ }
+ }
+ }
+ close(s);
+ return(0);
+}
+/*
+ * Expand the compacted form of addresses as returned via the
+ * configuration read via sysctl().
+ */
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+static void
+rt_xaddrs(cp, cplim, rtinfo)
+ caddr_t cp, cplim;
+ struct rt_addrinfo *rtinfo;
+{
+ struct sockaddr *sa;
+ int i;
+
+ memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
+ for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+ if ((rtinfo->rti_addrs & (1 << i)) == 0)
+ continue;
+ rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+ ADVANCE(cp, sa);
+ }
+}
+
diff --git a/lib/libncp/ipxsap.h b/lib/libncp/ipxsap.h
new file mode 100644
index 000000000000..2d8d7f039ec6
--- /dev/null
+++ b/lib/libncp/ipxsap.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _IPXSAP_H_
+#define _IPXSAP_H_
+
+#define IPX_SAP_GENERAL_QUERY 1
+#define IPX_SAP_GENERAL_RESPONSE 2
+#define IPX_SAP_NEAREST_QUERY 3
+#define IPX_SAP_NEAREST_RESPONSE 4
+
+
+#define IPX_SAP_MAX_ENTRIES 7
+#define IPX_SAP_SERVER_DOWN 16
+#define IPX_SAP_SERVER_NAME_LEN 48
+#define IPX_SAP_REQUEST_LEN 4
+
+/* Values for server_type */
+#define IPX_SAP_FILE_SERVER 4
+
+struct sap_query {
+ u_short query_type; /* net order */
+ u_short server_type; /* net order */
+};
+
+struct sap_entry {
+ u_short server_type;
+ u_char server_name[IPX_SAP_SERVER_NAME_LEN];
+ struct ipx_addr ipx;
+ u_short hops;
+};
+
+struct sap_packet {
+ u_short operation;
+ struct sap_entry sap_entries[1];
+};
+
+struct sap_rq {
+ struct sockaddr_ipx dest_addr;
+ int sock;
+ int entries;
+ struct sap_packet* buffer;
+};
+/*
+#define sap_name_equal(n1,n2) (strncmp(n1,n2,IPX_SAP_SERVER_NAME_LEN) == 0);
+#define sap_type_equal(t1,t2) (t1==IPX_SAP_GENERAL_RQ || t2==IPX_SAP_GENERAL_RQ || t1==t2);
+*/
+void sap_copy_name(char *dest,char *src);
+int sap_getsock(int *rsock);
+
+
+int sap_rq_init(struct sap_rq* out,int sock);
+int sap_rq_flush(struct sap_rq* out);
+void sap_rq_general(struct sap_rq* out,u_short ser_type);
+void sap_rq_gns_request(struct sap_rq* out,u_short ser_type);
+void sap_rq_response(struct sap_rq* out,u_short type,char *name,struct sockaddr_ipx* addr,u_short hops,int down_allow);
+void sap_rq_gns_response(struct sap_rq* out,u_short type,char * name,struct sockaddr_ipx* addr,u_short hops);
+void sap_rq_set_destination(struct sap_rq* out,struct ipx_addr *dest);
+
+int sap_find_nearest(int server_type, struct sockaddr_ipx *result,char *server_name);
+
+extern int (*sap_sendto_func)(void* buffer,int size,struct sockaddr_ipx* daddr,int sock);
+int ipx_iffind(char *ifname, struct ipx_addr *addr);
+
+#endif /* !_IPXSAP_H_ */
diff --git a/lib/libncp/ncp_cfg.h b/lib/libncp/ncp_cfg.h
new file mode 100644
index 000000000000..82a30d748d5d
--- /dev/null
+++ b/lib/libncp/ncp_cfg.h
@@ -0,0 +1,9 @@
+/*
+ * static configuration for libncp
+ *
+ * $FreeBSD$
+ */
+
+#define NCP_NLS_KOI2CP866
+#define NCP_NLS_DEFAULT NCP_NLS_KOI_866
+#define NCP_PREFIX ""
diff --git a/lib/libncp/ncp_file.h b/lib/libncp/ncp_file.h
new file mode 100644
index 000000000000..17b5bd5f8aec
--- /dev/null
+++ b/lib/libncp/ncp_file.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NCP_NCP_FILE_H_
+#define _NCP_NCP_FILE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ nuint32 sequence;
+ nuint32 parent;
+ nuint32 attributes;
+ nuint8 uniqueID;
+ nuint8 flags;
+ nuint8 nameSpace;
+ nuint8 nameLength;
+ nuint8 name [256];
+ nuint32 creationDateAndTime;
+ nuint32 ownerID;
+ nuint32 lastArchiveDateAndTime;
+ nuint32 lastArchiverID;
+ nuint32 updateDateAndTime;
+ nuint32 updatorID;
+ nuint32 fileSize;
+ nuint8 reserved[44];
+ nuint16 inheritedRightsMask;
+ nuint16 lastAccessDate;
+ nuint32 deletedTime;
+ nuint32 deletedDateAndTime;
+ nuint32 deletorID;
+ nuint8 reserved3 [16];
+} __attribute__((packed)) NWDELETED_INFO;
+
+int ncp_AllocTempDirHandle(char *path, NWDIR_HANDLE *pdh);
+int ncp_DeallocateDirHandle(NWDIR_HANDLE dh);
+int ncp_GetNSEntryInfo(NWDIR_HANDLE dh, struct nw_entry_info *fi, int *ns);
+
+NWCCODE ncp_ScanNSEntryInfo(NWCONN_HANDLE cH, nuint8 namSpc, nuint16 attrs,
+ SEARCH_SEQUENCE *seq, pnstr8 searchPattern, nuint32 retInfoMask,
+ NW_ENTRY_INFO *entryInfo);
+
+NWCCODE ncp_PurgeDeletedFile(NWCONN_HANDLE cH, nuint32 iterHandle,
+ nuint32 volNum, nuint32 dirBase, nuint8 ns);
+
+NWCCODE NWRecoverDeletedFile(NWCONN_HANDLE conn, NWDIR_HANDLE dirHandle,
+ nuint32 iterHandle,
+ nuint32 volNum, nuint32 dirBase,
+ pnstr8 delFileName, pnstr8 rcvrFileName);
+
+NWCCODE ncp_ScanForDeletedFiles(NWCONN_HANDLE cH, pnuint32 iterHandle,
+ pnuint32 volNum, pnuint32 dirBase, nuint8 ns,
+ NWDELETED_INFO *entryInfo);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NCP_NCP_FILE_ */
diff --git a/lib/libncp/ncp_lib.h b/lib/libncp/ncp_lib.h
new file mode 100644
index 000000000000..bff63390017a
--- /dev/null
+++ b/lib/libncp/ncp_lib.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NCP_LIB_H_
+#define _NCP_LIB_H_
+
+#define IPX
+#define INET
+
+#include <netncp/ncp.h>
+#include <netncp/ncp_conn.h>
+#include <netncp/ncp_user.h>
+#include <netncp/ncp_rq.h>
+
+#define ncp_printf printf
+
+#define sipx_cnetwork sipx_addr.x_net.c_net
+#define sipx_node sipx_addr.x_host.c_host
+#define ipx_netlong(iaddr) (((union ipx_net_u *)(&((iaddr).x_net)))->long_e)
+
+#define STDPARAM_ARGS 'A':case 'B':case 'C':case 'I':case 'M': \
+ case 'N':case 'U':case 'R':case 'S':case 'T': \
+ case 'W':case 'O':case 'P'
+
+#define STDPARAM_OPT "A:BCI:M:N:O:P:U:R:S:T:W:"
+
+#ifndef min
+#define min(a,b) (((a)<(b)) ? (a) : (b))
+#endif
+
+
+/*
+ * An attempt to do a unified options parser
+ */
+enum ncp_argtype {NCA_STR,NCA_INT,NCA_BOOL};
+
+struct ncp_args;
+
+typedef int ncp_setopt_t (struct ncp_args*);
+
+#define NAFL_NONE 0x0000
+#define NAFL_HAVEMIN 0x0001
+#define NAFL_HAVEMAX 0x0002
+#define NAFL_MINMAX NAFL_HAVEMIN | NAFL_HAVEMAX
+
+struct ncp_args {
+ enum ncp_argtype at;
+ int opt; /* command line option */
+ char *name; /* rc file equiv */
+ int flag; /* NAFL_* */
+ int ival; /* int/bool values, or max len for str value */
+ char *str; /* string value */
+ int min; /* min for ival */
+ int max; /* max for ival */
+ ncp_setopt_t *fn;/* call back to validate */
+};
+
+typedef struct {
+ nuint8 day;
+ nuint8 month;
+ nuint16 year;
+} NW_DATE;
+
+/* hours is a nuint16 so that this structure will be the same length as a dword */
+typedef struct {
+ nuint8 seconds;
+ nuint8 minutes;
+ nuint16 hours;
+} NW_TIME;
+
+struct ncp_bitname {
+ u_int bn_bit;
+ char *bn_name;
+};
+
+int ncp_args_parserc(struct ncp_args *na, char *sect, ncp_setopt_t *set_callback);
+int ncp_args_parseopt(struct ncp_args *na, int opt, char *optarg, ncp_setopt_t *set_callback);
+
+
+struct sockaddr_ipx;
+struct ipx_addr;
+struct sockaddr;
+struct ncp_buf;
+struct rcfile;
+
+int ncp_initlib(void);
+int ncp_connect(struct ncp_conn_args *li, int *connHandle);
+int ncp_connect_addr(struct sockaddr *sa, NWCONN_HANDLE *chp);
+int ncp_disconnect(int connHandle);
+int ncp_request(int connHandle,int function, struct ncp_buf *ncpbuf);
+int ncp_conn_request(int connHandle, struct ncp_buf *ncpbuf);
+int ncp_login(int connHandle, const char *user, int objtype, const char *password);
+int ncp_conn_scan(struct ncp_conn_loginfo *li, int *connHandle);
+int ncp_conn_cnt(void);
+void *ncp_conn_list(void);
+int ncp_conn_getinfo(int connHandle, struct ncp_conn_stat *ps);
+int ncp_conn_getuser(int connHandle, char **user);
+int ncp_conn2ref(int connHandle, int *connRef);
+int ncp_conn_dup(NWCONN_HANDLE org, NWCONN_HANDLE *res);
+int ncp_path2conn(char *path, int *connHandle);
+int ncp_li_init(struct ncp_conn_loginfo *li, int argc, char *argv[]);
+void ncp_li_done(struct ncp_conn_loginfo *li);
+int ncp_li_login(struct ncp_conn_loginfo *li, int *aconnHandle);
+int ncp_li_readrc(struct ncp_conn_loginfo *li);
+int ncp_li_check(struct ncp_conn_loginfo *li);
+int ncp_li_arg(struct ncp_conn_loginfo *li, int opt, char *arg);
+int ncp_li_setserver(struct ncp_conn_loginfo *li, const char *arg);
+int ncp_li_setuser(struct ncp_conn_loginfo *li, char *arg);
+int ncp_li_setpassword(struct ncp_conn_loginfo *li, const char *passwd);
+int ncp_conn_setflags(int connHandle, u_int16_t mask, u_int16_t flags);
+int ncp_conn_find(char *server, char *user);
+NWCCODE NWRequest(NWCONN_HANDLE cH, nuint16 fn,
+ nuint16 nrq, NW_FRAGMENT* rq,
+ nuint16 nrp, NW_FRAGMENT* rp) ;
+
+#define ncp_setpermanent(connHandle,on) ncp_conn_setflags(connHandle, NCPFL_PERMANENT, (on) ? NCPFL_PERMANENT : 0)
+#define ncp_setprimary(connHandle,on) ncp_conn_setflags(connHandle, NCPFL_PRIMARY, (on) ? NCPFL_PRIMARY : 0)
+
+int ncp_find_fileserver(struct ncp_conn_loginfo *li, int af,char *name);
+int ncp_find_server(struct ncp_conn_loginfo *li, int type, int af,char *name);
+
+/* misc rotines */
+char* ncp_str_upper(char *name);
+int ncp_open_rcfile(void);
+int ncp_getopt(int nargc, char * const *nargv, const char *ostr);
+void NWUnpackDateTime(nuint32 dateTime, NW_DATE *sDate, NW_TIME *sTime);
+void NWUnpackDate(nuint16 date, NW_DATE *sDate);
+void NWUnpackTime(nuint16 time, NW_TIME *sTime);
+time_t ncp_UnpackDateTime(nuint32 dateTime);
+int ncp_GetFileServerDateAndTime(NWCONN_HANDLE cH, time_t *target);
+int ncp_SetFileServerDateAndTime(NWCONN_HANDLE cH, time_t * source);
+NWCCODE NWDownFileServer(NWCONN_HANDLE cH, int force);
+NWCCODE NWCloseBindery(NWCONN_HANDLE cH);
+NWCCODE NWOpenBindery(NWCONN_HANDLE cH);
+NWCCODE NWDisableTTS(NWCONN_HANDLE cH);
+NWCCODE NWEnableTTS(NWCONN_HANDLE cH);
+NWCCODE NWDisableFileServerLogin(NWCONN_HANDLE cH);
+NWCCODE NWEnableFileServerLogin(NWCONN_HANDLE cH);
+void ncp_error(char *fmt, int error,...);
+char *ncp_printb(char *dest, int flags, const struct ncp_bitname *bnp);
+void nw_keyhash(const u_char *key, const u_char *buf, int buflen, u_char *target);
+void nw_encrypt(const u_char *fra, const u_char *buf, u_char *target);
+void ipx_print_addr(struct ipx_addr *ipx);
+
+/* bindery calls */
+int ncp_get_bindery_object_id(int connHandle, u_int16_t object_type, const char *object_name,
+ struct ncp_bindery_object *target);
+int ncp_get_bindery_object_name(int connHandle, u_int32_t object_id,
+ struct ncp_bindery_object *target);
+int ncp_scan_bindery_object(int connHandle, u_int32_t last_id, u_int16_t object_type,
+ char *search_string, struct ncp_bindery_object *target);
+int ncp_read_property_value(int connHandle,int object_type, const char *object_name,
+ int segment, const char *prop_name, struct nw_property *target);
+void shuffle(const u_char *lon, const u_char *buf, int buflen, u_char *target);
+int ncp_get_encryption_key(NWCONN_HANDLE cH, char *target);
+int ncp_change_obj_passwd(NWCONN_HANDLE connid,
+ const struct ncp_bindery_object *object,
+ const u_char *key,
+ const u_char *oldpasswd, const u_char *newpasswd);
+int ncp_keyed_verify_password(NWCONN_HANDLE cH, char *key, char *passwd,
+ struct ncp_bindery_object *objinfo);
+
+/* queue calls */
+int ncp_create_queue_job_and_file(int connHandle, u_int32_t queue_id, struct queue_job *job);
+int ncp_close_file_and_start_job(int connHandle, u_int32_t queue_id, struct queue_job *job);
+int ncp_attach_to_queue(int connHandle, u_int32_t queue_id);
+int ncp_detach_from_queue(int connHandle, u_int32_t queue_id);
+int ncp_service_queue_job(int connHandle, u_int32_t queue_id, u_int16_t job_type,
+ struct queue_job *job);
+int ncp_finish_servicing_job(int connHandle, u_int32_t queue_id, u_int32_t job_number,
+ u_int32_t charge_info);
+int ncp_abort_servicing_job(int connHandle, u_int32_t queue_id, u_int32_t job_number);
+int ncp_get_queue_length(int connHandle, u_int32_t queue_id, u_int32_t *queue_length);
+int ncp_get_queue_job_ids(int connHandle, u_int32_t queue_id, u_int32_t queue_section,
+ u_int32_t *length1, u_int32_t *length2, u_int32_t ids[]);
+int ncp_get_queue_job_info(int connHandle, u_int32_t queue_id, u_int32_t job_id,
+ struct nw_queue_job_entry *jobdata);
+/*
+ * file system and volume calls
+ */
+int ncp_read(int connHandle, ncp_fh *fh, off_t offset, size_t count, char *target);
+int ncp_write(int connHandle, ncp_fh *fh, off_t offset, size_t count, char *source);
+int ncp_geteinfo(char *path, struct nw_entry_info *fi);
+int ncp_NSEntryInfo(NWCONN_HANDLE cH, nuint8 ns, nuint8 vol, nuint32 dirent,
+ NW_ENTRY_INFO *entryInfo);
+
+NWCCODE NWGetVolumeName(NWCONN_HANDLE cH, u_char volume, char *name);
+
+/* misc ncp calls */
+int ncp_get_file_server_information(int connHandle, struct ncp_file_server_info *target);
+int ncp_get_stations_logged_info(int connHandle, u_int32_t connection,
+ struct ncp_bindery_object *target, time_t *login_time);
+int ncp_get_internet_address(int connHandle, u_int32_t connection, struct ipx_addr *target,
+ u_int8_t * conn_type);
+NWCCODE NWGetObjectConnectionNumbers(NWCONN_HANDLE connHandle,
+ pnstr8 pObjName, nuint16 objType,
+ pnuint16 pNumConns, pnuint16 pConnHandleList,
+ nuint16 maxConns);
+/*
+ * Message broadcast
+ */
+NWCCODE NWDisableBroadcasts(NWCONN_HANDLE connHandle);
+NWCCODE NWEnableBroadcasts(NWCONN_HANDLE connHandle);
+NWCCODE NWBroadcastToConsole(NWCONN_HANDLE connHandle, pnstr8 message);
+NWCCODE NWSendBroadcastMessage(NWCONN_HANDLE connHandle, pnstr8 message,
+ nuint16 connCount, pnuint16 connList, pnuint8 resultList);
+NWCCODE NWGetBroadcastMessage(NWCONN_HANDLE connHandle, pnstr8 message);
+
+/*
+ * RPC calls
+ */
+NWCCODE NWSMExecuteNCFFile(NWCONN_HANDLE cH, pnstr8 NCFFileName);
+NWCCODE NWSMLoadNLM(NWCONN_HANDLE cH, pnstr8 cmd);
+NWCCODE NWSMUnloadNLM(NWCONN_HANDLE cH, pnstr8 cmd);
+NWCCODE NWSMMountVolume(NWCONN_HANDLE cH, pnstr8 volName, nuint32* volnum);
+NWCCODE NWSMDismountVolumeByName(NWCONN_HANDLE cH, pnstr8 vol);
+NWCCODE NWSMSetDynamicCmdIntValue(NWCONN_HANDLE cH, pnstr8 setCommandName, nuint32 cmdValue);
+NWCCODE NWSMSetDynamicCmdStrValue(NWCONN_HANDLE cH, pnstr8 setCommandName, pnstr8 cmdValue);
+
+int dostat(int modnum, char *modname, int *offset);
+
+extern int ncp_opterr, ncp_optind, ncp_optopt, ncp_optreset;
+extern char *ncp_optarg;
+
+extern struct rcfile *ncp_rc;
+extern int sysentoffset;
+#endif /* _NCP_LIB_H_ */
diff --git a/lib/libncp/ncp_mod.h b/lib/libncp/ncp_mod.h
new file mode 100644
index 000000000000..4bdc39af3d07
--- /dev/null
+++ b/lib/libncp/ncp_mod.h
@@ -0,0 +1,16 @@
+/*
+ * Describes all ncp_lib kernel functions
+ *
+ * $FreeBSD$
+ */
+#ifndef _NCP_MOD_H_
+#define _NCP_MOD_H_
+
+/* order of calls in syscall table relative to offset in system table */
+#define NCP_SE(callno) (callno+sysentoffset)
+#define NCP_CONNSCAN NCP_SE(0)
+#define NCP_CONNECT NCP_SE(1)
+#define NCP_INTFN NCP_SE(2)
+#define SNCP_REQUEST NCP_SE(3)
+
+#endif /* !_NCP_MOD_H_ */ \ No newline at end of file
diff --git a/lib/libncp/ncp_rcfile.h b/lib/libncp/ncp_rcfile.h
new file mode 100644
index 000000000000..bbdf8eb3dfe4
--- /dev/null
+++ b/lib/libncp/ncp_rcfile.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NCP_RCFILE_H_
+#define _NCP_RCFILE_H_
+#include <sys/queue.h>
+
+struct rckey {
+ SLIST_ENTRY(rckey) rk_next;
+ char *rk_name;
+ char *rk_value;
+};
+
+struct rcsection {
+ SLIST_ENTRY(rcsection) rs_next;
+ SLIST_HEAD(rckey_head,rckey) rs_keys;
+ char *rs_name;
+};
+
+struct rcfile {
+ SLIST_ENTRY(rcfile) rf_next;
+ SLIST_HEAD(rcsec_head, rcsection) rf_sect;
+ char *rf_name;
+ FILE *rf_f;
+};
+
+int rc_open(char *filename,char *mode,struct rcfile **rcfile);
+int rc_close(struct rcfile *rcp);
+int rc_getstringptr(struct rcfile *rcp,char *section, char *key,char **dest);
+int rc_getstring(struct rcfile *rcp,char *section, char *key,int maxlen,char *dest);
+int rc_getint(struct rcfile *rcp,char *section, char *key,int *value);
+int rc_getbool(struct rcfile *rcp,char *section, char *key,int *value);
+
+#endif /* _NCP_RCFILE_H_ */
diff --git a/lib/libncp/ncpl_bind.c b/lib/libncp/ncpl_bind.c
new file mode 100644
index 000000000000..40d0b7358eac
--- /dev/null
+++ b/lib/libncp/ncpl_bind.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+#include <netncp/ncp_lib.h>
+
+static void nw_passencrypt(char *old, char *new, char *out);
+
+int
+ncp_get_bindery_object_id(int connid, u_int16_t object_type, const char *object_name,
+ struct ncp_bindery_object *target) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 53);
+ ncp_add_word_hl(conn, object_type);
+ ncp_add_pstring(conn, object_name);
+
+ if ((error = ncp_request(connid, 23, conn)) != 0) {
+ return error;
+ }
+ if (conn->rpsize < 54) {
+ return EACCES;
+ }
+ target->object_id = ncp_reply_dword_hl(conn, 0);
+ target->object_type = ncp_reply_word_hl(conn, 4);
+ memcpy(target->object_name, ncp_reply_data(conn, 6), 48);
+ return 0;
+}
+
+int
+ncp_read_property_value(int connid, int object_type, const char *object_name,
+ int segment, const char *prop_name,
+ struct nw_property *target)
+{
+ int error;
+ struct ncp_buf conn;
+ ncp_init_request_s(&conn, 61);
+ ncp_add_word_hl(&conn, object_type);
+ ncp_add_pstring(&conn, object_name);
+ ncp_add_byte(&conn, segment);
+ ncp_add_pstring(&conn, prop_name);
+
+ if ((error = ncp_request(connid,23,&conn)) != 0) {
+ return error;
+ }
+ memcpy(&(target->value), ncp_reply_data(&conn, 0), 128);
+ target->more_flag = ncp_reply_byte(&conn, 128);
+ target->property_flag = ncp_reply_byte(&conn, 129);
+ return 0;
+}
+
+int
+ncp_scan_bindery_object(int connid, u_int32_t last_id, u_int16_t object_type,
+ char *search_string, struct ncp_bindery_object *target)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 55);
+ ncp_add_dword_hl(conn, last_id);
+ ncp_add_word_hl(conn, object_type);
+ ncp_add_pstring(conn, search_string);
+ error = ncp_request(connid, 23, conn);
+ if (error) return error;
+ target->object_id = ncp_reply_dword_hl(conn, 0);
+ target->object_type = ncp_reply_word_hl(conn, 4);
+ memcpy(target->object_name, ncp_reply_data(conn, 6),NCP_BINDERY_NAME_LEN);
+ target->object_flags = ncp_reply_byte(conn, 54);
+ target->object_security = ncp_reply_byte(conn, 55);
+ target->object_has_prop = ncp_reply_byte(conn, 56);
+ return 0;
+}
+
+int
+ncp_get_bindery_object_name(int connid, u_int32_t object_id,
+ struct ncp_bindery_object *target) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 54);
+ ncp_add_dword_hl(conn, object_id);
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ target->object_id = ncp_reply_dword_hl(conn, 0);
+ target->object_type = ncp_reply_word_hl(conn, 4);
+ memcpy(target->object_name, ncp_reply_data(conn, 6), 48);
+ return 0;
+}
+
+int
+ncp_change_obj_passwd(NWCONN_HANDLE connid,
+ const struct ncp_bindery_object *object,
+ const u_char *key,
+ const u_char *oldpasswd,
+ const u_char *newpasswd)
+{
+ long id = htonl(object->object_id);
+ u_char cryptkey[8];
+ u_char newpwd[16]; /* new passwd as stored by server */
+ u_char oldpwd[16]; /* old passwd as stored by server */
+ u_char len;
+ DECLARE_RQ;
+
+ memcpy(cryptkey, key, 8);
+ nw_keyhash((u_char *)&id, oldpasswd, strlen(oldpasswd), oldpwd);
+ nw_keyhash((u_char *)&id, newpasswd, strlen(newpasswd), newpwd);
+ nw_encrypt(cryptkey, oldpwd, cryptkey);
+ nw_passencrypt(oldpwd, newpwd, newpwd);
+ nw_passencrypt(oldpwd + 8, newpwd + 8, newpwd + 8);
+ if ((len = strlen(newpasswd)) > 63) {
+ len = 63;
+ }
+ len = ((len ^ oldpwd[0] ^ oldpwd[1]) & 0x7f) | 0x40;
+
+ ncp_init_request_s(conn, 75);
+ ncp_add_mem(conn, cryptkey, 8);
+ ncp_add_word_hl(conn, object->object_type);
+ ncp_add_pstring(conn, object->object_name);
+ ncp_add_byte(conn, len);
+ ncp_add_mem(conn, newpwd, 16);
+ return ncp_request(connid, 23, conn);
+}
+
+/*
+ * target is a 8-byte buffer
+ */
+int
+ncp_get_encryption_key(NWCONN_HANDLE cH, char *target) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 23);
+
+ error = ncp_request(cH, 23, conn);
+ if (error)
+ return error;
+ if (conn->rpsize < 8)
+ return EACCES;
+ memcpy(target, ncp_reply_data(conn, 0), 8);
+ return 0;
+}
+
+int
+ncp_keyed_verify_password(NWCONN_HANDLE cH, char *key, char *passwd,
+ struct ncp_bindery_object *objinfo) {
+ u_long id = htonl(objinfo->object_id);
+ u_char cryptkey[8];
+ u_char buf[128];
+ DECLARE_RQ;
+
+ nw_keyhash((u_char *)&id, passwd, strlen(passwd), buf);
+ nw_encrypt(key, buf, cryptkey);
+
+ ncp_init_request_s(conn, 74);
+ ncp_add_mem(conn, cryptkey, sizeof(cryptkey));
+ ncp_add_word_hl(conn, objinfo->object_type);
+ ncp_add_pstring(conn, objinfo->object_name);
+
+ return ncp_request(cH, 23, conn);
+}
+
+static char passkeys[256 + 16] = {
+ 0x0f, 0x08, 0x05, 0x07, 0x0c, 0x02, 0x0e, 0x09,
+ 0x00, 0x01, 0x06, 0x0d, 0x03, 0x04, 0x0b, 0x0a,
+ 0x02, 0x0c, 0x0e, 0x06, 0x0f, 0x00, 0x01, 0x08,
+ 0x0d, 0x03, 0x0a, 0x04, 0x09, 0x0b, 0x05, 0x07,
+ 0x05, 0x02, 0x09, 0x0f, 0x0c, 0x04, 0x0d, 0x00,
+ 0x0e, 0x0a, 0x06, 0x08, 0x0b, 0x01, 0x03, 0x07,
+ 0x0f, 0x0d, 0x02, 0x06, 0x07, 0x08, 0x05, 0x09,
+ 0x00, 0x04, 0x0c, 0x03, 0x01, 0x0a, 0x0b, 0x0e,
+ 0x05, 0x0e, 0x02, 0x0b, 0x0d, 0x0a, 0x07, 0x00,
+ 0x08, 0x06, 0x04, 0x01, 0x0f, 0x0c, 0x03, 0x09,
+ 0x08, 0x02, 0x0f, 0x0a, 0x05, 0x09, 0x06, 0x0c,
+ 0x00, 0x0b, 0x01, 0x0d, 0x07, 0x03, 0x04, 0x0e,
+ 0x0e, 0x08, 0x00, 0x09, 0x04, 0x0b, 0x02, 0x07,
+ 0x0c, 0x03, 0x0a, 0x05, 0x0d, 0x01, 0x06, 0x0f,
+ 0x01, 0x04, 0x08, 0x0a, 0x0d, 0x0b, 0x07, 0x0e,
+ 0x05, 0x0f, 0x03, 0x09, 0x00, 0x02, 0x06, 0x0c,
+ 0x05, 0x03, 0x0c, 0x08, 0x0b, 0x02, 0x0e, 0x0a,
+ 0x04, 0x01, 0x0d, 0x00, 0x06, 0x07, 0x0f, 0x09,
+ 0x06, 0x00, 0x0b, 0x0e, 0x0d, 0x04, 0x0c, 0x0f,
+ 0x07, 0x02, 0x08, 0x0a, 0x01, 0x05, 0x03, 0x09,
+ 0x0b, 0x05, 0x0a, 0x0e, 0x0f, 0x01, 0x0c, 0x00,
+ 0x06, 0x04, 0x02, 0x09, 0x03, 0x0d, 0x07, 0x08,
+ 0x07, 0x02, 0x0a, 0x00, 0x0e, 0x08, 0x0f, 0x04,
+ 0x0c, 0x0b, 0x09, 0x01, 0x05, 0x0d, 0x03, 0x06,
+ 0x07, 0x04, 0x0f, 0x09, 0x05, 0x01, 0x0c, 0x0b,
+ 0x00, 0x03, 0x08, 0x0e, 0x02, 0x0a, 0x06, 0x0d,
+ 0x09, 0x04, 0x08, 0x00, 0x0a, 0x03, 0x01, 0x0c,
+ 0x05, 0x0f, 0x07, 0x02, 0x0b, 0x0e, 0x06, 0x0d,
+ 0x09, 0x05, 0x04, 0x07, 0x0e, 0x08, 0x03, 0x01,
+ 0x0d, 0x0b, 0x0c, 0x02, 0x00, 0x0f, 0x06, 0x0a,
+ 0x09, 0x0a, 0x0b, 0x0d, 0x05, 0x03, 0x0f, 0x00,
+ 0x01, 0x0c, 0x08, 0x07, 0x06, 0x04, 0x0e, 0x02,
+ 0x03, 0x0e, 0x0f, 0x02, 0x0d, 0x0c, 0x04, 0x05,
+ 0x09, 0x06, 0x00, 0x01, 0x0b, 0x07, 0x0a, 0x08
+};
+
+static void
+nw_passencrypt(char *old, char *new, char *out)
+{
+ char *p, v;
+ char copy[8];
+ int i, di, ax;
+
+#define HIGH(x) (((x) >> 4) & 0xf)
+#define LOW(x) ((x) & 0xf)
+ memcpy(copy, new, 8);
+
+ for (i = 0; i < 16; i++) {
+ for (di = 0, ax = 0, p = old; di < 8; di++, ax += 0x20, p++) {
+ v = copy[di] ^ *p;
+ copy[di] = (passkeys[HIGH(v) + ax + 0x10] << 4) |
+ passkeys[LOW(v) + ax];
+ }
+ v = old[7];
+ for (p = old + 7; p > old; p--) {
+ *p = HIGH(p[-1]) | ((*p) << 4);
+ }
+ *old = HIGH(v) | (*old) << 4;
+ bzero(out, 8);
+
+ for (di = 0; di < 16; di++) {
+ v = passkeys[di + 0x100];
+ v = (v & 1) ? HIGH(copy[v / 2]) : LOW(copy[v / 2]);
+ out[di / 2] |= ((di & 1) ? v << 4 : v);
+ }
+ memcpy(copy, out, 8);
+ }
+}
diff --git a/lib/libncp/ncpl_conn.c b/lib/libncp/ncpl_conn.c
new file mode 100644
index 000000000000..df9580733169
--- /dev/null
+++ b/lib/libncp/ncpl_conn.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ *
+ * Current scheme to create/open connection:
+ * 1. ncp_li_init() - lookup -S [-U] options in command line
+ * 2. ncp_li_init() - try to find existing connection
+ * 3. ncp_li_init() - if no server name and no accessible connections - bail out
+ * 4. This is connection candidate, read .rc file, override with command line
+ * and go ahead
+ * Note: connection referenced only via ncp_login() call. Although it is
+ * possible to get connection handle in other way, it will be unwise to use
+ * it, since conn can be destroyed at any time.
+ *
+ */
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_rcfile.h>
+#include <nwfs/nwfs.h>
+
+static char *server_name; /* need a better way ! */
+
+
+
+int
+ncp_li_setserver(struct ncp_conn_loginfo *li, const char *arg) {
+ if (strlen(arg) >= NCP_BINDERY_NAME_LEN) {
+ fprintf(stderr, "Server name too long:%s\n", arg);
+ return ENAMETOOLONG;
+ }
+ ncp_str_upper(strcpy(li->server, arg));
+ return 0;
+}
+
+int
+ncp_li_setuser(struct ncp_conn_loginfo *li, char *arg) {
+ if (arg && strlen(arg) >= NCP_BINDERY_NAME_LEN) {
+ fprintf(stderr, "User name too long:%s\n", arg);
+ return ENAMETOOLONG;
+ }
+ if (li->user)
+ free(li->user);
+ if (arg) {
+ li->user = strdup(arg);
+ if (li->user == NULL)
+ return ENOMEM;
+ ncp_str_upper(li->user);
+ } else
+ li->user = NULL;
+ return 0;
+}
+
+int
+ncp_li_setpassword(struct ncp_conn_loginfo *li, const char *passwd) {
+ if (passwd && strlen(passwd) >= 127) {
+ fprintf(stderr, "Password too long:%s\n", passwd);
+ return ENAMETOOLONG;
+ }
+ if (li->password) {
+ bzero(li->password, strlen(li->password));
+ free(li->password);
+ }
+ if (passwd) {
+ li->password = strdup(passwd);
+ if (li->password == NULL)
+ return ENOMEM;
+ } else
+ li->password = NULL;
+ return 0;
+}
+/*
+ * Prescan command line for [-S server] [-U user] arguments
+ * and fill li structure with defaults
+ */
+int
+ncp_li_init(struct ncp_conn_loginfo *li, int argc, char *argv[]) {
+ int opt, error = 0;
+ char *arg;
+
+ bzero(li,sizeof(*li));
+ li->timeout = 15; /* these values should be large enough to handle */
+ li->retry_count = 4; /* slow servers, even on ethernet */
+ li->access_mode = 0;
+ li->password = NULL;
+ li->sig_level = 1;
+ li->objtype = NCP_BINDERY_USER;
+ li->owner = NCP_DEFAULT_OWNER;
+ li->group = NCP_DEFAULT_GROUP;
+ server_name = NULL;
+ if (argv == NULL) return 0;
+ while ((opt = ncp_getopt(argc, argv, ":S:U:")) != -1) {
+ arg = ncp_optarg;
+ switch (opt) {
+ case 'S':
+ error = ncp_li_setserver(li, arg);
+ break;
+ case 'U':
+ error = ncp_li_setuser(li, arg);
+ break;
+ }
+ }
+ ncp_optind = ncp_optreset = 1;
+ return error;
+}
+
+void
+ncp_li_done(struct ncp_conn_loginfo *li) {
+ if (li->user)
+ free(li->user);
+ if (li->password)
+ free(li->password);
+}
+
+/*
+ * Lookup existing connection based on li structure, if connection
+ * found, it will be referenced. Otherwise full login sequence performed.
+ */
+int
+ncp_li_login(struct ncp_conn_loginfo *li, int *aconnid) {
+ int connHandle, error;
+
+ if ((error = ncp_conn_scan(li, &connHandle)) == 0) {
+ *aconnid = connHandle;
+ return 0;
+ }
+ error = ncp_connect(li, &connHandle);
+ if (error) return errno;
+ error = ncp_login(connHandle, li->user, li->objtype, li->password);
+ if (error) {
+ ncp_disconnect(connHandle);
+ } else
+ *aconnid = connHandle;
+ return error;
+}
+
+/*
+ * read rc file as follows:
+ * 1. read [server] section
+ * 2. override with [server:user] section
+ * Since abcence of rcfile is not a bug, silently ignore that fact.
+ * rcfile never closed to reduce number of open/close operations.
+ */
+int
+ncp_li_readrc(struct ncp_conn_loginfo *li) {
+ int i, val, error;
+ char uname[NCP_BINDERY_NAME_LEN*2+1];
+ char *sect = NULL, *p;
+
+ /*
+ * if info from cmd line incomplete, try to find existing
+ * connection and fill server/user from it.
+ */
+ if (li->server[0] == 0 || li->user == NULL) {
+ int connHandle;
+ struct ncp_conn_stat cs;
+
+ if ((error = ncp_conn_scan(li, &connHandle)) != 0) {
+ fprintf(stderr, "no default connection found: %s\n",strerror(errno));
+ return error;
+ }
+ ncp_conn_getinfo(connHandle, &cs);
+ ncp_li_setserver(li, cs.li.server);
+ ncp_li_setuser(li, cs.user);
+ ncp_li_setpassword(li, "");
+ ncp_disconnect(connHandle);
+ }
+ if (ncp_open_rcfile()) return 0;
+
+ for (i = 0; i < 2; i++) {
+ switch (i) {
+ case 0:
+ sect = li->server;
+ break;
+ case 1:
+ strcat(strcat(strcpy(uname,li->server),":"),li->user ? li->user : "default");
+ sect = uname;
+ break;
+ }
+ rc_getstringptr(ncp_rc, sect, "password", &p);
+ if (p)
+ ncp_li_setpassword(li, p);
+ rc_getint(ncp_rc,sect, "timeout", &li->timeout);
+ rc_getint(ncp_rc,sect, "retry_count", &li->retry_count);
+ rc_getint(ncp_rc,sect, "sig_level", &li->sig_level);
+ if (rc_getint(ncp_rc,sect,"access_mode",&val) == 0)
+ li->access_mode = val;
+ if(rc_getbool(ncp_rc,sect,"bindery",&val) == 0 && val) {
+ li->opt |= NCP_OPT_BIND;
+ }
+ }
+ return 0;
+}
+
+/*
+ * check for all uncompleted fields
+ */
+int
+ncp_li_check(struct ncp_conn_loginfo *li) {
+ int error = 0;
+ char *p;
+
+ do {
+ if (li->server[0] == 0) {
+ fprintf(stderr, "no server name specified\n");
+ error = 1;
+ break;
+ }
+ error = ncp_find_fileserver(li,
+ (server_name==NULL) ? AF_IPX : AF_INET, server_name);
+ if (error) {
+ fprintf(stderr,"Can't find server %s, error=%s\n",li->server,strerror(errno));
+ break;
+ }
+ if (li->user == NULL || li->user[0] == 0) {
+ fprintf(stderr, "no user name specified for server %s\n",li->server);
+ error = 1;
+ break;
+ }
+ if (li->password == NULL) {
+ p = getpass("Netware password:");
+ error = ncp_li_setpassword(li, p) ? 1 : 0;
+ }
+ } while (0);
+ return error;
+}
+
+int
+ncp_conn_cnt(void) {
+ int error, cnt = 0, len = sizeof(cnt);
+
+#if __FreeBSD_version < 400001
+ error = sysctlbyname("net.ipx.ncp.conn_cnt", &cnt, &len, NULL, 0);
+#else
+ error = sysctlbyname("net.ncp.conn_cnt", &cnt, &len, NULL, 0);
+#endif
+ if (error) cnt = 0;
+ return cnt;
+}
+
+/*
+ * Find an existing connection and reference it
+ */
+int
+ncp_conn_find(char *server,char *user) {
+ struct ncp_conn_args ca;
+ int connid, error;
+
+ if (server == NULL && user == NULL) {
+ error = ncp_conn_scan(NULL,&connid);
+ if (error) return -2;
+ return connid;
+ }
+ if (server == NULL)
+ return -2;
+ ncp_str_upper(server);
+ if (user) ncp_str_upper(user);
+ bzero(&ca, sizeof(ca));
+ ncp_li_setserver(&ca, server);
+ ncp_li_setuser(&ca, user);
+ error = ncp_conn_scan(&ca,&connid);
+ if (error)
+ connid = -1;
+ return connid;
+}
+
+int
+ncp_li_arg(struct ncp_conn_loginfo *li, int opt, char *arg) {
+ int error = 0, sig_level;
+ char *p, *cp;
+ struct group *gr;
+ struct passwd *pw;
+
+ switch(opt) {
+ case 'S': /* we already fill server/[user] pair */
+ case 'U':
+ break;
+ case 'A':
+ server_name = arg;
+ break;
+ case 'B':
+ li->opt |= NCP_OPT_BIND;
+ break;
+ case 'C':
+ li->opt |= NCP_OPT_NOUPCASEPASS;
+ break;
+ case 'I':
+ sig_level = atoi(arg);
+ if (sig_level < 0 || sig_level > 3) {
+ fprintf(stderr, "Invalid NCP signature level option `%s' (must be number between 0 and 3)\n", arg);
+ error = 1;
+ }
+ li->sig_level = sig_level;
+ if (sig_level > 1) li->opt |= NCP_OPT_SIGN;
+ break;
+ case 'M':
+ li->access_mode = strtol(arg, NULL, 8);
+ break;
+ case 'N':
+ ncp_li_setpassword(li, "");
+ break;
+ case 'O':
+ p = strdup(arg);
+ cp = strchr(p, ':');
+ if (cp) {
+ *cp++ = '\0';
+ if (*cp) {
+ gr = getgrnam(cp);
+ if (gr) {
+ li->group = gr->gr_gid;
+ } else
+ ncp_error("Invalid group name %s, ignored",
+ 0, cp);
+ }
+ }
+ if (*p) {
+ pw = getpwnam(p);
+ if (pw) {
+ li->owner = pw->pw_uid;
+ } else
+ ncp_error("Invalid user name %s, ignored", 0, p);
+ }
+ endpwent();
+ free(p);
+ break;
+ case 'P':
+ li->opt |= NCP_OPT_PERMANENT;
+ break;
+ case 'R':
+ li->retry_count = atoi(arg);
+ break;
+ case 'W':
+ li->timeout = atoi(arg);
+ break;
+ }
+ return error;
+}
+
+void *
+ncp_conn_list(void) {
+ int error, cnt = 0, len;
+ void *p;
+
+ cnt = ncp_conn_cnt();
+ if (cnt == 0) return NULL;
+ len = cnt*(sizeof(struct ncp_conn_stat))+sizeof(int);
+ p = malloc(len);
+ if (p == NULL) return NULL;
+#if __FreeBSD_version < 400001
+ error = sysctlbyname("net.ipx.ncp.conn_stat", p, &len, NULL, 0);
+#else
+ error = sysctlbyname("net.ncp.conn_stat", p, &len, NULL, 0);
+#endif
+ if (error) {
+ free(p);
+ p = NULL;
+ }
+ return p;
+}
+
+
+int
+ncp_conn_setflags(int connid, u_int16_t mask, u_int16_t flags) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_SETFLAGS);
+ ncp_add_word_lh(conn, mask);
+ ncp_add_word_lh(conn, flags);
+ if ((error = ncp_conn_request(connid, conn)) < 0)
+ return -1;
+ return error;
+}
+
+int
+ncp_login(int connHandle, const char *user, int objtype, const char *password) {
+ int error;
+ struct ncp_conn_login *p;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_LOGIN);
+ p = (struct ncp_conn_login *)&conn->packet[conn->rqsize];
+ (const char*)p->username = user;
+ p->objtype = objtype;
+ (const char*)p->password = password;
+ conn->rqsize += sizeof(*p);
+ if ((error = ncp_conn_request(connHandle, conn)) < 0)
+ return -1;
+ return error;
+}
+
+int
+ncp_connect_addr(struct sockaddr *sa, NWCONN_HANDLE *chp) {
+ int error;
+ struct ncp_conn_args li;
+
+ bzero(&li, sizeof(li));
+ bcopy(sa, &li.addr, sa->sa_len);
+ /*
+ * XXX Temporary !!!. server will be filled in kernel !!!
+ */
+ strcpy(li.server,ipx_ntoa(li.ipxaddr.sipx_addr));
+ error = ncp_connect(&li, chp);
+ return error;
+}
+
+int
+ncp_conn_getinfo(int connHandle, struct ncp_conn_stat *ps) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_GETINFO);
+ if ((error = ncp_conn_request(connHandle, conn)) < 0)
+ return -1;
+ memcpy(ps, ncp_reply_data(conn,0), sizeof(*ps));
+ return error;
+}
+
+int
+ncp_conn_getuser(int connHandle, char **user) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_GETUSER);
+ if ((error = ncp_conn_request(connHandle, conn)) < 0)
+ return -1;
+ *user = strdup(ncp_reply_data(conn,0));
+ return error;
+}
+
+int
+ncp_conn2ref(int connHandle, int *connRef) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_CONN2REF);
+ if ((error = ncp_conn_request(connHandle, conn)) < 0)
+ return -1;
+ *connRef = *((int*)ncp_reply_data(conn,0));
+ return error;
+}
+
+int
+ncp_path2conn(char *path, int *connHandle) {
+ struct statfs st;
+ int d, error;
+
+ if ((error = statfs(path, &st)) != 0) return errno;
+ if (strcmp(st.f_fstypename,"nwfs") != 0) return EINVAL;
+ if ((d = open(path, O_RDONLY)) < 0) return errno;
+ if ((error = ioctl(d,NWFSIOC_GETCONN, connHandle)) != 0) return errno;
+ close(d);
+ return 0;
+}
+
+int
+ncp_conn_dup(NWCONN_HANDLE org, NWCONN_HANDLE *res) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_DUP);
+ if ((error = ncp_conn_request(org, conn)) < 0)
+ return errno;
+ *res = *((int*)ncp_reply_data(conn, 0));
+ return 0;
+}
diff --git a/lib/libncp/ncpl_crypt.c b/lib/libncp/ncpl_crypt.c
new file mode 100644
index 000000000000..00ce9bfd9a11
--- /dev/null
+++ b/lib/libncp/ncpl_crypt.c
@@ -0,0 +1,137 @@
+/*
+ * Routines in this file based on the work of Volker Lendecke,
+ * Adapted for ncplib by Boris Popov
+ * Please note that ncpl_crypt.c file should be indentical to this one
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <string.h>
+
+/*$*********************************************************
+ $*
+ $* This code has been taken from DDJ 11/93, from an
+ $* article by Pawel Szczerbina.
+ $*
+ $* Password encryption routines follow.
+ $* Converted to C from Barry Nance's Pascal
+ $* prog published in the March -93 issue of Byte.
+ $*
+ $* Adapted to be useable for ncpfs by
+ $* Volker Lendecke <lendecke@namu01.gwdg.de> in
+ $* October 1995.
+ $*
+ $********************************************************* */
+
+
+
+typedef unsigned char buf32[32];
+
+static unsigned char encrypttable[256] = {
+0x7, 0x8, 0x0, 0x8, 0x6, 0x4, 0xE, 0x4, 0x5, 0xC, 0x1, 0x7, 0xB, 0xF, 0xA, 0x8,
+0xF, 0x8, 0xC, 0xC, 0x9, 0x4, 0x1, 0xE, 0x4, 0x6, 0x2, 0x4, 0x0, 0xA, 0xB, 0x9,
+0x2, 0xF, 0xB, 0x1, 0xD, 0x2, 0x1, 0x9, 0x5, 0xE, 0x7, 0x0, 0x0, 0x2, 0x6, 0x6,
+0x0, 0x7, 0x3, 0x8, 0x2, 0x9, 0x3, 0xF, 0x7, 0xF, 0xC, 0xF, 0x6, 0x4, 0xA, 0x0,
+0x2, 0x3, 0xA, 0xB, 0xD, 0x8, 0x3, 0xA, 0x1, 0x7, 0xC, 0xF, 0x1, 0x8, 0x9, 0xD,
+0x9, 0x1, 0x9, 0x4, 0xE, 0x4, 0xC, 0x5, 0x5, 0xC, 0x8, 0xB, 0x2, 0x3, 0x9, 0xE,
+0x7, 0x7, 0x6, 0x9, 0xE, 0xF, 0xC, 0x8, 0xD, 0x1, 0xA, 0x6, 0xE, 0xD, 0x0, 0x7,
+0x7, 0xA, 0x0, 0x1, 0xF, 0x5, 0x4, 0xB, 0x7, 0xB, 0xE, 0xC, 0x9, 0x5, 0xD, 0x1,
+0xB, 0xD, 0x1, 0x3, 0x5, 0xD, 0xE, 0x6, 0x3, 0x0, 0xB, 0xB, 0xF, 0x3, 0x6, 0x4,
+0x9, 0xD, 0xA, 0x3, 0x1, 0x4, 0x9, 0x4, 0x8, 0x3, 0xB, 0xE, 0x5, 0x0, 0x5, 0x2,
+0xC, 0xB, 0xD, 0x5, 0xD, 0x5, 0xD, 0x2, 0xD, 0x9, 0xA, 0xC, 0xA, 0x0, 0xB, 0x3,
+0x5, 0x3, 0x6, 0x9, 0x5, 0x1, 0xE, 0xE, 0x0, 0xE, 0x8, 0x2, 0xD, 0x2, 0x2, 0x0,
+0x4, 0xF, 0x8, 0x5, 0x9, 0x6, 0x8, 0x6, 0xB, 0xA, 0xB, 0xF, 0x0, 0x7, 0x2, 0x8,
+0xC, 0x7, 0x3, 0xA, 0x1, 0x4, 0x2, 0x5, 0xF, 0x7, 0xA, 0xC, 0xE, 0x5, 0x9, 0x3,
+0xE, 0x7, 0x1, 0x2, 0xE, 0x1, 0xF, 0x4, 0xA, 0x6, 0xC, 0x6, 0xF, 0x4, 0x3, 0x0,
+0xC, 0x0, 0x3, 0x6, 0xF, 0x8, 0x7, 0xB, 0x2, 0xD, 0xC, 0x6, 0xA, 0xA, 0x8, 0xD
+};
+
+static buf32 encryptkeys = {
+ 0x48, 0x93, 0x46, 0x67, 0x98, 0x3D, 0xE6, 0x8D,
+ 0xB7, 0x10, 0x7A, 0x26, 0x5A, 0xB9, 0xB1, 0x35,
+ 0x6B, 0x0F, 0xD5, 0x70, 0xAE, 0xFB, 0xAD, 0x11,
+ 0xF4, 0x47, 0xDC, 0xA7, 0xEC, 0xCF, 0x50, 0xC0
+};
+
+/*
+ * Create table-based 16-bytes hash from a 32-bytes array
+ */
+static void
+nw_hash(buf32 temp, unsigned char *target) {
+ short sum;
+ unsigned char b3;
+ int s, b2, i;
+
+ sum = 0;
+
+ for (b2 = 0; b2 <= 1; ++b2) {
+ for (s = 0; s <= 31; ++s) {
+ b3 = (temp[s] + sum) ^ (temp[(s + sum) & 31] - encryptkeys[s]);
+ sum += b3;
+ temp[s] = b3;
+ }
+ }
+
+ for (i = 0; i <= 15; ++i) {
+ target[i] = encrypttable[temp[2 * i]]
+ | (encrypttable[temp[2 * i + 1]] << 4);
+ }
+}
+
+
+/*
+ * Create a 16-bytes pattern from given buffer based on a four bytes key
+ */
+void
+nw_keyhash(const u_char *key, const u_char *buf, int buflen, u_char *target) {
+ int b2, d, s;
+ buf32 temp;
+
+ while (buflen > 0 && buf[buflen - 1] == 0)
+ buflen--;
+
+ bzero(temp, sizeof(temp));
+
+ d = 0;
+ while (buflen >= 32) {
+ for (s = 0; s <= 31; ++s)
+ temp[s] ^= buf[d++];
+ buflen -= 32;
+ }
+ b2 = d;
+ if (buflen > 0) {
+ for (s = 0; s <= 31; ++s) {
+ if (d + buflen == b2) {
+ temp[s] ^= encryptkeys[s];
+ b2 = d;
+ } else
+ temp[s] ^= buf[b2++];
+ }
+ }
+ for (s = 0; s <= 31; ++s)
+ temp[s] ^= key[s & 3];
+
+ nw_hash(temp, target);
+}
+
+/*
+ * Create an 8-bytes pattern from an 8-bytes key and 16-bytes of data
+ */
+void
+nw_encrypt(const u_char *fra, const u_char *buf, u_char *target) {
+ buf32 k;
+ int s;
+
+ nw_keyhash(fra, buf, 16, k);
+ nw_keyhash(fra + 4, buf, 16, k + 16);
+
+ for (s = 0; s < 16; s++)
+ k[s] ^= k[31 - s];
+
+ for (s = 0; s < 8; s++)
+ *target++ = k[s] ^ k[15 - s];
+}
+
+
diff --git a/lib/libncp/ncpl_file.c b/lib/libncp/ncpl_file.c
new file mode 100644
index 000000000000..e305bc0b0999
--- /dev/null
+++ b/lib/libncp/ncpl_file.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <strings.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_file.h>
+#include <nwfs/nwfs.h>
+
+int
+ncp_read(int connid, ncp_fh *fh, off_t offset, size_t count, char *target) {
+ int result;
+ struct ncp_rw rwrq;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_READ);
+ rwrq.nrw_fh = *fh;
+ rwrq.nrw_base = target;
+ rwrq.nrw_cnt = count;
+ rwrq.nrw_offset = offset;
+ ncp_add_mem(conn, &rwrq, sizeof(rwrq));
+ if ((result = ncp_conn_request(connid, conn)) < 0)
+ return -1;
+ return result;
+}
+
+int
+ncp_write(int connid, ncp_fh *fh, off_t offset, size_t count, char *source)
+{
+ int result;
+ struct ncp_rw rwrq;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_WRITE);
+ rwrq.nrw_fh = *fh;
+ rwrq.nrw_base = source;
+ rwrq.nrw_cnt = count;
+ rwrq.nrw_offset = offset;
+ ncp_add_mem(conn, &rwrq, sizeof(rwrq));
+
+ if ((result = ncp_conn_request(connid, conn)) < 0)
+ return -1;
+ return result;
+}
+
+int
+ncp_geteinfo(char *path, struct nw_entry_info *fi) {
+ int d, error;
+
+ if ((d = open(path, O_RDONLY)) < 0) return errno;
+ if ((error = ioctl(d, NWFSIOC_GETEINFO, fi)) != 0) return errno;
+ close(d);
+ return 0;
+}
+
+
+int
+ncp_AllocTempDirHandle(char *path, NWDIR_HANDLE *pdh) {
+ int d;
+
+ if ((d = open(path, O_RDONLY)) < 0) return errno;
+ *pdh = d;
+ return 0;
+}
+
+int
+ncp_DeallocateDirHandle(NWDIR_HANDLE dh) {
+ close(dh);
+ return 0;
+}
+
+int
+ncp_GetNSEntryInfo(NWDIR_HANDLE dh, struct nw_entry_info *fi, int *ns) {
+ int error;
+
+ if ((error = ioctl(dh, NWFSIOC_GETEINFO, fi)) != 0) return errno;
+ if ((error = ioctl(dh, NWFSIOC_GETNS, ns)) != 0) return errno;
+ return 0;
+}
+
+NWCCODE
+ncp_ScanForDeletedFiles(NWCONN_HANDLE cH, pnuint32 iterHandle,
+ pnuint32 volNum, pnuint32 dirBase, nuint8 ns,
+ NWDELETED_INFO *entryInfo)
+{
+ int error;
+ struct nw_entry_info *pfi;
+ DECLARE_RQ;
+#define UNITEDT(d,t) (((d) << 16) | (t))
+
+ bzero(entryInfo, sizeof(NWDELETED_INFO));
+ ncp_init_request(conn);
+ ncp_add_byte(conn, 16);
+ ncp_add_byte(conn, ns);
+ ncp_add_byte(conn, 0); /* data stream */
+ ncp_add_dword_lh(conn, IM_ALL & ~(IM_SPACE_ALLOCATED | IM_TOTAL_SIZE | IM_EA | IM_DIRECTORY));
+ ncp_add_dword_lh(conn, *iterHandle);
+
+ ncp_add_byte(conn, *volNum);
+ ncp_add_dword_lh(conn, *dirBase);
+ ncp_add_byte(conn, NCP_HF_DIRBASE); /* dirBase */
+ ncp_add_byte(conn, 0); /* no component */
+ if ((error = ncp_request(cH, 87, conn)) != 0) {
+ return error;
+ }
+ if (conn->rpsize < 0x61) {
+ return EBADRPC; /* EACCES ? */
+ }
+ *iterHandle = entryInfo->sequence = ncp_reply_dword_lh(conn, 0x00);
+ entryInfo->deletedTime = ncp_reply_word_lh(conn, 0x04);
+ entryInfo->deletedDateAndTime = UNITEDT(ncp_reply_word_lh(conn, 0x06), entryInfo->deletedTime);
+ entryInfo->deletorID = ncp_reply_dword_hl(conn, 0x08);
+ *volNum = ncp_reply_dword_lh(conn, 0x0C);
+ *dirBase = ncp_reply_dword_lh(conn, 0x10);
+ entryInfo->parent = ncp_reply_dword_lh(conn, 0x10);
+ pfi = (struct nw_entry_info*) ncp_reply_data(conn, 0x14);
+ entryInfo->nameLength = pfi->nameLen;
+ memcpy(entryInfo->name, pfi->entryName, pfi->nameLen);
+ return error;
+}
+
+NWCCODE
+ncp_PurgeDeletedFile(NWCONN_HANDLE cH, nuint32 iterHandle,
+ nuint32 volNum, nuint32 dirBase, nuint8 ns)
+{
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, 18);
+ ncp_add_byte(conn, ns);
+ ncp_add_byte(conn, 0); /* reserved */
+ ncp_add_dword_lh(conn, iterHandle);
+ ncp_add_dword_lh(conn, volNum);
+ ncp_add_dword_lh(conn, dirBase);
+ return ncp_request(cH, 87, conn);
+}
+
+
+static void
+ncp_extract_entryInfo(char *data, NW_ENTRY_INFO *entry) {
+ u_char l;
+ const int info_struct_size = sizeof(NW_ENTRY_INFO) - 257;
+
+ memcpy(entry, data, info_struct_size);
+ data += info_struct_size;
+ l = *data++;
+ entry->nameLen = l;
+ memcpy(entry->entryName, data, l);
+ entry->entryName[l] = '\0';
+ return;
+}
+
+NWCCODE
+ncp_ScanNSEntryInfo(NWCONN_HANDLE cH,
+ nuint8 namSpc, nuint16 attrs, SEARCH_SEQUENCE *seq,
+ pnstr8 searchPattern, nuint32 retInfoMask, NW_ENTRY_INFO *entryInfo)
+{
+ int error, l;
+ DECLARE_RQ;
+
+ if (seq->searchDirNumber == -1) {
+ seq->searchDirNumber = 0;
+ ncp_init_request(conn);
+ ncp_add_byte(conn, 2);
+ ncp_add_byte(conn, namSpc);
+ ncp_add_byte(conn, 0);
+ ncp_add_handle_path(conn, seq->volNumber, seq->dirNumber,
+ NCP_HF_DIRBASE, NULL);
+ error = ncp_request(cH, 87, conn);
+ if (error) return error;
+ memcpy(seq, ncp_reply_data(conn, 0), 9);
+ }
+ ncp_init_request(conn);
+ ncp_add_byte(conn, 3);
+ ncp_add_byte(conn, namSpc);
+ ncp_add_byte(conn, 0); /* dataStream */
+ ncp_add_word_lh(conn, attrs); /* SearchAttributes */
+ ncp_add_dword_lh(conn, retInfoMask);
+ ncp_add_mem(conn, seq, sizeof(*seq));
+ l = strlen(searchPattern);
+ ncp_add_byte(conn, l);
+ ncp_add_mem(conn, searchPattern, l);
+ error = ncp_request(cH, 87, conn);
+ if (error) return error;
+ memcpy(seq, ncp_reply_data(conn, 0), sizeof(*seq));
+ ncp_extract_entryInfo(ncp_reply_data(conn, 10), entryInfo);
+ return 0;
+}
+
+int
+ncp_NSEntryInfo(NWCONN_HANDLE cH, nuint8 ns, nuint8 vol, nuint32 dirent,
+ NW_ENTRY_INFO *entryInfo)
+{
+ DECLARE_RQ;
+ int error;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, 6);
+ ncp_add_byte(conn, ns);
+ ncp_add_byte(conn, ns); /* DestNameSpace */
+ ncp_add_word_lh(conn, htons(0xff00)); /* get all */
+ ncp_add_dword_lh(conn, IM_ALL);
+ ncp_add_handle_path(conn, vol, dirent, NCP_HF_DIRBASE, NULL);
+ error = ncp_request(cH, 87, conn);
+ if (error) return error;
+ ncp_extract_entryInfo(ncp_reply_data(conn, 0), entryInfo);
+ return 0;
+}
+
+NWCCODE
+NWGetVolumeName(NWCONN_HANDLE cH, u_char volume, char *name) {
+ int error, len;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 44);
+ ncp_add_byte(conn, volume);
+ error = ncp_request(cH, 22, conn);
+ if (error) return error;
+ len = ncp_reply_byte(conn, 29);
+ if (len == 0)
+ return ENOENT;
+ bcopy(ncp_reply_data(conn, 30), name, len);
+ name[len] = 0;
+ return 0;
+}
diff --git a/lib/libncp/ncpl_misc.c b/lib/libncp/ncpl_misc.c
new file mode 100644
index 000000000000..7f7a67a8a368
--- /dev/null
+++ b/lib/libncp/ncpl_misc.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * calls that don't fit to any other category
+ *
+ */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+
+#include <netncp/ncp_lib.h>
+
+static time_t
+ncp_nw_to_ctime(struct nw_time_buffer *source) {
+ struct tm u_time;
+
+ bzero(&u_time,sizeof(struct tm));
+ /*
+ * XXX: NW 4.x tracks daylight automatically
+ */
+ u_time.tm_isdst = -1;
+ u_time.tm_sec = source->second;
+ u_time.tm_min = source->minute;
+ u_time.tm_hour = source->hour;
+ u_time.tm_mday = source->day;
+ u_time.tm_mon = source->month - 1;
+ u_time.tm_year = source->year;
+
+ if (u_time.tm_year < 80) {
+ u_time.tm_year += 100;
+ }
+ return mktime(&u_time);
+}
+
+int
+ncp_get_file_server_information(int connid, struct ncp_file_server_info *target)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 17);
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ memcpy(target, ncp_reply_data(conn, 0), sizeof(*target));
+ target->MaximumServiceConnections
+ = htons(target->MaximumServiceConnections);
+ target->ConnectionsInUse
+ = htons(target->ConnectionsInUse);
+ target->MaxConnectionsEverUsed
+ = htons(target->MaxConnectionsEverUsed);
+ target->NumberMountedVolumes
+ = htons(target->NumberMountedVolumes);
+ return 0;
+}
+
+int
+ncp_get_stations_logged_info(int connid, u_int32_t connection,
+ struct ncp_bindery_object *target,
+ time_t *login_time)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 28);
+ ncp_add_dword_lh(conn, connection);
+
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ bzero(target, sizeof(*target));
+ target->object_id = ncp_reply_dword_hl(conn, 0);
+ target->object_type = ncp_reply_word_hl(conn, 4);
+ memcpy(target->object_name, ncp_reply_data(conn, 6),
+ sizeof(target->object_name));
+ *login_time = ncp_nw_to_ctime((struct nw_time_buffer *)ncp_reply_data(conn, 54));
+ return 0;
+}
+
+int
+ncp_get_internet_address(int connid, u_int32_t connection, struct ipx_addr *target,
+ u_int8_t * conn_type) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 26);
+ ncp_add_dword_lh(conn, connection);
+ error = ncp_request(connid, 23, conn);
+ if (error) return error;
+ bzero(target, sizeof(*target));
+ ipx_netlong(*target) = ncp_reply_dword_lh(conn, 0);
+ memcpy(&(target->x_host), ncp_reply_data(conn, 4), 6);
+ target->x_port = ncp_reply_word_lh(conn, 10);
+ *conn_type = ncp_reply_byte(conn, 12);
+ return 0;
+}
+
+NWCCODE
+NWGetObjectConnectionNumbers(NWCONN_HANDLE connHandle,
+ pnstr8 pObjName, nuint16 objType,
+ pnuint16 pNumConns, pnuint16 pConnHandleList,
+ nuint16 maxConns)
+{
+ int error, i;
+ DECLARE_RQ;
+ ncp_init_request_s(conn, 21);
+ ncp_add_word_hl(conn, objType);
+ ncp_add_pstring(conn, pObjName);
+ if ((error = ncp_request(connHandle, 23, conn)) != 0) return error;
+ i = ncp_reply_byte(conn,0);
+ *pNumConns = i;
+ for (i = min(i, maxConns); i; i--) {
+ pConnHandleList[i-1] = ncp_reply_byte(conn, i);
+ }
+ return 0;
+}
+
+void
+NWUnpackDateTime(nuint32 dateTime, NW_DATE *sDate, NW_TIME *sTime) {
+ NWUnpackDate(dateTime >> 16, sDate);
+ NWUnpackTime(dateTime & 0xffff, sTime);
+}
+
+void
+NWUnpackDate(nuint16 date, NW_DATE *sDate) {
+ sDate->day = date & 0x1f;
+ sDate->month = (date >> 5) & 0xf;
+ sDate->year = ((date >> 9) & 0x7f) + 1980;
+}
+
+void
+NWUnpackTime(nuint16 time, NW_TIME *sTime) {
+ sTime->seconds = time & 0x1f;
+ sTime->minutes = (time >> 5) & 0x3f;
+ sTime->hours = (time >> 11) & 0x1f;
+}
+
+nuint32
+NWPackDateTime(NW_DATE *sDate, NW_TIME *sTime) {
+ return 0;
+}
+
+nuint16
+NWPackDate(NW_DATE *sDate) {
+ return 0;
+}
+
+nuint16
+NWPackTime(NW_TIME *sTime) {
+ return 0;
+}
+
+time_t
+ncp_UnpackDateTime(nuint32 dateTime) {
+ struct tm u_time;
+ NW_DATE d;
+ NW_TIME t;
+
+ NWUnpackDateTime(dateTime, &d, &t);
+ bzero(&u_time,sizeof(struct tm));
+ u_time.tm_isdst = -1;
+ u_time.tm_sec = t.seconds;
+ u_time.tm_min = t.minutes;
+ u_time.tm_hour = t.hours;
+ u_time.tm_mday = d.day;
+ u_time.tm_mon = d.month - 1;
+ u_time.tm_year = d.year - 1900;
+
+ return mktime(&u_time);
+}
+
+int
+ncp_GetFileServerDateAndTime(NWCONN_HANDLE cH, time_t *target) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ if ((error = ncp_request(cH, 20, conn)) != 0)
+ return error;
+ *target = ncp_nw_to_ctime((struct nw_time_buffer *) ncp_reply_data(conn, 0));
+ return 0;
+}
+
+int
+ncp_SetFileServerDateAndTime(NWCONN_HANDLE cH, time_t * source) {
+ int year;
+ struct tm *utime = localtime(source);
+ DECLARE_RQ;
+
+ year = utime->tm_year;
+ if (year > 99) {
+ year -= 100;
+ }
+ ncp_init_request_s(conn, 202);
+ ncp_add_byte(conn, year);
+ ncp_add_byte(conn, utime->tm_mon + 1);
+ ncp_add_byte(conn, utime->tm_mday);
+ ncp_add_byte(conn, utime->tm_hour);
+ ncp_add_byte(conn, utime->tm_min);
+ ncp_add_byte(conn, utime->tm_sec);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWDownFileServer(NWCONN_HANDLE cH, int force) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 211);
+ ncp_add_byte(conn, force ? 0 : 0xff);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWCloseBindery(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 68);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWOpenBindery(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 69);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWDisableTTS(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 207);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWEnableTTS(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 208);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWDisableFileServerLogin(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 203);
+ return ncp_request(cH, 23, conn);
+}
+
+NWCCODE
+NWEnableFileServerLogin(NWCONN_HANDLE cH) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 204);
+ return ncp_request(cH, 23, conn);
+}
diff --git a/lib/libncp/ncpl_msg.c b/lib/libncp/ncpl_msg.c
new file mode 100644
index 000000000000..a65131bd14fb
--- /dev/null
+++ b/lib/libncp/ncpl_msg.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_nls.h>
+
+NWCCODE
+NWDisableBroadcasts(NWCONN_HANDLE connHandle) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 2);
+ return ncp_request(connHandle, 21, conn);
+}
+
+NWCCODE
+NWEnableBroadcasts(NWCONN_HANDLE connHandle) {
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 3);
+ return ncp_request(connHandle, 21, conn);
+}
+
+NWCCODE
+NWBroadcastToConsole(NWCONN_HANDLE connHandle, pnstr8 message) {
+ int l, error;
+ DECLARE_RQ;
+
+ l = strlen(message);
+ if (l > 60) return EMSGSIZE;
+ ncp_init_request_s(conn, 9);
+ ncp_add_byte(conn, l);
+ ncp_add_mem_nls(conn, message, l);
+ error = ncp_request(connHandle, 21, conn);
+ return error;
+}
+
+NWCCODE
+NWSendBroadcastMessage(NWCONN_HANDLE connHandle, pnstr8 message,
+ nuint16 connCount, pnuint16 connList, pnuint8 resultList)
+{
+ int l, i, error;
+ DECLARE_RQ;
+
+ l = strlen(message);
+ if (l > 255) return EMSGSIZE;
+ if (connCount > 350) return EINVAL;
+
+ ncp_init_request_s(conn, 0x0A);
+ ncp_add_word_lh(conn, connCount);
+ for (i = 0; i < connCount; i++)
+ ncp_add_dword_lh(conn, connList[i]);
+ ncp_add_byte(conn, l);
+ ncp_add_mem_nls(conn, message, l);
+ error = ncp_request(connHandle, 0x15, conn);
+ if (!error) {
+ l = ncp_reply_word_lh(conn, 0);
+ for (i = 0; i < l; i++)
+ resultList[i] = ncp_reply_dword_lh(conn, (i)*4 + 2);
+ return 0;
+ }
+ if (error != 0xfb) return error;
+ if (l > 58) return EMSGSIZE;
+ ncp_init_request_s(conn, 0);
+ ncp_add_byte(conn, connCount);
+ for (i = 0; i < connCount; i++)
+ ncp_add_byte(conn, connList[i]);
+ ncp_add_byte(conn, l);
+ ncp_add_mem_nls(conn, message, l);
+ error = ncp_request(connHandle, 0x15, conn);
+ if (error) return error;
+ i = ncp_reply_byte(conn, 0);
+ memcpy(resultList, ncp_reply_data(conn, 1), i);
+ return 0;
+}
+
+
+NWCCODE
+NWGetBroadcastMessage(NWCONN_HANDLE connHandle, pnstr8 message) {
+ int i, error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 0x0B);
+ error = ncp_request(connHandle, 0x15, conn);
+ if (error) {
+ if (error != 0x89fb) return error;
+ ncp_init_request_s(conn, 0x01);
+ if ((error = ncp_request(connHandle, 0x15, conn)) != 0)
+ return error;
+ }
+ i = ncp_reply_byte(conn, 0);
+ if (i == 0) return ENOENT;
+ memcpy(message, ncp_reply_data(conn, 1), i);
+ message[i] = 0;
+ ncp_nls_str_n2u(message, message);
+ return 0;
+}
diff --git a/lib/libncp/ncpl_net.c b/lib/libncp/ncpl_net.c
new file mode 100644
index 000000000000..da21b663de51
--- /dev/null
+++ b/lib/libncp/ncpl_net.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/syscall.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netipx/ipx.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "ipxsap.h"
+#include <netncp/ncp_lib.h>
+#include "ncp_mod.h"
+
+static int ncp_find_server_in(struct ncp_conn_loginfo *li, int type, char *server_name);
+
+static int
+ncp_find_server_ipx(struct ncp_conn_loginfo *li, int type) {
+ char server[NCP_BINDERY_NAME_LEN + 1];
+ int error;
+ char nearest[NCP_BINDERY_NAME_LEN + 1];
+ struct nw_property prop;
+ struct ipx_addr *n_addr = (struct ipx_addr *) &prop;
+/* struct ncp_conn_loginfo ltmp;*/
+ int connid;
+
+ bzero(server, sizeof(server));
+ bzero(nearest, sizeof(nearest));
+
+ strcpy(server, li->server);
+ ncp_str_upper(server);
+
+ if ((error = sap_find_nearest(type, &li->ipxaddr, nearest)) != 0) {
+ return error;
+ }
+ /* if no server specified return info about nearest */
+ if (!li->server[0]) {
+ strcpy(li->server, nearest);
+ return 0;
+ }
+/* printf("%s\n",ipx_ntoa(li->ipxaddr.sipx_addr));*/
+ if (strcmp(server, nearest) == 0) {
+ return 0;
+ }
+ /* We have to ask the nearest server for our wanted server */
+ li->opt=0;
+ if ((error = ncp_connect(li, &connid)) != 0) {
+ return error;
+ }
+ if (ncp_read_property_value(connid, type, server, 1, "NET_ADDRESS", &prop) != 0) {
+ ncp_disconnect(connid);
+ return EHOSTUNREACH;
+ }
+ if ((error = ncp_disconnect(connid)) != 0) {
+ return error;
+ }
+ li->ipxaddr.sipx_family = AF_IPX;
+ li->ipxaddr.sipx_addr.x_net = n_addr->x_net;
+ li->ipxaddr.sipx_port = n_addr->x_port;
+ li->ipxaddr.sipx_addr.x_host = n_addr->x_host;
+ return 0;
+}
+
+static int
+ncp_find_server_in(struct ncp_conn_loginfo *li, int type, char *server_name) {
+ struct hostent* h;
+ int l;
+
+ h = gethostbyname(server_name);
+ if (!h) {
+ fprintf(stderr, "Get host address `%s': ", server_name);
+ herror(NULL);
+ return 1;
+ }
+ if (h->h_addrtype != AF_INET) {
+ fprintf(stderr, "Get host address `%s': Not AF_INET\n", server_name);
+ return 1;
+ }
+ if (h->h_length != 4) {
+ fprintf(stderr, "Get host address `%s': Bad address length\n", server_name);
+ return 1;
+ }
+ l = sizeof(struct sockaddr_in);
+ bzero(&li->inaddr, l);
+ li->inaddr.sin_len = l;
+ li->inaddr.sin_family = h->h_addrtype;
+ memcpy(&li->inaddr.sin_addr.s_addr, h->h_addr, 4);
+ li->inaddr.sin_port = htons(524); /* ncp */
+ return 0;
+}
+
+int
+ncp_find_server(struct ncp_conn_loginfo *li, int type, int af, char *name) {
+ int error = EHOSTUNREACH;
+
+ switch(af) {
+ case AF_IPX:
+ error = ncp_find_server_ipx(li, type);
+ break;
+ case AF_INET:
+ if (name)
+ error = ncp_find_server_in(li, type, name);
+ break;
+ default:
+ error = EPROTONOSUPPORT;
+ }
+ return error;
+}
+
+int
+ncp_find_fileserver(struct ncp_conn_loginfo *li, int af, char *name) {
+ return ncp_find_server(li, NCP_BINDERY_FSERVER, af, name);
+}
diff --git a/lib/libncp/ncpl_nls.c b/lib/libncp/ncpl_nls.c
new file mode 100644
index 000000000000..92bc013c6103
--- /dev/null
+++ b/lib/libncp/ncpl_nls.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Languages support. Currently is very primitive.
+ */
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <locale.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_cfg.h>
+#include <netncp/ncp_nls.h>
+
+#ifndef NCP_NLS_DEFAULT
+#define NCP_NLS_DEFAULT NCP_NLS_AS_IS
+#endif
+
+/*
+ * TODO: Make all tables dynamically loadable.
+ */
+#ifdef NCP_NLS_KOI2CP866
+/* Russian tables from easy-cyrillic:
+ * Copyright (C) 1993-1994 by Andrey A. Chernov, Moscow, Russia
+ */
+static u_int8_t alt2koi8[] = {
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x00 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x10 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x5f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa,
+ 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe,
+ 0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1,
+ 0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda,
+ 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+ 0x90, 0x91, 0x92, 0x81, 0x87, 0xb2, 0xb4, 0xa7,
+ 0xa6, 0xb5, 0xa1, 0xa8, 0xae, 0xad, 0xac, 0x83,
+ 0x84, 0x89, 0x88, 0x86, 0x80, 0x8a, 0xaf, 0xb0,
+ 0xab, 0xa5, 0xbb, 0xb8, 0xb1, 0xa0, 0xbe, 0xb9,
+ 0xba, 0xb6, 0xb7, 0xaa, 0xa9, 0xa2, 0xa4, 0xbd,
+ 0xbc, 0x85, 0x82, 0x8d, 0x8c, 0x8e, 0x8f, 0x8b,
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde,
+ 0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1,
+ 0xb3, 0xa3, 0x99, 0x98, 0x93, 0x9b, 0x9f, 0x97,
+ 0x9c, 0x95, 0x9e, 0x96, 0xbf, 0x9d, 0x94, 0x9a
+};
+
+static u_int8_t koi82alt[] = {
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x00 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, /* 0x10 */
+ 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x5f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0xc4, 0xb3, 0xda, 0xbf, 0xc0, 0xd9, 0xc3, 0xb4, /* 0x80 */
+ 0xc2, 0xc1, 0xc5, 0xdf, 0xdc, 0xdb, 0xdd, 0xde,
+ 0xb0, 0xb1, 0xb2, 0xf4, 0xfe, 0xf9, 0xfb, 0xf7,
+ 0xf3, 0xf2, 0xff, 0xf5, 0xf8, 0xfd, 0xfa, 0xf6,
+ 0xcd, 0xba, 0xd5, 0xf1, 0xd6, 0xc9, 0xb8, 0xb7,
+ 0xbb, 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6,
+ 0xc7, 0xcc, 0xb5, 0xf0, 0xb6, 0xb9, 0xd1, 0xd2,
+ 0xcb, 0xcf, 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0xfc,
+ 0xee, 0xa0, 0xa1, 0xe6, 0xa4, 0xa5, 0xe4, 0xa3,
+ 0xe5, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae,
+ 0xaf, 0xef, 0xe0, 0xe1, 0xe2, 0xe3, 0xa6, 0xa2,
+ 0xec, 0xeb, 0xa7, 0xe8, 0xed, 0xe9, 0xe7, 0xea,
+ 0x9e, 0x80, 0x81, 0x96, 0x84, 0x85, 0x94, 0x83,
+ 0x95, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
+ 0x8f, 0x9f, 0x90, 0x91, 0x92, 0x93, 0x86, 0x82, /* 0xf0 */
+ 0x9c, 0x9b, 0x87, 0x98, 0x9d, 0x99, 0x97, 0x9a
+};
+
+#endif
+
+static u_int8_t def2lower[256];
+static u_int8_t def2upper[256];
+
+/*
+ * List of available charsets
+ */
+struct ncp_nlsdesc {
+ int scheme;
+ char *name;
+ struct ncp_nlstables nls;
+};
+
+static struct ncp_nlsdesc ncp_nlslist[] = {
+ {NCP_NLS_AS_IS, NCP_NLS_AS_IS_NAME,
+ {def2lower, def2upper, NULL, NULL, 0}
+ },
+#ifdef NCP_NLS_KOI2CP866
+ {NCP_NLS_KOI_866, NCP_NLS_KOI_866_NAME,
+ {def2lower, def2upper, alt2koi8, koi82alt, 0}
+ },
+#endif
+ {NULL, 0}
+};
+
+struct ncp_nlstables ncp_nls;
+
+int
+ncp_nls_setlocale(char *name) {
+ int i;
+
+ ncp_nls.tolower = def2lower;
+ ncp_nls.toupper = def2upper;
+ if (setlocale(LC_CTYPE, name) == NULL) {
+ fprintf(stderr, "Can't set locale '%s'\n", name);
+ return EINVAL;
+ }
+ for (i = 0; i < 256; i++) {
+ ncp_nls.tolower[i] = tolower(i);
+ ncp_nls.toupper[i] = toupper(i);
+ }
+ return 0;
+}
+
+int
+ncp_nls_setrecode(int scheme) {
+ struct ncp_nlsdesc *nd;
+
+ if (scheme == 0) {
+#if NCP_NLS_DEFAULT
+ scheme = NCP_NLS_DEFAULT;
+#else
+ scheme = NCP_NLS_AS_IS;
+#endif
+ }
+ for (nd = ncp_nlslist; nd->name; nd++) {
+ if (nd->scheme != scheme) continue;
+ ncp_nls.u2n = nd->nls.u2n;
+ ncp_nls.n2u = nd->nls.n2u;
+ return ncp_nls_setlocale("");
+ }
+ fprintf(stderr, "Character conversion scheme %d was not compiled in\n", scheme);
+ return EINVAL;
+}
+
+int
+ncp_nls_setrecodebyname(char *name) {
+ struct ncp_nlsdesc *nd;
+
+ for (nd = ncp_nlslist; nd->name; nd++) {
+ if (strcmp(nd->name, name) != 0) continue;
+ ncp_nls.u2n = nd->nls.u2n;
+ ncp_nls.n2u = nd->nls.n2u;
+ return 0;
+ }
+ fprintf(stderr, "Character conversion scheme %s was not compiled in\n", name);
+ return EINVAL;
+}
+
+char *
+ncp_nls_str_n2u(char *dst, const char *src) {
+ char *p;
+
+ if (ncp_nls.n2u == NULL) {
+ return strcpy(dst, src);
+ }
+ p = dst;
+ while (*src)
+ *p++ = ncp_nls.n2u[(u_char)*(src++)];
+ *p = 0;
+ return dst;
+}
+
+char *
+ncp_nls_str_u2n(char *dst, const char *src) {
+ char *p;
+
+ if (ncp_nls.u2n == NULL) {
+ return strcpy(dst, src);
+ }
+ p = dst;
+ while (*src)
+ *p++ = ncp_nls.u2n[(u_char)*(src++)];
+ *p = 0;
+ return dst;
+}
+
+char *
+ncp_nls_mem_n2u(char *dst, const char *src, int size) {
+ char *p;
+
+ if (size == 0) return NULL;
+ if (ncp_nls.n2u == NULL) {
+ return memcpy(dst, src, size);
+ }
+ for(p = dst; size; size--, p++)
+ *p = ncp_nls.n2u[(u_char)*(src++)];
+ return dst;
+}
+
+char *
+ncp_nls_mem_u2n(char *dst, const char *src, int size) {
+ char *p;
+
+ if (size == 0) return NULL;
+ if (ncp_nls.u2n == NULL) {
+ return strcpy(dst, src);
+ }
+ for(p = dst; size; size--, p++)
+ *p = ncp_nls.u2n[(u_char)*(src++)];
+ return dst;
+}
+
+char *
+ncp_str_upper(char *s) {
+ char *p = s;
+ while (*s) {
+ *s = toupper(*s);
+ s++;
+ }
+ return p;
+}
diff --git a/lib/libncp/ncpl_queue.c b/lib/libncp/ncpl_queue.c
new file mode 100644
index 000000000000..beb34c7bd155
--- /dev/null
+++ b/lib/libncp/ncpl_queue.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * NetWare queue interface
+ *
+ */
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <netncp/ncp_lib.h>
+
+int
+ncp_create_queue_job_and_file(int connid, u_int32_t queue_id,
+ struct queue_job *job)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 121);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_mem(conn, &(job->j), sizeof(job->j));
+
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ memcpy(&(job->j), ncp_reply_data(conn, 0), 78);
+ ConvertToNWfromDWORD(job->j.JobFileHandle, &job->file_handle);
+ return 0;
+}
+
+int
+ncp_close_file_and_start_job(int connid, u_int32_t queue_id, struct queue_job *job)
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 127);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_dword_lh(conn, job->j.JobNumber);
+ error = ncp_request(connid, 23, conn);
+ return error;
+}
+
+int
+ncp_attach_to_queue(int connid, u_int32_t queue_id) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 111);
+ ncp_add_dword_hl(conn, queue_id);
+ error = ncp_request(connid, 23, conn);
+ return error;
+}
+
+int
+ncp_detach_from_queue(int connid, u_int32_t queue_id) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 112);
+ ncp_add_dword_hl(conn, queue_id);
+ error= ncp_request(connid, 23, conn);
+ return error;
+}
+
+int
+ncp_service_queue_job(int connid, u_int32_t queue_id, u_int16_t job_type,
+ struct queue_job *job) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 124);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_word_hl(conn, job_type);
+ if ((error = ncp_request(connid, 23, conn)) != 0) {
+ return error;
+ }
+ memcpy(&(job->j), ncp_reply_data(conn, 0), 78);
+ ConvertToNWfromDWORD(job->j.JobFileHandle, &job->file_handle);
+ return error;
+}
+
+int
+ncp_finish_servicing_job(int connid, u_int32_t queue_id, u_int32_t job_number,
+ u_int32_t charge_info) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 131);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_dword_lh(conn, job_number);
+ ncp_add_dword_hl(conn, charge_info);
+
+ error = ncp_request(connid, 23, conn);
+ return error;
+}
+
+int
+ncp_abort_servicing_job(int connid, u_int32_t queue_id, u_int32_t job_number) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 132);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_dword_lh(conn, job_number);
+ error = ncp_request(connid, 23, conn);
+ return error;
+}
+
+int
+ncp_get_queue_length(int connid, u_int32_t queue_id, u_int32_t *queue_length) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn, 125);
+ ncp_add_dword_hl(conn, queue_id);
+
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ if (conn->rpsize < 12) {
+ ncp_printf("ncp_reply_size %d < 12\n", conn->rpsize);
+ return EINVAL;
+ }
+ if (ncp_reply_dword_hl(conn,0) != queue_id) {
+ printf("Ouch! Server didn't reply with same queue id in ncp_get_queue_length!\n");
+ return EINVAL;
+ }
+ *queue_length = ncp_reply_dword_lh(conn,8);
+ return error;
+}
+
+int
+ncp_get_queue_job_ids(int connid, u_int32_t queue_id, u_int32_t queue_section,
+ u_int32_t *length1, u_int32_t *length2, u_int32_t ids[])
+{
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn,129);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_dword_lh(conn, queue_section);
+
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+ if (conn->rpsize < 8) {
+ ncp_printf("ncp_reply_size %d < 8\n", conn->rpsize);
+ return EINVAL;
+ }
+ *length2 = ncp_reply_dword_lh(conn,4);
+ if (conn->rpsize < 8 + 4*(*length2)) {
+ ncp_printf("ncp_reply_size %d < %d\n", conn->rpsize, 8+4*(*length2));
+ return EINVAL;
+ }
+ if (ids) {
+ int count = min(*length1, *length2)*sizeof(u_int32_t);
+ int pos;
+
+ for (pos=0; pos<count; pos+=sizeof(u_int32_t)) {
+ *ids++ = ncp_reply_dword_lh(conn, 8+pos);
+ }
+ }
+ *length1 = ncp_reply_dword_lh(conn,0);
+ return error;
+}
+
+int
+ncp_get_queue_job_info(int connid, u_int32_t queue_id, u_int32_t job_id,
+ struct nw_queue_job_entry *jobdata) {
+ int error;
+ DECLARE_RQ;
+
+ ncp_init_request_s(conn,122);
+ ncp_add_dword_hl(conn, queue_id);
+ ncp_add_dword_lh(conn, job_id);
+
+ if ((error = ncp_request(connid, 23, conn)) != 0)
+ return error;
+
+ if (conn->rpsize < sizeof(struct nw_queue_job_entry)) {
+ ncp_printf("ncp_reply_size %d < %d\n", conn->rpsize,sizeof(struct nw_queue_job_entry));
+ return EINVAL;
+ }
+ memcpy(jobdata,ncp_reply_data(conn,0), sizeof(struct nw_queue_job_entry));
+ return error;
+}
diff --git a/lib/libncp/ncpl_rcfile.c b/lib/libncp/ncpl_rcfile.c
new file mode 100644
index 000000000000..7a69071be752
--- /dev/null
+++ b/lib/libncp/ncpl_rcfile.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_rcfile.h>
+#include <netncp/ncp_cfg.h>
+
+#define NWFS_CFG_FILE NCP_PREFIX"/etc/nwfs.conf"
+
+struct rcfile *ncp_rc = NULL;
+
+SLIST_HEAD(rcfile_head, rcfile);
+static struct rcfile_head pf_head = {NULL};
+
+int rc_merge(char *filename,struct rcfile **rcfile);
+static struct rcfile* rc_find(char *filename);
+static struct rcsection *rc_findsect(struct rcfile *rcp, char *sectname);
+static struct rcsection *rc_addsect(struct rcfile *rcp, char *sectname);
+static int rc_sect_free(struct rcsection *rsp);
+static struct rckey *rc_sect_findkey(struct rcsection *rsp, char *keyname);
+static struct rckey *rc_sect_addkey(struct rcsection *rsp, char *name, char *value);
+static void rc_key_free(struct rckey *p);
+static void rc_parse(struct rcfile *rcp);
+
+
+/*
+ * open rcfile and load its content, if already open - return previous handle
+ */
+int
+rc_open(char *filename,char *mode,struct rcfile **rcfile) {
+ struct rcfile *rcp;
+ FILE *f;
+
+ rcp = rc_find(filename);
+ if( rcp ) {
+ *rcfile = rcp;
+ return 0;
+ }
+ f = fopen (filename, mode);
+ if (f==NULL)
+ return errno;
+ rcp = malloc(sizeof(struct rcfile));
+ if (rcp==NULL) {
+ fclose(f);
+ return ENOMEM;
+ }
+ bzero(rcp, sizeof(struct rcfile));
+ rcp->rf_name = strdup (filename);
+ rcp->rf_f = f;
+ SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
+ rc_parse(rcp);
+ *rcfile = rcp;
+ return 0;
+}
+
+int
+rc_merge(char *filename,struct rcfile **rcfile) {
+ struct rcfile *rcp = *rcfile;
+ FILE *f, *t;
+
+ if (rcp == NULL) {
+ return rc_open(filename,"r",rcfile);
+ }
+ f = fopen (filename, "r");
+ if (f==NULL)
+ return errno;
+ t = rcp->rf_f;
+ rcp->rf_f = f;
+ rc_parse(rcp);
+ rcp->rf_f = t;
+ fclose(f);
+ return 0;
+}
+
+int
+rc_close(struct rcfile *rcp) {
+ struct rcsection *p,*n;
+
+ fclose(rcp->rf_f);
+ for(p = SLIST_FIRST(&rcp->rf_sect);p;) {
+ n = p;
+ p = SLIST_NEXT(p,rs_next);
+ rc_sect_free(n);
+ }
+ free(rcp->rf_name);
+ SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
+ free(rcp);
+ return 0;
+}
+
+static struct rcfile*
+rc_find(char *filename) {
+ struct rcfile *p;
+
+ SLIST_FOREACH(p, &pf_head, rf_next)
+ if (strcmp (filename, p->rf_name)==0)
+ return p;
+ return 0;
+}
+
+static struct rcsection *
+rc_findsect(struct rcfile *rcp, char *sectname) {
+ struct rcsection *p;
+
+ SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
+ if (strcmp(p->rs_name, sectname)==0)
+ return p;
+ return NULL;
+}
+
+static struct rcsection *
+rc_addsect(struct rcfile *rcp, char *sectname) {
+ struct rcsection *p;
+
+ p = rc_findsect(rcp, sectname);
+ if (p) return p;
+ p = malloc(sizeof(*p));
+ if (!p) return NULL;
+ p->rs_name = strdup(sectname);
+ SLIST_INIT(&p->rs_keys);
+ SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
+ return p;
+}
+
+static int
+rc_sect_free(struct rcsection *rsp) {
+ struct rckey *p,*n;
+
+ for(p = SLIST_FIRST(&rsp->rs_keys);p;) {
+ n = p;
+ p = SLIST_NEXT(p,rk_next);
+ rc_key_free(n);
+ }
+ free(rsp->rs_name);
+ free(rsp);
+ return 0;
+}
+
+static struct rckey *
+rc_sect_findkey(struct rcsection *rsp, char *keyname) {
+ struct rckey *p;
+
+ SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
+ if (strcmp(p->rk_name, keyname)==0)
+ return p;
+ return NULL;
+}
+
+static struct rckey *
+rc_sect_addkey(struct rcsection *rsp, char *name, char *value) {
+ struct rckey *p;
+
+ p = rc_sect_findkey(rsp, name);
+ if (p) {
+ free(p->rk_value);
+ } else {
+ p = malloc(sizeof(*p));
+ if (!p) return NULL;
+ SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
+ p->rk_name = strdup(name);
+ }
+ p->rk_value = value ? strdup(value) : strdup("");
+ return p;
+}
+
+void
+rc_sect_delkey(struct rcsection *rsp, struct rckey *p) {
+
+ SLIST_REMOVE(&rsp->rs_keys,p,rckey,rk_next);
+ rc_key_free(p);
+ return;
+}
+
+static void
+rc_key_free(struct rckey *p){
+ free(p->rk_value);
+ free(p->rk_name);
+ free(p);
+}
+
+enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
+
+static void
+rc_parse(struct rcfile *rcp) {
+ FILE *f = rcp->rf_f;
+ int state = stNewLine, c;
+ struct rcsection *rsp = NULL;
+ struct rckey *rkp = NULL;
+ char buf[2048];
+ char *next = buf, *last = &buf[sizeof(buf)-1];
+
+ while ((c = getc (f)) != EOF) {
+ if (c == '\r')
+ continue;
+ if (state == stNewLine) {
+ next = buf;
+ if (isspace(c))
+ continue; /* skip leading junk */
+ if (c == '[') {
+ state = stHeader;
+ rsp = NULL;
+ continue;
+ }
+ if (c == '#' || c == ';') {
+ state = stSkipToEOL;
+ } else { /* something meaningfull */
+ state = stGetKey;
+ }
+ }
+ if (state == stSkipToEOL || next == last) {/* ignore long lines */
+ if (c == '\n'){
+ state = stNewLine;
+ next = buf;
+ }
+ continue;
+ }
+ if (state == stHeader) {
+ if (c == ']') {
+ *next = 0;
+ next = buf;
+ rsp = rc_addsect(rcp, buf);
+ state = stSkipToEOL;
+ } else
+ *next++ = c;
+ continue;
+ }
+ if (state == stGetKey) {
+ if (c == ' ' || c == '\t')/* side effect: 'key name='*/
+ continue; /* become 'keyname=' */
+ if (c == '\n') { /* silently ignore ... */
+ state = stNewLine;
+ continue;
+ }
+ if (c != '=') {
+ *next++ = c;
+ continue;
+ }
+ *next = 0;
+ if (rsp == NULL) {
+ fprintf(stderr, "Key '%s' defined before section\n", buf);
+ state = stSkipToEOL;
+ continue;
+ }
+ rkp = rc_sect_addkey(rsp, buf, NULL);
+ next = buf;
+ state = stGetValue;
+ continue;
+ }
+ /* only stGetValue left */
+ if (state != stGetValue) {
+ fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name);
+ state = stSkipToEOL;
+ }
+ if (c != '\n') {
+ *next++ = c;
+ continue;
+ }
+ *next = 0;
+ rkp->rk_value = strdup(buf);
+ state = stNewLine;
+ rkp = NULL;
+ } /* while */
+ if (c == EOF && state == stGetValue) {
+ *next = 0;
+ rkp->rk_value = strdup(buf);
+ }
+ return;
+}
+
+int
+rc_getstringptr(struct rcfile *rcp,char *section, char *key,char **dest) {
+ struct rcsection *rsp;
+ struct rckey *rkp;
+
+ *dest = NULL;
+ rsp = rc_findsect(rcp, section);
+ if (!rsp) return ENOENT;
+ rkp = rc_sect_findkey(rsp,key);
+ if (!rkp) return ENOENT;
+ *dest = rkp->rk_value;
+ return 0;
+}
+
+int
+rc_getstring(struct rcfile *rcp,char *section, char *key,int maxlen,char *dest) {
+ char *value;
+ int error;
+
+ error = rc_getstringptr(rcp, section, key, &value);
+ if (error) return error;
+ if (strlen(value) >= maxlen) {
+ fprintf(stderr, "line too long for key '%s' in section '%s', max = %d\n",key, section, maxlen);
+ return EINVAL;
+ }
+ strcpy(dest,value);
+ return 0;
+}
+
+int
+rc_getint(struct rcfile *rcp,char *section, char *key,int *value) {
+ struct rcsection *rsp;
+ struct rckey *rkp;
+
+ rsp = rc_findsect(rcp, section);
+ if (!rsp) return ENOENT;
+ rkp = rc_sect_findkey(rsp,key);
+ if (!rkp) return ENOENT;
+ errno = 0;
+ *value = strtol(rkp->rk_value,NULL,0);
+ if (errno) {
+ fprintf(stderr, "invalid int value '%s' for key '%s' in section '%s'\n",rkp->rk_value,key,section);
+ return errno;
+ }
+ return 0;
+}
+
+/*
+ * 1,yes,true
+ * 0,no,false
+ */
+int
+rc_getbool(struct rcfile *rcp,char *section, char *key,int *value) {
+ struct rcsection *rsp;
+ struct rckey *rkp;
+ char *p;
+
+ rsp = rc_findsect(rcp, section);
+ if (!rsp) return ENOENT;
+ rkp = rc_sect_findkey(rsp,key);
+ if (!rkp) return ENOENT;
+ p = rkp->rk_value;
+ while (*p && isspace(*p)) p++;
+ if (*p == '0' || strcasecmp(p,"no") == 0 || strcasecmp(p,"false") == 0) {
+ *value = 0;
+ return 0;
+ }
+ if (*p == '1' || strcasecmp(p,"yes") == 0 || strcasecmp(p,"true") == 0) {
+ *value = 1;
+ return 0;
+ }
+ fprintf(stderr, "invalid boolean value '%s' for key '%s' in section '%s' \n",p, key, section);
+ return EINVAL;
+}
+
+/*
+ * first read ~/.nwfsrc, next try to merge NWFS_CFG_FILE
+ */
+int
+ncp_open_rcfile(void) {
+ char *home, *fn;
+ int error;
+
+ home = getenv("HOME");
+ if (home) {
+ fn = malloc(strlen(home) + 20);
+ sprintf(fn, "%s/.nwfsrc", home);
+ error = rc_open(fn,"r",&ncp_rc);
+ free (fn);
+ }
+ error = rc_merge(NWFS_CFG_FILE, &ncp_rc);
+ if( ncp_rc == NULL ) {
+ printf("Warning: no cfg files found.\n");
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/lib/libncp/ncpl_rpc.c b/lib/libncp/ncpl_rpc.c
new file mode 100644
index 000000000000..f2f9e54425e4
--- /dev/null
+++ b/lib/libncp/ncpl_rpc.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * NetWare RPCs
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <netncp/ncp_lib.h>
+
+struct ncp_rpc_rq {
+ nuint16 len; /* HL */
+ nuint8 subfn;
+ nuint32 reserved[4];
+ nuint8 flags[4];
+} __attribute__ ((packed));
+
+struct ncp_rpc_rp {
+ nuint32 rpccode;
+ nuint32 reserved[4];
+ nuint32 rpcval;
+} __attribute__ ((packed));
+
+static NWCCODE
+ncp_rpc(NWCONN_HANDLE cH, int rpcfn,
+ const nuint8* rpcarg, char* arg1, char *arg2,
+ nuint32* rpcval) {
+ NWCCODE error;
+ NW_FRAGMENT rq[4], rp;
+ struct ncp_rpc_rq rqh;
+ struct ncp_rpc_rp rph;
+
+ rqh.subfn = rpcfn;
+ if (rpcarg)
+ bcopy(rpcarg, rqh.reserved, 4 * 4 + 4);
+ else
+ bzero(rqh.reserved, 4 * 4 + 4);
+ rq[0].fragAddress = (char*)&rqh;
+ rq[0].fragSize = sizeof(rqh);
+ rq[1].fragAddress = arg1;
+ rq[1].fragSize = strlen(arg1) + 1;
+ rq[2].fragAddress = arg2;
+ rq[2].fragSize = arg2 ? (strlen(arg2) + 1) : 0;
+ rqh.len = htons(rq[2].fragSize + rq[1].fragSize + sizeof(rqh) - 2);
+ rp.fragAddress = (char*)&rph;
+ rp.fragSize = sizeof(rph);
+ error = NWRequest(cH, 131, 3, rq, 1, &rp);
+ if (error) return error;
+ if (rp.fragSize < 4) return EBADRPC;
+ error = rph.rpccode;
+ if (error) return error;
+ if (rpcval) {
+ if (rp.fragSize < 24)
+ return EBADRPC;
+ *rpcval = rph.rpcval;
+ }
+ return 0;
+}
+
+NWCCODE
+NWSMLoadNLM(NWCONN_HANDLE cH, pnstr8 cmd) {
+ return ncp_rpc(cH, 1, NULL, cmd, NULL, NULL);
+}
+
+NWCCODE
+NWSMUnloadNLM(NWCONN_HANDLE cH, pnstr8 cmd) {
+ return ncp_rpc(cH, 2, NULL, cmd, NULL, NULL);
+}
+
+NWCCODE
+NWSMMountVolume(NWCONN_HANDLE cH, pnstr8 volName, nuint32* volnum) {
+ return ncp_rpc(cH, 3, NULL, volName, NULL, volnum);
+}
+
+NWCCODE
+NWSMDismountVolumeByName(NWCONN_HANDLE cH, pnstr8 vol) {
+ return ncp_rpc(cH, 4, NULL, vol, NULL, NULL);
+}
+
+struct ncp_set_hdr {
+ nuint32 typeFlag; /* 0 - str, 1 - value */
+ nuint32 value;
+ nuint32 pad[20 - 4 - 4];
+} __attribute__ ((packed));
+
+NWCCODE
+NWSMSetDynamicCmdIntValue(NWCONN_HANDLE cH, pnstr8 setCommandName, nuint32 cmdValue) {
+ struct ncp_set_hdr rq;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.typeFlag = 1;
+ rq.value = cmdValue;
+ return ncp_rpc(cH, 6, (char*)&rq, setCommandName, NULL, NULL);
+}
+
+NWCCODE
+NWSMSetDynamicCmdStrValue(NWCONN_HANDLE cH, pnstr8 setCommandName,
+ pnstr8 cmdValue) {
+ return ncp_rpc(cH, 6, NULL, setCommandName, cmdValue, NULL);
+}
+
+NWCCODE
+NWSMExecuteNCFFile(NWCONN_HANDLE cH, pnstr8 NCFFileName) {
+ return ncp_rpc(cH, 7, NULL, NCFFileName, NULL, NULL);
+}
diff --git a/lib/libncp/ncpl_subr.c b/lib/libncp/ncpl_subr.c
new file mode 100644
index 000000000000..c7606c72abe8
--- /dev/null
+++ b/lib/libncp/ncpl_subr.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/sysctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <netncp/ncp_lib.h>
+#include <netncp/ncp_rcfile.h>
+#include <netncp/ncp_nls.h>
+/*#include <netncp/ncp_cfg.h>*/
+#include "ncp_mod.h"
+
+int sysentoffset;
+
+void
+ncp_add_word_lh(struct ncp_buf *conn, u_int16_t x) {
+ setwle(conn->packet, conn->rqsize, x);
+ conn->rqsize += 2;
+ return;
+}
+
+void
+ncp_add_dword_lh(struct ncp_buf *conn, u_int32_t x) {
+ setdle(conn->packet, conn->rqsize, x);
+ conn->rqsize += 4;
+ return;
+}
+
+void
+ncp_add_word_hl(struct ncp_buf *conn, u_int16_t x){
+ setwbe(conn->packet, conn->rqsize, x);
+ conn->rqsize += 2;
+ return;
+}
+
+void
+ncp_add_dword_hl(struct ncp_buf *conn, u_int32_t x) {
+ setdbe(conn->packet, conn->rqsize, x);
+ conn->rqsize += 4;
+ return;
+}
+
+void
+ncp_add_mem(struct ncp_buf *conn, const void *source, int size) {
+ memcpy(conn->packet+conn->rqsize, source, size);
+ conn->rqsize += size;
+ return;
+}
+
+void
+ncp_add_mem_nls(struct ncp_buf *conn, const void *source, int size) {
+ ncp_nls_mem_u2n(conn->packet+conn->rqsize, source, size);
+ conn->rqsize += size;
+ return;
+}
+
+void
+ncp_add_pstring(struct ncp_buf *conn, const char *s) {
+ int len = strlen(s);
+ if (len > 255) {
+ ncp_printf("ncp_add_pstring: string too long: %s\n", s);
+ len = 255;
+ }
+ ncp_add_byte(conn, len);
+ ncp_add_mem(conn, s, len);
+ return;
+}
+
+void
+ncp_add_handle_path(struct ncp_buf *conn, nuint32 volNumber, nuint32 dirNumber,
+ int handleFlag, const char *path)
+{
+ ncp_add_byte(conn, volNumber);
+ ncp_add_dword_lh(conn, dirNumber);
+ ncp_add_byte(conn, handleFlag);
+ if (path) {
+ ncp_add_byte(conn, 1); /* 1 component */
+ ncp_add_pstring(conn, path);
+ } else {
+ ncp_add_byte(conn, 0);
+ }
+}
+
+void
+ncp_init_request(struct ncp_buf *conn) {
+ conn->rqsize = 0;
+ conn->rpsize = 0;
+}
+
+void
+ncp_init_request_s(struct ncp_buf *conn, int subfn) {
+ ncp_init_request(conn);
+ ncp_add_word_lh(conn, 0);
+ ncp_add_byte(conn, subfn);
+}
+
+u_int16_t
+ncp_reply_word_hl(struct ncp_buf *conn, int offset) {
+ return getwbe(ncp_reply_data(conn, offset), 0);
+}
+
+u_int16_t
+ncp_reply_word_lh(struct ncp_buf *conn, int offset) {
+ return getwle(ncp_reply_data(conn, offset), 0);
+}
+
+u_int32_t
+ncp_reply_dword_hl(struct ncp_buf *conn, int offset) {
+ return getdbe(ncp_reply_data(conn, offset), 0);
+}
+
+u_int32_t
+ncp_reply_dword_lh(struct ncp_buf *conn, int offset) {
+ return getdle(ncp_reply_data(conn, offset), 0);
+}
+
+
+int
+ncp_connect(struct ncp_conn_args *li, int *connHandle) {
+ return syscall(NCP_CONNECT,li,connHandle);
+}
+
+int
+ncp_disconnect(int cH) {
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_CONNCLOSE);
+ return ncp_conn_request(cH, conn);
+}
+
+int
+ncp_request(int connHandle,int function, struct ncp_buf *ncpbuf){
+ int err = syscall(SNCP_REQUEST,connHandle,function,ncpbuf);
+ return (err<0) ? errno : 0;
+}
+
+int
+ncp_conn_request(int connHandle, struct ncp_buf *ncpbuf){
+ return syscall(SNCP_REQUEST, connHandle, NCP_CONN, ncpbuf);
+}
+
+int
+ncp_conn_scan(struct ncp_conn_loginfo *li, int *connid) {
+ return syscall(NCP_CONNSCAN,li, connid);
+}
+
+NWCCODE
+NWRequest(NWCONN_HANDLE cH, nuint16 fn,
+ nuint16 nrq, NW_FRAGMENT* rq,
+ nuint16 nrp, NW_FRAGMENT* rp)
+{
+ int error;
+ struct ncp_conn_frag nf;
+ DECLARE_RQ;
+
+ ncp_init_request(conn);
+ ncp_add_byte(conn, NCP_CONN_FRAG);
+ nf.fn = fn;
+ nf.rqfcnt = nrq;
+ nf.rqf = rq;
+ nf.rpf = rp;
+ nf.rpfcnt = nrp;
+ ncp_add_mem(conn, &nf, sizeof(nf));
+ error = ncp_conn_request(cH, conn);
+ return error;
+}
+
+
+int
+ncp_initlib(void){
+ int error;
+ int len = sizeof(sysentoffset);
+ int kv, kvlen = sizeof(kv);
+ static int ncp_initialized;
+
+ if (ncp_initialized)
+ return 0;
+#if __FreeBSD_version < 400001
+ error = sysctlbyname("net.ipx.ncp.sysent", &sysentoffset, &len, NULL, 0);
+#else
+ error = sysctlbyname("net.ncp.sysent", &sysentoffset, &len, NULL, 0);
+#endif
+ if (error) {
+ fprintf(stderr, "%s: can't find kernel module\n", __FUNCTION__);
+ return error;
+ }
+#if __FreeBSD_version < 400001
+ error = sysctlbyname("net.ipx.ncp.version", &kv, &kvlen, NULL, 0);
+#else
+ error = sysctlbyname("net.ncp.version", &kv, &kvlen, NULL, 0);
+#endif
+ if (error) {
+ fprintf(stderr, "%s: kernel module is old, please recompile it.\n", __FUNCTION__);
+ return error;
+ }
+ if (NCP_VERSION != kv) {
+ fprintf(stderr, "%s: kernel module version(%d) don't match library(%d).\n", __FUNCTION__, kv, NCP_VERSION);
+ return EINVAL;
+ }
+ if ((error = ncp_nls_setrecode(0)) != 0) {
+ fprintf(stderr, "%s: can't initialise recode\n", __FUNCTION__);
+ return error;
+ }
+ if ((error = ncp_nls_setlocale("")) != 0) {
+ fprintf(stderr, "%s: can't initialise locale\n", __FUNCTION__);
+ return error;
+ }
+ ncp_initialized++;
+ return 0;
+}
+
+
+/*
+ */
+int ncp_opterr = 1, /* if error message should be printed */
+ ncp_optind = 1, /* index into parent argv vector */
+ ncp_optopt, /* character checked for validity */
+ ncp_optreset; /* reset getopt */
+char *ncp_optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+int
+ncp_getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ extern char *__progname;
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+ int tmpind;
+
+ if (ncp_optreset || !*place) { /* update scanning pointer */
+ ncp_optreset = 0;
+ tmpind = ncp_optind;
+ while (1) {
+ if (tmpind >= nargc) {
+ place = EMSG;
+ return (-1);
+ }
+ if (*(place = nargv[tmpind]) != '-') {
+ tmpind++;
+ continue; /* lookup next option */
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ ncp_optind = ++tmpind;
+ place = EMSG;
+ return (-1);
+ }
+ ncp_optind = tmpind;
+ break;
+ }
+ } /* option letter okay? */
+ if ((ncp_optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, ncp_optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (ncp_optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++ncp_optind;
+ if (ncp_opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname, ncp_optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ ncp_optarg = NULL;
+ if (!*place)
+ ++ncp_optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ ncp_optarg = place;
+ else if (nargc <= ++ncp_optind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (ncp_opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname, ncp_optopt);
+ return (BADCH);
+ }
+ else /* white space */
+ ncp_optarg = nargv[ncp_optind];
+ place = EMSG;
+ ++ncp_optind;
+ }
+ return (ncp_optopt); /* dump back option letter */
+}
+/*
+ * misc options parsing routines
+ */
+int
+ncp_args_parserc(struct ncp_args *na, char *sect, ncp_setopt_t *set_callback) {
+ int len, error;
+
+ for (; na->opt; na++) {
+ switch (na->at) {
+ case NCA_STR:
+ if (rc_getstringptr(ncp_rc,sect,na->name,&na->str) == 0) {
+ len = strlen(na->str);
+ if (len > na->ival) {
+ fprintf(stderr,"rc: Argument for option '%c' (%s) too long\n",na->opt,na->name);
+ return EINVAL;
+ }
+ set_callback(na);
+ }
+ break;
+ case NCA_BOOL:
+ error = rc_getbool(ncp_rc,sect,na->name,&na->ival);
+ if (error == ENOENT) break;
+ if (error) return EINVAL;
+ set_callback(na);
+ break;
+ case NCA_INT:
+ if (rc_getint(ncp_rc,sect,na->name,&na->ival) == 0) {
+ if (((na->flag & NAFL_HAVEMIN) &&
+ (na->ival < na->min)) ||
+ ((na->flag & NAFL_HAVEMAX) &&
+ (na->ival > na->max))) {
+ fprintf(stderr,"rc: Argument for option '%c' (%s) should be in [%d-%d] range\n",na->opt,na->name,na->min,na->max);
+ return EINVAL;
+ }
+ set_callback(na);
+ };
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+int
+ncp_args_parseopt(struct ncp_args *na, int opt, char *optarg, ncp_setopt_t *set_callback) {
+ int len;
+
+ for (; na->opt; na++) {
+ if (na->opt != opt) continue;
+ switch (na->at) {
+ case NCA_STR:
+ na->str = optarg;
+ if (optarg) {
+ len = strlen(na->str);
+ if (len > na->ival) {
+ fprintf(stderr,"opt: Argument for option '%c' (%s) too long\n",na->opt,na->name);
+ return EINVAL;
+ }
+ set_callback(na);
+ }
+ break;
+ case NCA_BOOL:
+ na->ival = 0;
+ set_callback(na);
+ break;
+ case NCA_INT:
+ errno = 0;
+ na->ival = strtol(optarg, NULL, 0);
+ if (errno) {
+ fprintf(stderr,"opt: Invalid integer value for option '%c' (%s).\n",na->opt,na->name);
+ return EINVAL;
+ }
+ if (((na->flag & NAFL_HAVEMIN) &&
+ (na->ival < na->min)) ||
+ ((na->flag & NAFL_HAVEMAX) &&
+ (na->ival > na->max))) {
+ fprintf(stderr,"opt: Argument for option '%c' (%s) should be in [%d-%d] range\n",na->opt,na->name,na->min,na->max);
+ return EINVAL;
+ }
+ set_callback(na);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Print a (descriptive) error message
+ * error values:
+ * 0 - no specific error code available;
+ * -999..-1 - NDS error
+ * 1..32767 - system error
+ * the rest - requester error;
+ */
+void
+ncp_error(char *fmt, int error,...) {
+ va_list ap;
+
+ va_start(ap, error);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (error == -1)
+ error = errno;
+ if (error > -1000 && error < 0) {
+ fprintf(stderr, ": dserr = %d\n", error);
+ } else if (error & 0x8000) {
+ fprintf(stderr, ": nwerr = %04x\n", error);
+ } else if (error) {
+ fprintf(stderr, ": syserr = %s\n", strerror(error));
+ } else
+ fprintf(stderr, "\n");
+}
+
+char *
+ncp_printb(char *dest, int flags, const struct ncp_bitname *bnp) {
+ int first = 1;
+
+ strcpy(dest, "<");
+ for(; bnp->bn_bit; bnp++) {
+ if (flags & bnp->bn_bit) {
+ strcat(dest, bnp->bn_name);
+ first = 0;
+ }
+ if (!first && (flags & bnp[1].bn_bit))
+ strcat(dest, "|");
+ }
+ strcat(dest, ">");
+ return dest;
+}
diff --git a/lib/libncp/sap.c b/lib/libncp/sap.c
new file mode 100644
index 000000000000..32e0ab217111
--- /dev/null
+++ b/lib/libncp/sap.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1999, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netipx/ipx.h>
+#include <errno.h>
+#include <unistd.h>
+#include "ipxsap.h"
+
+/*
+ * TODO: These should go to ipx headers
+ */
+#define ipx_set_net(x,y) ((x).x_net.s_net[0] = (y).x_net.s_net[0]); \
+ ((x).x_net.s_net[1]=(y).x_net.s_net[1])
+#define ipx_set_nullnet(x) ((x).x_net.s_net[0]=0); ((x).x_net.s_net[1]=0)
+#define ipx_set_nullhost(x) ((x).x_host.s_host[0] = 0); \
+ ((x).x_host.s_host[1] = 0); ((x).x_host.s_host[2] = 0)
+#define ipx_set_wildnet(x) ((x).x_net.s_net[0] = 0xFFFF); \
+ ((x).x_net.s_net[1]=0xFFFF)
+#define ipx_set_wildhost(x) ((x).x_host.s_host[0] = 0xFFFF); \
+ ((x).x_host.s_host[1] = 0xFFFF); ((x).x_host.s_host[2] = 0xFFFF);
+
+
+static struct sap_packet* sap_packet_alloc(int entries);
+static int sap_size(int entries, u_short operation);
+int (*sap_sendto_func)(void*,int,struct sockaddr_ipx*,int sock)=NULL;
+
+static int
+sap_sendto(void* buffer, int size, struct sockaddr_ipx* daddr, int sock)
+{
+ if (sap_sendto_func)
+ return sap_sendto_func(buffer,size,daddr,sock);
+ return sendto(sock, (char*)buffer, size, 0,
+ (struct sockaddr*)daddr, sizeof(*daddr));
+}
+
+static struct sap_packet*
+sap_packet_alloc(int entries)
+{
+ if (entries > IPX_SAP_MAX_ENTRIES)
+ return NULL;
+ return
+ (struct sap_packet*)malloc(sap_size(entries, IPX_SAP_GENERAL_RESPONSE));
+}
+
+static int
+sap_size(int entries, u_short operation)
+{
+ if (entries <= 0)
+ return 0;
+ switch (operation) {
+ case IPX_SAP_GENERAL_QUERY:
+ return entries == 1 ? IPX_SAP_REQUEST_LEN : 0;
+ case IPX_SAP_GENERAL_RESPONSE:
+ if (entries > IPX_SAP_MAX_ENTRIES)
+ return 0;
+ return sizeof(struct sap_packet) + (entries - 1) * sizeof(struct sap_entry);
+ case IPX_SAP_NEAREST_QUERY:
+ return entries == 1 ? IPX_SAP_REQUEST_LEN : 0;
+ case IPX_SAP_NEAREST_RESPONSE:
+ return entries == 1 ? sizeof(struct sap_packet) : 0;
+ default:
+ return 0;
+ }
+}
+
+void
+sap_copyname(char *dest, const char *src)
+{
+ bzero(dest, IPX_SAP_SERVER_NAME_LEN);
+ strncpy(dest, src, IPX_SAP_SERVER_NAME_LEN - 1);
+}
+
+int
+sap_rq_init(struct sap_rq* rq, int sock)
+{
+ rq->buffer = sap_packet_alloc(IPX_SAP_MAX_ENTRIES);
+ if (rq->buffer == NULL)
+ return 0;
+ rq->entries = 0;
+ rq->buffer->operation = htons(IPX_SAP_GENERAL_QUERY);
+ rq->dest_addr.sipx_family = AF_IPX;
+ rq->dest_addr.sipx_len = sizeof(struct sockaddr_ipx);
+ rq->sock = sock;
+ return 1;
+}
+
+int
+sap_rq_flush(struct sap_rq* rq)
+{
+ int result;
+
+ if (rq->entries == 0)
+ return 0;
+ result = sap_sendto(rq->buffer,
+ sap_size(rq->entries, ntohs(rq->buffer->operation)),
+ &rq->dest_addr, rq->sock);
+ rq->entries = 0;
+ return result;
+}
+
+void
+sap_rq_general_query(struct sap_rq* rq, u_short ser_type)
+{
+ struct sap_entry* sep;
+
+ sap_rq_flush(rq);
+ rq->buffer->operation = htons(IPX_SAP_GENERAL_QUERY);
+ sep = rq->buffer->sap_entries + rq->entries++;
+ sep->server_type = htons(ser_type);
+}
+
+void
+sap_rq_gns_request(struct sap_rq* rq, u_short ser_type)
+{
+ struct sap_entry* sep;
+
+ sap_rq_flush(rq);
+ rq->buffer->operation = htons(IPX_SAP_NEAREST_QUERY);
+ sep = rq->buffer->sap_entries + rq->entries++;
+ sep->server_type = htons(ser_type);
+}
+
+void
+sap_rq_general_response(struct sap_rq* rq,u_short type,char *name,struct sockaddr_ipx* addr, u_short hops,int down_allow)
+{
+ struct sap_entry* sep;
+
+ if (hops >= IPX_SAP_SERVER_DOWN && !down_allow) return;
+ if (rq->entries >= IPX_SAP_MAX_ENTRIES)
+ sap_rq_flush(rq);
+ if (rq->buffer->operation != htons(IPX_SAP_GENERAL_RESPONSE)){
+ sap_rq_flush(rq);
+ rq->buffer->operation = htons(IPX_SAP_GENERAL_RESPONSE);
+ }
+ sep = rq->buffer->sap_entries + rq->entries;
+ sep->server_type = htons(type);
+ sap_copyname(sep->server_name, name);
+ memcpy(&sep->ipx, &addr->sipx_addr, sizeof(struct ipx_addr));
+ sep->hops = htons(hops);
+ rq->entries++;
+}
+
+void
+sap_rq_gns_response(struct sap_rq* rq,u_short type,char *name,struct sockaddr_ipx* addr,u_short hops)
+{
+ struct sap_entry* sep;
+
+ if (hops >= IPX_SAP_SERVER_DOWN) return;
+ sap_rq_flush(rq);
+ rq->buffer->operation = htons(IPX_SAP_NEAREST_RESPONSE);
+ sep = rq->buffer->sap_entries + rq->entries;
+ sep->server_type = htons(type);
+ sap_copyname(sep->server_name, name);
+ memcpy(&sep->ipx, &addr->sipx_addr, sizeof(struct ipx_addr));
+ sep->hops = htons(hops);
+ rq->entries++;
+}
+
+void
+sap_rq_set_destination(struct sap_rq* rq,struct ipx_addr *dest)
+{
+ sap_rq_flush(rq);
+ memcpy(&rq->dest_addr.sipx_addr,dest,sizeof(struct ipx_addr));
+}
+
+int
+sap_getsock(int *rsock) {
+ struct sockaddr_ipx sap_addr;
+ int opt, sock, slen;
+
+ sock = socket(AF_IPX, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return (errno);
+ slen = sizeof(sap_addr);
+ bzero(&sap_addr, slen);
+ sap_addr.sipx_family = AF_IPX;
+ sap_addr.sipx_len = slen;
+ if (bind(sock, (struct sockaddr*)&sap_addr, slen) == -1) {
+ close(sock);
+ return(errno);
+ }
+ opt = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) != 0){
+ close(sock);
+ return(errno);
+ }
+ *rsock = sock;
+ return(0);
+}
+
+static int
+sap_recv(int sock,void *buf,int len,int flags, int timeout){
+ fd_set rd, wr, ex;
+ struct timeval tv;
+ int result;
+
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_ZERO(&ex);
+ FD_SET(sock, &rd);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ if ((result = select(sock + 1, &rd, &wr, &ex, &tv)) == -1) {
+ return result;
+ }
+ if (FD_ISSET(sock, &rd)) {
+ result = recv(sock, buf, len, flags);
+ } else {
+ errno = ETIMEDOUT;
+ result = -1;
+ }
+ return result;
+}
+
+int
+sap_find_nearest(int server_type, struct sockaddr_ipx *daddr, char *server_name)
+{
+ struct ipx_addr addr;
+ char data[1024];
+ int sock, error, packets, len;
+ struct sap_packet *reply = (struct sap_packet*)&data;
+ struct sap_rq sap_rq;
+
+ error = sap_getsock(&sock);
+ if (error)
+ return error;
+ bzero(&addr, sizeof(addr));
+ /* BAD: we should enum all ifs (and nets ?) */
+ if (ipx_iffind(NULL, &addr) != 0) {
+ return (EPROTONOSUPPORT);
+ }
+ ipx_set_wildhost(addr);
+ addr.x_port = htons(IPXPORT_SAP);
+
+ if (!sap_rq_init(&sap_rq, sock)) {
+ close(sock);
+ return(ENOMEM);
+ }
+ sap_rq_set_destination(&sap_rq, &addr);
+ sap_rq_gns_request(&sap_rq, server_type);
+ sap_rq_flush(&sap_rq);
+ packets = 5;
+ do {
+ len = sap_recv(sock, data, sizeof(data), 0, 1);
+ if (len < 66) {
+ packets++;
+ continue;
+ }
+ } while (ntohs(reply->operation) != IPX_SAP_NEAREST_RESPONSE &&
+ packets > 0);
+
+ if (packets == 0) {
+ close(sock);
+ return ENETDOWN;
+ }
+
+ daddr->sipx_addr = reply->sap_entries[0].ipx;
+ daddr->sipx_family = AF_IPX;
+ daddr->sipx_len = sizeof(struct sockaddr_ipx);
+ sap_copyname(server_name, reply->sap_entries[0].server_name);
+ errno = 0;
+ close(sock);
+ return 0;
+}