summaryrefslogtreecommitdiff
path: root/daemon/smblib/smblib-util.c
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2004-04-21 17:37:06 +0000
committerStef Walter <stef@memberwebs.com>2004-04-21 17:37:06 +0000
commitff76efc3e5e1b0e4ca3b10b7402406f619509bba (patch)
treec3b1e49235f67eabd22d31ebfc14934743b70858 /daemon/smblib/smblib-util.c
parent01430fca169c1b8d7b1b4f1bdd529aa6bc4be80b (diff)
Initial Import
Diffstat (limited to 'daemon/smblib/smblib-util.c')
-rw-r--r--daemon/smblib/smblib-util.c783
1 files changed, 783 insertions, 0 deletions
diff --git a/daemon/smblib/smblib-util.c b/daemon/smblib/smblib-util.c
new file mode 100644
index 0000000..c91a46e
--- /dev/null
+++ b/daemon/smblib/smblib-util.c
@@ -0,0 +1,783 @@
+/* UNIX SMBlib NetBIOS implementation
+
+ Version 1.0
+ SMBlib 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 "smblib-priv.h"
+
+#include "../rfcnb/rfcnb.h"
+
+/* Print out an SMB pkt in all its gory detail ... */
+
+void SMB_Print_Pkt(FILE fd, RFCNB_Pkt *pkt, BOOL command, int Offset, int Len)
+
+{
+
+ /* Well, just how do we do this ... print it I suppose */
+
+ /* Print out the SMB header ... */
+
+ /* Print the command */
+
+ /* Print the other bits in the header */
+
+
+ /* etc */
+
+}
+
+/* Convert a DOS Date_Time to a local host type date time for printing */
+
+char *SMB_DOSTimToStr(int DOS_time)
+
+{ static char SMB_Time_Temp[48];
+ int DOS_sec, DOS_min, DOS_hour, DOS_day, DOS_month, DOS_year;
+
+ SMB_Time_Temp[0] = 0;
+
+ DOS_sec = (DOS_time & 0x001F) * 2;
+ DOS_min = (DOS_time & 0x07E0) >> 5;
+ DOS_hour = ((DOS_time & 0xF800) >> 11);
+
+ DOS_day = (DOS_time & 0x001F0000) >> 16;
+ DOS_month = (DOS_time & 0x01E00000) >> 21;
+ DOS_year = ((DOS_time & 0xFE000000) >> 25) + 80;
+
+ sprintf(SMB_Time_Temp, "%2d/%02d/%2d %2d:%02d:%02d", DOS_day, DOS_month,
+ DOS_year, DOS_hour, DOS_min, DOS_sec);
+
+ return(SMB_Time_Temp);
+
+}
+
+/* Convert an attribute byte/word etc to a string ... We return a pointer
+ to a static string which we guarantee is long enough. If verbose is
+ true, we print out long form of strings ... */
+
+char *SMB_AtrToStr(int attribs, BOOL verbose)
+
+{ static char SMB_Attrib_Temp[128];
+
+ SMB_Attrib_Temp[0] = 0;
+
+ if (attribs & SMB_FA_ROF)
+ strcat(SMB_Attrib_Temp, (verbose?"Read Only ":"R"));
+
+ if (attribs & SMB_FA_HID)
+ strcat(SMB_Attrib_Temp, (verbose?"Hidden ":"H"));
+
+ if (attribs & SMB_FA_SYS)
+ strcat(SMB_Attrib_Temp, (verbose?"System ":"S"));
+
+ if (attribs & SMB_FA_VOL)
+ strcat(SMB_Attrib_Temp, (verbose?"Volume ":"V"));
+
+ if (attribs & SMB_FA_DIR)
+ strcat(SMB_Attrib_Temp, (verbose?"Directory ":"D"));
+
+ if (attribs & SMB_FA_ARC)
+ strcat(SMB_Attrib_Temp, (verbose?"Archive ":"A"));
+
+ return(SMB_Attrib_Temp);
+
+}
+
+/* Pick up the Max Buffer Size from the Tree Structure ... */
+
+int SMB_Get_Tree_MBS(SMB_Tree_Handle tree)
+
+{
+ if (tree != NULL) {
+ return(tree -> mbs);
+ }
+ else {
+ return(SMBlibE_BAD);
+ }
+}
+
+/* Pick up the Max buffer size */
+
+int SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle)
+
+{
+ if (Con_Handle != NULL) {
+ return(Con_Handle -> max_xmit);
+ }
+ else {
+ return(SMBlibE_BAD);
+ }
+
+}
+/* Pickup the protocol index from the connection structure */
+
+int SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle)
+
+{
+ if (Con_Handle != NULL) {
+ return(Con_Handle -> prot_IDX);
+ }
+ else {
+ return(0xFFFF); /* Invalid protocol */
+ }
+
+}
+
+/* Pick up the protocol from the connection structure */
+
+int SMB_Get_Protocol(SMB_Handle_Type Con_Handle)
+
+{
+ if (Con_Handle != NULL) {
+ return(Con_Handle -> protocol);
+ }
+ else {
+ return(0xFFFF); /* Invalid protocol */
+ }
+
+}
+
+/* Figure out what protocol was accepted, given the list of dialect strings */
+/* We offered, and the index back from the server. We allow for a user */
+/* supplied list, and assume that it is a subset of our list */
+
+int SMB_Figure_Protocol(char *dialects[], int prot_index)
+
+{ int i;
+
+ if (dialects == SMB_Prots) { /* The jobs is easy, just index into table */
+
+ return(SMB_Types[prot_index]);
+ }
+ else { /* Search through SMB_Prots looking for a match */
+
+ for (i = 0; SMB_Prots[i] != NULL; i++) {
+
+ if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) { /* A match */
+
+ return(SMB_Types[i]);
+
+ }
+
+ }
+
+ /* If we got here, then we are in trouble, because the protocol was not */
+ /* One we understand ... */
+
+ return(SMB_P_Unknown);
+
+ }
+
+}
+
+
+/* Negotiate the protocol we will use from the list passed in Prots */
+/* we return the index of the accepted protocol in NegProt, -1 indicates */
+/* none acceptible, and our return value is 0 if ok, <0 if problems */
+
+int SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[])
+
+{ struct SMB_Neg_Prot_Def *prot_pkt;
+ struct SMB_Neg_Prot_Resp_Def *resp_pkt;
+ struct RFCNB_Pkt *pkt;
+ int prots_len, i, pkt_len, prot, alloc_len;
+ char *p;
+
+ /* Figure out how long the prot list will be and allocate space for it */
+
+ prots_len = 0;
+
+ for (i = 0; Prots[i] != NULL; i++) {
+
+ prots_len = prots_len + strlen(Prots[i]) + 2; /* Account for null etc */
+
+ }
+
+ /* The -1 accounts for the one byte smb_buf we have because some systems */
+ /* don't like char msg_buf[] */
+
+ pkt_len = SMB_negp_len + prots_len;
+
+ /* Make sure that the pkt len is long enough for the max response ... */
+ /* Which is a problem, because the encryption key len eec may be long */
+
+ if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) {
+
+ alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40;
+
+ }
+ else {
+
+ alloc_len = pkt_len;
+
+ }
+
+ pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(alloc_len);
+
+ if (pkt == NULL) {
+
+ SMBlib_errno = SMBlibE_NoSpace;
+ return(SMBlibE_BAD);
+
+ }
+
+ /* Now plug in the bits we need */
+
+ bzero(SMB_Hdr(pkt), SMB_negp_len);
+ SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
+ *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot;
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
+ *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+ SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len);
+
+ /* Now copy the prot strings in with the right stuff */
+
+ p = (char *)(SMB_Hdr(pkt) + SMB_negp_buf_offset);
+
+ for (i = 0; Prots[i] != NULL; i++) {
+
+ *p = SMBdialectID;
+ strcpy(p + 1, Prots[i]);
+ p = p + strlen(Prots[i]) + 2; /* Adjust len of p for null plus dialectID */
+
+ }
+
+ /* Now send the packet and sit back ... */
+
+ if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
+
+
+#ifdef DEBUG
+ fprintf(stderr, "Error sending negotiate protocol\n");
+#endif
+
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = -SMBlibE_SendFailed; /* Failed, check lower layer errno */
+ return(SMBlibE_BAD);
+
+ }
+
+ /* Now get the response ... */
+
+ if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, alloc_len) < 0) {
+
+#ifdef DEBUG
+ fprintf(stderr, "Error receiving response to negotiate\n");
+#endif
+
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = -SMBlibE_RecvFailed; /* Failed, check lower layer errno */
+ return(SMBlibE_BAD);
+
+ }
+
+ if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
+
+#ifdef DEBUG
+ fprintf(stderr, "SMB_Negotiate failed with errorclass = %i, Error Code = %i\n",
+ CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+ SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+ SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = SMBlibE_Remote;
+ return(SMBlibE_BAD);
+
+ }
+
+ if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) {
+
+#ifdef DEBUG
+ fprintf(stderr, "None of our protocols was accepted ... ");
+#endif
+
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = SMBlibE_NegNoProt;
+ return(SMBlibE_BAD);
+
+ }
+
+ /* Now, unpack the info from the response, if any and evaluate the proto */
+ /* selected. We must make sure it is one we like ... */
+
+ Con_Handle -> prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset);
+ Con_Handle -> protocol = SMB_Figure_Protocol(Prots, prot);
+
+ if (Con_Handle -> protocol == SMB_P_Unknown) { /* No good ... */
+
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = SMBlibE_ProtUnknown;
+ return(SMBlibE_BAD);
+
+ }
+
+ switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) {
+
+ case 0x01: /* No more info ... */
+
+ break;
+
+ case 13: /* Up to and including LanMan 2.1 */
+
+ Con_Handle -> Security = SVAL(SMB_Hdr(pkt), SMB_negrLM_sec_offset);
+ Con_Handle -> encrypt_passwords = ((Con_Handle -> Security & SMB_sec_encrypt_mask) != 0x00);
+ Con_Handle -> Security = Con_Handle -> Security & SMB_sec_user_mask;
+
+ Con_Handle -> max_xmit = SVAL(SMB_Hdr(pkt), SMB_negrLM_mbs_offset);
+ Con_Handle -> MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrLM_mmc_offset);
+ Con_Handle -> MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrLM_mnv_offset);
+ Con_Handle -> Raw_Support = SVAL(SMB_Hdr(pkt), SMB_negrLM_rm_offset);
+ Con_Handle -> SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrLM_sk_offset);
+ Con_Handle -> SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrLM_stz_offset);
+ Con_Handle -> Encrypt_Key_Len = SVAL(SMB_Hdr(pkt), SMB_negrLM_ekl_offset);
+
+ p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle -> Encrypt_Key_Len);
+
+ strncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom) - 1);
+
+ break;
+
+ case 17: /* NT LM 0.12 and LN LM 1.0 */
+
+ Con_Handle -> Security = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_sec_offset);
+ Con_Handle -> encrypt_passwords = ((Con_Handle -> Security & SMB_sec_encrypt_mask) != 0x00);
+ Con_Handle -> Security = Con_Handle -> Security & SMB_sec_user_mask;
+
+ Con_Handle -> max_xmit = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mbs_offset);
+ Con_Handle -> MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mmc_offset);
+ Con_Handle -> MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mnv_offset);
+ Con_Handle -> MaxRaw = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mrs_offset);
+ Con_Handle -> SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_sk_offset);
+ Con_Handle -> SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_stz_offset);
+ Con_Handle -> Encrypt_Key_Len = CVAL(SMB_Hdr(pkt), SMB_negrNTLM_ekl_offset);
+
+ p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle -> Encrypt_Key_Len);
+
+ strncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom) - 1);
+
+ break;
+
+ default:
+
+#ifdef DEBUG
+ fprintf(stderr, "Unknown NegProt response format ... Ignored\n");
+ fprintf(stderr, " wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset));
+#endif
+
+ break;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]);
+#endif
+
+ RFCNB_Free_Pkt(pkt);
+ return(0);
+
+}
+
+/* Get our hostname */
+
+void SMB_Get_My_Name(char *name, int len)
+
+{ int loc;
+
+ if (gethostname(name, len) < 0) { /* Error getting name */
+
+ strncpy(name, "unknown", len);
+
+ /* Should check the error */
+
+#ifdef DEBUG
+ fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:");
+ perror("");
+#endif
+
+ }
+
+ /* only keep the portion up to the first "." */
+
+
+}
+
+/* Send a TCON to the remote server ... */
+
+SMB_Tree_Handle SMB_TreeConnect(SMB_Handle_Type Con_Handle,
+ SMB_Tree_Handle Tree_Handle,
+ char *path,
+ char *password,
+ char *device)
+
+{ struct RFCNB_Pkt *pkt;
+ int param_len, i, pkt_len;
+ char *p;
+ SMB_Tree_Handle tree;
+
+ /* Figure out how much space is needed for path, password, dev ... */
+
+ if (path == NULL | password == NULL | device == NULL) {
+
+#ifdef DEBUG
+ fprintf(stderr, "Bad parameter passed to SMB_TreeConnect\n");
+#endif
+
+ SMBlib_errno = SMBlibE_BadParam;
+ return(NULL);
+
+ }
+
+ /* The + 2 is because of the \0 and the marker ... */
+
+ param_len = strlen(path) + 2 + strlen(password) + 2 + strlen(device) + 2;
+
+ /* The -1 accounts for the one byte smb_buf we have because some systems */
+ /* don't like char msg_buf[] */
+
+ pkt_len = SMB_tcon_len + param_len;
+
+ pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
+
+ if (pkt == NULL) {
+
+ SMBlib_errno = SMBlibE_NoSpace;
+ return(NULL); /* Should handle the error */
+
+ }
+
+ /* Now allocate a tree for this to go into ... */
+
+ if (Tree_Handle == NULL) {
+
+ tree = (SMB_Tree_Handle)malloc(sizeof(struct SMB_Tree_Structure));
+
+ if (tree == NULL) {
+
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = SMBlibE_NoSpace;
+ return(NULL);
+
+ }
+ }
+ else {
+
+ tree = Tree_Handle;
+
+ }
+
+ tree -> next = tree -> prev = NULL;
+ tree -> con = Con_Handle;
+ strncpy(tree -> path, path, sizeof(tree -> path));
+ strncpy(tree -> device_type, device, sizeof(tree -> device_type));
+
+ /* Now plug in the values ... */
+
+ bzero(SMB_Hdr(pkt), SMB_tcon_len);
+ SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
+ *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtcon;
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
+ *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+ SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, param_len);
+
+ /* Now copy the param strings in with the right stuff */
+
+ p = (char *)(SMB_Hdr(pkt) + SMB_tcon_buf_offset);
+ *p = SMBasciiID;
+ strcpy(p + 1, path);
+ p = p + strlen(path) + 2;
+ *p = SMBasciiID;
+ strcpy(p + 1, password);
+ p = p + strlen(password) + 2;
+ *p = SMBasciiID;
+ strcpy(p + 1, device);
+
+ /* Now send the packet and sit back ... */
+
+ if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
+
+#ifdef DEBUG
+ fprintf(stderr, "Error sending TCon request\n");
+#endif
+
+ if (Tree_Handle == NULL)
+ free(tree);
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = -SMBlibE_SendFailed;
+ return(NULL);
+
+ }
+
+ /* Now get the response ... */
+
+ if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+ fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+ if (Tree_Handle == NULL)
+ free(tree);
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = -SMBlibE_RecvFailed;
+ return(NULL);
+
+ }
+
+ /* Check out the response type ... */
+
+ if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
+
+#ifdef DEBUG
+ fprintf(stderr, "SMB_TCon failed with errorclass = %i, Error Code = %i\n",
+ CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+ SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+ if (Tree_Handle == NULL)
+ free(tree);
+ SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = SMBlibE_Remote;
+ return(NULL);
+
+ }
+
+ tree -> tid = SVAL(SMB_Hdr(pkt), SMB_tconr_tid_offset);
+ tree -> mbs = SVAL(SMB_Hdr(pkt), SMB_tconr_mbs_offset);
+
+#ifdef DEBUG
+ fprintf(stderr, "TConn succeeded, with TID=%i, Max Xmit=%i\n",
+ tree -> tid, tree -> mbs);
+#endif
+
+ /* Now link the Tree to the Server Structure ... */
+
+ if (Con_Handle -> first_tree == NULL) {
+
+ Con_Handle -> first_tree == tree;
+ Con_Handle -> last_tree == tree;
+
+ }
+ else {
+
+ Con_Handle -> last_tree -> next = tree;
+ tree -> prev = Con_Handle -> last_tree;
+ Con_Handle -> last_tree = tree;
+
+ }
+
+ RFCNB_Free_Pkt(pkt);
+ return(tree);
+
+}
+
+int SMB_TreeDisconnect(SMB_Tree_Handle Tree_Handle, BOOL discard)
+
+{ struct RFCNB_Pkt *pkt;
+ int pkt_len;
+
+ pkt_len = SMB_tdis_len;
+
+ pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
+
+ if (pkt == NULL) {
+
+ SMBlib_errno = SMBlibE_NoSpace;
+ return(SMBlibE_BAD); /* Should handle the error */
+
+ }
+
+ /* Now plug in the values ... */
+
+ bzero(SMB_Hdr(pkt), SMB_tdis_len);
+ SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
+ *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtdis;
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle -> con -> pid);
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Tree_Handle -> con -> mid);
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Tree_Handle -> con -> uid);
+ *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+ SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle -> tid);
+ SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, 0);
+
+ /* Now send the packet and sit back ... */
+
+ if (RFCNB_Send(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0){
+
+#ifdef DEBUG
+ fprintf(stderr, "Error sending TDis request\n");
+#endif
+
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = -SMBlibE_SendFailed;
+ return(SMBlibE_BAD);
+
+ }
+
+ /* Now get the response ... */
+
+ if (RFCNB_Recv(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+ fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = -SMBlibE_RecvFailed;
+ return(SMBlibE_BAD);
+
+ }
+
+ /* Check out the response type ... */
+
+ if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
+
+#ifdef DEBUG
+ fprintf(stderr, "SMB_TDis failed with errorclass = %i, Error Code = %i\n",
+ CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+ SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+ SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+ RFCNB_Free_Pkt(pkt);
+ SMBlib_errno = SMBlibE_Remote;
+ return(SMBlibE_BAD);
+
+ }
+
+ Tree_Handle -> tid = 0xFFFF; /* Invalid TID */
+ Tree_Handle -> mbs = 0; /* Invalid */
+
+#ifdef DEBUG
+
+ fprintf(stderr, "Tree disconnect successful ...\n");
+
+#endif
+
+ /* What about the tree handle ? */
+
+ if (discard == TRUE) { /* Unlink it and free it ... */
+
+ if (Tree_Handle -> next == NULL)
+ Tree_Handle -> con -> first_tree = Tree_Handle -> prev;
+ else
+ Tree_Handle -> next -> prev = Tree_Handle -> prev;
+
+ if (Tree_Handle -> prev == NULL)
+ Tree_Handle -> con -> last_tree = Tree_Handle -> next;
+ else
+ Tree_Handle -> prev -> next = Tree_Handle -> next;
+
+ }
+
+ RFCNB_Free_Pkt(pkt);
+ return(0);
+
+}
+
+/* Pick up the last LMBlib error ... */
+
+int SMB_Get_Last_Error()
+
+{
+
+ return(SMBlib_errno);
+
+}
+
+/* Pick up the last error returned in an SMB packet */
+/* We will need macros to extract error class and error code */
+
+int SMB_Get_Last_SMB_Err()
+
+{
+
+ return(SMBlib_SMB_Error);
+
+}
+
+/* Pick up the error message associated with an error from SMBlib */
+
+/* Keep this table in sync with the message codes in smblib-common.h */
+
+static char *SMBlib_Error_Messages[] = {
+
+ "Request completed sucessfully.",
+ "Server returned a non-zero SMB Error Class and Code.",
+ "A lower layer protocol error occurred.",
+ "Function not yet implemented.",
+ "The protocol negotiated does not support the request.",
+ "No space available for operation.",
+ "One or more bad parameters passed.",
+ "None of the protocols we offered were accepted.",
+ "The attempt to send an SMB request failed. See protocol error info.",
+ "The attempt to get an SMB response failed. See protocol error info.",
+ "The logon request failed, but you were logged in as guest.",
+ "The attempt to call the remote server failed. See protocol error info.",
+ "The protocol dialect specified in a NegProt and accepted by the server is unknown.",
+ /* This next one simplifies error handling */
+ "No such error code.",
+ NULL};
+
+int SMB_Get_Error_Msg(int msg, char *msgbuf, int len)
+
+{
+
+ if (msg >= 0) {
+
+ strncpy(msgbuf,
+ SMBlib_Error_Messages[msg>SMBlibE_NoSuchMsg?SMBlibE_NoSuchMsg:msg],
+ len - 1);
+ msgbuf[len - 1] = 0; /* Make sure it is a string */
+ }
+ else { /* Add the lower layer message ... */
+
+ char prot_msg[1024];
+
+ msg = -msg; /* Make it positive */
+
+ strncpy(msgbuf,
+ SMBlib_Error_Messages[msg>SMBlibE_NoSuchMsg?SMBlibE_NoSuchMsg:msg],
+ len - 1);
+
+ msgbuf[len - 1] = 0; /* make sure it is a string */
+
+ if (strlen(msgbuf) < len) { /* If there is space, put rest in */
+
+ strncat(msgbuf, "\n\t", len - strlen(msgbuf));
+
+ RFCNB_Get_Error(prot_msg, sizeof(prot_msg) - 1);
+
+ strncat(msgbuf, prot_msg, len - strlen(msgbuf));
+
+ }
+ }
+
+}