summaryrefslogtreecommitdiff
path: root/daemon/smbval/rfcnb-util.inc.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/smbval/rfcnb-util.inc.c')
-rw-r--r--daemon/smbval/rfcnb-util.inc.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/daemon/smbval/rfcnb-util.inc.c b/daemon/smbval/rfcnb-util.inc.c
new file mode 100644
index 0000000..31e7e05
--- /dev/null
+++ b/daemon/smbval/rfcnb-util.inc.c
@@ -0,0 +1,257 @@
+/* mod_ntlm file: $Id: rfcnb-util.inc.c,v 1.2 2003/02/21 01:55:14 casz Exp $ */
+
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+ *
+ * Version 1.0 RFCNB Utility Routines ...
+ *
+ * Copyright (C) Richard Sharpe 1996
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details. You
+ * should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <string.h>
+#include <malloc.h>
+#include <stdint.h>
+
+#include "std-includes.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+
+/* Convert name and pad to 16 chars as needed. Name 1 is a C string
+ * with null termination, name 2 may not be. If SysName is true, then
+ * put a <00> on end, else space> */
+static void
+RFCNB_CvtPad_Name(char *name1, char *name2)
+{
+ char c, c1, c2;
+ int i, len;
+
+ len = strlen(name1);
+ for (i = 0; i < 16; i++) {
+ if (i >= len) {
+ c1 = 'C';
+ c2 = 'A'; /* CA is a space */
+ } else {
+ c = name1[i];
+ c1 = (char) ((int) c / 16 + (int) 'A');
+ c2 = (char) ((int) c % 16 + (int) 'A');
+ }
+ name2[i * 2] = c1;
+ name2[i * 2 + 1] = c2;
+ }
+ name2[32] = 0; /* Put in the nll ... */
+}
+
+/* Get a packet of size n */
+static struct RFCNB_Pkt *
+RFCNB_Alloc_Pkt(int n)
+{
+ RFCNB_Pkt *pkt;
+
+ if ((pkt = (struct RFCNB_Pkt *) malloc(
+ sizeof(struct RFCNB_Pkt))) == NULL) {
+ RFCNB_errno = RFCNBE_NoSpace;
+ RFCNB_saved_errno = errno;
+ return NULL;
+ }
+ pkt->next = NULL;
+ pkt->len = n;
+
+ if (n == 0)
+ return pkt;
+
+ if ((pkt->data = (char *) malloc(n)) == NULL) {
+ RFCNB_errno = RFCNBE_NoSpace;
+ RFCNB_saved_errno = errno;
+ free(pkt);
+ return (NULL);
+ }
+ return pkt;
+}
+
+/* Free up a packet */
+static void
+RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
+{
+ struct RFCNB_Pkt *pkt_next;
+ char *data_ptr;
+
+ while (pkt != NULL) {
+ pkt_next = pkt->next;
+ data_ptr = pkt->data;
+ if (data_ptr != NULL)
+ free(data_ptr);
+ free(pkt);
+ pkt = pkt_next;
+ }
+}
+
+/* Resolve a name into an address */
+static int
+RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
+{
+ int addr; /* Assumes IP4, 32 bit network addresses */
+ struct hostent *hp;
+
+ /* Use inet_addr to try to convert the address */
+ if ((addr = inet_addr(host)) == INADDR_NONE) { /* a good try :-) */
+ /* Now try a name look up with gethostbyname */
+ if ((hp = gethostbyname(host)) == NULL) { /* Not in DNS */
+ /* Try NetBIOS name lookup, how the hell do we do that? */
+ RFCNB_errno = RFCNBE_BadName; /* Is this right? */
+ RFCNB_saved_errno = errno;
+ return (RFCNBE_Bad);
+ } else { /* We got a name */
+ memcpy((void *) Dest_IP, (void *) hp->h_addr_list[0],
+ sizeof(struct in_addr));
+ }
+ } else { /* It was an IP address */
+ memcpy((void *) Dest_IP, (void *) &addr, sizeof(struct in_addr));
+ }
+ return 0;
+}
+
+/* Disconnect the TCP connection to the server */
+static int
+RFCNB_Close(int socket)
+{
+ close(socket);
+ /* If we want to do error recovery, here is where we put it */
+ return 0;
+}
+
+/* Connect to the server specified in the IP address. Not sure how to
+ * handle socket options etc. */
+static int
+RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
+{
+ struct sockaddr_in Socket;
+ int fd;
+
+ /* Create a socket */
+ if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
+ RFCNB_errno = RFCNBE_BadSocket;
+ RFCNB_saved_errno = errno;
+ return (RFCNBE_Bad);
+ }
+ bzero((char *) &Socket, sizeof(Socket));
+ memcpy((char *) &Socket.sin_addr, (char *) &Dest_IP, sizeof(Dest_IP));
+
+ Socket.sin_port = htons(port);
+ Socket.sin_family = PF_INET;
+
+ /* Now connect to the destination */
+ if (connect(fd, (struct sockaddr *) &Socket, sizeof(Socket)) < 0) {
+ /* Error */
+ close(fd);
+ RFCNB_errno = RFCNBE_ConnectFailed;
+ RFCNB_saved_errno = errno;
+ return (RFCNBE_Bad);
+ }
+ return fd;
+}
+
+/* handle the details of establishing the RFCNB session with remote end */
+static int
+RFCNB_Session_Req(struct RFCNB_Con *con,
+ char *Called_Name,
+ char *Calling_Name,
+ BOOL * redirect,
+ struct in_addr *Dest_IP,
+ int *port)
+{
+ char *sess_pkt;
+
+ /* Response packet should be no more than 9 bytes, make 16 jic */
+ char resp[16];
+ int len;
+ struct RFCNB_Pkt *pkt, res_pkt;
+
+ /* We build and send the session request, then read the response */
+ pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
+ if (pkt == NULL) {
+ return RFCNBE_Bad; /* Leave the error that RFCNB_Alloc_Pkt gives) */
+ }
+ sess_pkt = pkt->data; /* Get pointer to packet proper */
+
+ sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
+ RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len - RFCNB_Pkt_Hdr_Len);
+ sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
+ sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
+
+ RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
+ RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
+
+ /* Now send the packet */
+#ifdef RFCNB_DEBUG
+ fprintf(stderr, "Sending packet: ");
+#endif
+ if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0)
+ return RFCNBE_Bad; /* Should be able to write that lot ... */
+#ifdef RFCNB_DEBUG
+ fprintf(stderr, "Getting packet.\n");
+#endif
+
+ res_pkt.data = resp;
+ res_pkt.len = sizeof(resp);
+ res_pkt.next = NULL;
+
+ if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0)
+ return RFCNBE_Bad;
+
+ /* Now analyze the packet ... */
+ switch (RFCNB_Pkt_Type(resp)) {
+ case RFCNB_SESSION_REJ: /* Didnt like us ... too bad */
+ /* Why did we get rejected ? */
+ switch (CVAL(resp, RFCNB_Pkt_Error_Offset)) {
+ case 0x80:
+ RFCNB_errno = RFCNBE_CallRejNLOCN;
+ break;
+ case 0x81:
+ RFCNB_errno = RFCNBE_CallRejNLFCN;
+ break;
+ case 0x82:
+ RFCNB_errno = RFCNBE_CallRejCNNP;
+ break;
+ case 0x83:
+ RFCNB_errno = RFCNBE_CallRejInfRes;
+ break;
+ case 0x8F:
+ RFCNB_errno = RFCNBE_CallRejUnSpec;
+ break;
+ default:
+ RFCNB_errno = RFCNBE_ProtErr;
+ break;
+ }
+ return (RFCNBE_Bad);
+ break;
+
+ case RFCNB_SESSION_ACK: /* Got what we wanted ... */
+ return (0);
+ break;
+
+ case RFCNB_SESSION_RETARGET: /* Go elsewhere */
+ *redirect = TRUE; /* Copy port and ip addr */
+ memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset),
+ sizeof(struct in_addr));
+ *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
+ return 0;
+ break;
+ default: /* A protocol error */
+ RFCNB_errno = RFCNBE_ProtErr;
+ return (RFCNBE_Bad);
+ break;
+ }
+}