From e593016a80ceee52b6e3244512ff4307f8c208fa Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Wed, 10 May 2006 17:31:32 +0000 Subject: Add NTLM support. --- daemon/smbval/rfcnb-util.inc.c | 257 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 daemon/smbval/rfcnb-util.inc.c (limited to 'daemon/smbval/rfcnb-util.inc.c') 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 +#include +#include + +#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; + } +} -- cgit v1.2.3