diff options
Diffstat (limited to 'daemon/smblib')
-rw-r--r-- | daemon/smblib/exper.c | 748 | ||||
-rw-r--r-- | daemon/smblib/file.c | 1306 | ||||
-rw-r--r-- | daemon/smblib/find_password.c | 281 | ||||
-rw-r--r-- | daemon/smblib/smb-errors.c | 220 | ||||
-rw-r--r-- | daemon/smblib/smbencrypt.c | 202 | ||||
-rw-r--r-- | daemon/smblib/smblib-api.c | 379 | ||||
-rw-r--r-- | daemon/smblib/smblib-common.h | 184 | ||||
-rw-r--r-- | daemon/smblib/smblib-priv.h | 624 | ||||
-rw-r--r-- | daemon/smblib/smblib-util.c | 783 | ||||
-rw-r--r-- | daemon/smblib/smblib.c | 549 | ||||
-rw-r--r-- | daemon/smblib/smblib.h | 95 | ||||
-rw-r--r-- | daemon/smblib/std-defines.h | 45 |
12 files changed, 5416 insertions, 0 deletions
diff --git a/daemon/smblib/exper.c b/daemon/smblib/exper.c new file mode 100644 index 0000000..13f9ba6 --- /dev/null +++ b/daemon/smblib/exper.c @@ -0,0 +1,748 @@ +/* UNIX SMBlib NetBIOS implementation + + Version 1.0 + SMBlib Routines. Experimental Section ... + + 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" + +#include <signal.h> + + +/* Logon and tree connect to the server. If a tree handle was given to us, */ +/* we use it and return it, otherwise we create one ... */ + +SMB_Tree_Handle SMB_Logon_And_TCon(SMB_Handle_Type Con_Handle, + SMB_Tree_Handle Tree_Handle, + char *UserName, + char *PassWord, + char *service, + char *service_type) + +{ struct RFCNB_Pkt *pkt; + int param_len, i, pkt_len, andx_len, andx_param_len; + char *p, *AndXCom; + SMB_Tree_Handle tree; + + /* Lets create a tree if we need one ... */ + + if (Tree_Handle == NULL) { + + tree = (SMB_Tree_Handle)malloc(sizeof(struct SMB_Tree_Structure)); + + if (tree == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return(tree); + + } + else { /* Initialize the tree */ + + tree -> con = Con_Handle; + tree -> prev = tree -> next = NULL; + + } + } + else + tree = Tree_Handle; + + /* First we need a packet etc ... but we need to know what protocol has */ + /* been negotiated to figure out if we can do it and what SMB format to */ + /* use ... */ + + /* Since we are going to do a LogonAndX with a TCon as the second command*/ + /* We need the packet size correct. So TCon starts at wct field */ + + if (Con_Handle -> protocol < SMB_P_LanMan1) { + + SMBlib_errno = SMBlibE_ProtLow; + if (Tree_Handle == NULL) + free(tree); + return(NULL); + + } + + /* Now build the correct structure */ + + andx_len = SMB_tconx_len - SMB_hdr_wct_offset; + + /* We send a null password as we sent one in the setup and X */ + + andx_param_len = strlen(service) + 1 + strlen(service_type) + 1; + + if (Con_Handle -> protocol < SMB_P_NT1) { + +#ifdef SMBLIB_DEBUG + fprintf(stderr, "Doing an LM session setup etc ...\n"); +#endif + + /* We don't do encrypted passwords ... */ + + param_len = strlen(UserName) + 1 + strlen(PassWord) + 1 + + strlen(Con_Handle -> PDomain) + 1 + + strlen(Con_Handle -> OSName) + 1; + + pkt_len = SMB_ssetpLM_len + param_len + andx_len + andx_param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + if (Tree_Handle == NULL) + free(tree); + return(NULL); /* Should handle the error */ + + } + + bzero(SMB_Hdr(pkt), SMB_ssetpLM_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX; + 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, 0); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10; + *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = SMBtconX; + SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, SMB_ssetpLM_len + param_len); + + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle -> pid); + SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, strlen(PassWord) + 1); + SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len); + + /* Now copy the param strings in with the right stuff */ + + p = (char *)(SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset); + + /* Copy in password, then the rest. Password has no null at end */ + + strcpy(p, PassWord); + + p = p + strlen(PassWord) + 1; + + strcpy(p, UserName); + p = p + strlen(UserName); + *p = 0; + + p = p + 1; + + strcpy(p, Con_Handle -> PDomain); + p = p + strlen(Con_Handle -> PDomain); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle -> OSName); + p = p + strlen(Con_Handle -> OSName); + *p = 0; + + AndXCom = SMB_Hdr(pkt) + SMB_ssetpLM_len + param_len - SMB_hdr_wct_offset; + + } + else { + + /* We don't admit to UNICODE support ... */ + +#ifdef SMBLIB_DEBUG + fprintf(stderr, "Doing NT LM Sess Setup etc ... \n"); +#endif + + param_len = strlen(UserName) + 1 + strlen(PassWord) + + strlen(Con_Handle -> PDomain) + 1 + + strlen(Con_Handle -> OSName) + 1 + + strlen(Con_Handle -> LMType) + 1; + + pkt_len = SMB_ssetpNTLM_len + param_len + andx_len + andx_param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + if (Tree_Handle == NULL) + free(tree); + return(NULL); /* Should handle the error */ + + } + + bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX; + 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, 0); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13; + *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = SMBtconX; + SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, SMB_ssetpNTLM_len + param_len); + + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 2); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, strlen(PassWord)); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len); + + /* Now copy the param strings in with the right stuff */ + + p = (char *)(SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset); + + /* Copy in password, then the rest. Password has no null at end */ + + strcpy(p, PassWord); + + p = p + strlen(PassWord); + + strcpy(p, UserName); + p = p + strlen(UserName); + *p = 0; + + p = p + 1; + + strcpy(p, Con_Handle -> PDomain); + p = p + strlen(Con_Handle -> PDomain); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle -> OSName); + p = p + strlen(Con_Handle -> OSName); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle -> LMType); + p = p + strlen(Con_Handle -> LMType); + *p = 0; + + /* Now set up the TCON Part ... from WCT, make up a pointer that will + help us ... */ + + AndXCom = SMB_Hdr(pkt) + SMB_ssetpNTLM_len + param_len - SMB_hdr_wct_offset; + + } + *(AndXCom + SMB_hdr_wct_offset) = 4; + *(AndXCom + SMB_tconx_axc_offset) = 0xFF; /* No command */ + SSVAL(AndXCom, SMB_tconx_axo_offset, 0); + SSVAL(AndXCom, SMB_tconx_flg_offset, 0); /* Don't disconnect TID */ + SSVAL(AndXCom, SMB_tconx_pwl_offset, 0); /* No password, */ + SSVAL(AndXCom, SMB_tconx_bcc_offset, andx_param_len); + + p = (char *)(AndXCom + SMB_tconx_buf_offset); + + /**p = 0; + p = p + 1; */ + strcpy(p, service); + p = p + strlen(service) + 1; + strcpy(p, service_type); + + /* Now send it and get a response */ + + if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending SessSetupAndTCon request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + free(tree); + 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 SessSetupAndTCon\n"); +#endif + + RFCNB_Free_Pkt(pkt); + free(tree); + 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_SessSetupAndTCon 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 + + /* Note, here, that we have not properly handled the error processing */ + /* and so we cannot tell how much of our request crapped out */ + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + free(tree); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(NULL); + + } + +#ifdef DEBUG + fprintf(stderr, "SessSetupAndX response. Action = %i\n", + SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset)); +#endif + + /* Now pick up the UID for future reference ... */ + + Con_Handle -> uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset); + + /* And pick up the TID as well */ + + tree -> tid = SVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset); + + tree -> mbs = Con_Handle -> max_xmit; + + /* Link the tree into the list in con */ + + 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); + +} + +/* Logon and TCon and Open to a file on the server, but we need to pass */ +/* back a file pointer, so we better have one in the parameter list */ + +int SMB_Logon_TCon_Open(SMB_Handle_Type Con_Handle, char *UserName, + char *PassWord, + char *service, + char *service_type, + SMB_Tree_Handle *Tree_Handle, + char *filename, + WORD mode, + WORD search, + SMB_File **File_Handle) + +{ struct RFCNB_Pkt *pkt; + int param_len, i, pkt_len, tcon_len, tcon_param_len, open_len, + open_param_len, header_len; + struct SMB_File_Def *file_tmp; + SMB_Tree_Handle tree; + char *p, *AndXCom; + + /* First, we need a tree STRUCTURE as we are going to tree connect */ + + tree = (SMB_Tree_Handle)malloc(sizeof(struct SMB_Tree_Structure)); + + if (tree == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + else { + + tree -> con = Con_Handle; + tree -> next = tree -> prev = NULL; + + } + + /* Next, we need a file handle as we are going to pass one back ... */ + /* Hmm, there is a bug here ... We should check on File_Handle ... */ + + if ((file_tmp = (SMB_File *)malloc(sizeof(SMB_File))) == NULL){ + +#ifdef DEBUG + fprintf(stderr, "Could not allocate file handle space ..."); +#endif + + SMBlib_errno = SMBlibE_NoSpace; + free(tree); + return(SMBlibE_BAD); + + } + + /* Next we need a packet etc ... but we need to know what protocol has */ + /* been negotiated to figure out if we can do it and what SMB format to */ + /* use ... */ + + /* Since we are going to do a LogonAndX with a TCon as the second command*/ + /* We need the packet size correct. So TCon starts at wct field */ + + if (Con_Handle -> protocol < SMB_P_LanMan1) { + + free(tree); + free(file_tmp); + SMBlib_errno = SMBlibE_ProtLow; + return(SMBlibE_BAD); + + } + + /* Now build the correct structure */ + + /* We send a null password in the TconAndX ... */ + + tcon_len = SMB_tconx_len - SMB_hdr_wct_offset; + tcon_param_len = strlen(service) + 1 + strlen(service_type) + 1; + + open_len = SMB_openx_len - SMB_hdr_wct_offset; + open_param_len = 1 + strlen(filename) + 1; /* AsciiID + null */ + + if (Con_Handle -> protocol < SMB_P_NT1) { + + /* We don't do encrypted passwords yet */ + + param_len = strlen(UserName) + 1 + strlen(PassWord) + 1 + + strlen(Con_Handle -> PDomain) + 1 + + strlen(Con_Handle -> OSName) + 1; + + header_len = SMB_ssetpLM_len + param_len; + + pkt_len = header_len + tcon_len + tcon_param_len + + open_len + open_param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + free(tree); + free(file_tmp); + return(SMBlibE_BAD); /* Should handle the error */ + + } + + bzero(SMB_Hdr(pkt), SMB_ssetpLM_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX; + 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, 0); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10; + *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = SMBtconX; + SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, SMB_ssetpLM_len + param_len); + + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle -> pid); + SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, strlen(PassWord) + 1); + SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len); + + /* Now copy the param strings in with the right stuff */ + + p = (char *)(SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset); + + /* Copy in password, then the rest. Password has no null at end */ + + strcpy(p, PassWord); + + p = p + strlen(PassWord) + 1; + + strcpy(p, UserName); + p = p + strlen(UserName); + *p = 0; + + p = p + 1; + + strcpy(p, Con_Handle -> PDomain); + p = p + strlen(Con_Handle -> PDomain); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle -> OSName); + p = p + strlen(Con_Handle -> OSName); + *p = 0; + + AndXCom = SMB_Hdr(pkt) + SMB_ssetpLM_len + param_len - SMB_hdr_wct_offset; + + } + else { + + /* We don't admit to UNICODE support ... */ + + param_len = strlen(UserName) + 1 + strlen(PassWord) + + strlen(Con_Handle -> PDomain) + 1 + + strlen(Con_Handle -> OSName) + 1 + + strlen(Con_Handle -> LMType) + 1; + + header_len = SMB_ssetpNTLM_len + param_len; + + pkt_len = header_len + tcon_len + tcon_param_len + + open_len + open_param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + free(tree); + free(file_tmp); /* Should only do if we created one ... */ + return(-1); /* Should handle the error */ + + } + + bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX; + 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, 0); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13; + *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = SMBtconX; + SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, SMB_ssetpNTLM_len + param_len); + + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 2); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, strlen(PassWord)); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len); + + /* Now copy the param strings in with the right stuff */ + + p = (char *)(SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset); + + /* Copy in password, then the rest. Password has no null at end */ + + strcpy(p, PassWord); + + p = p + strlen(PassWord); + + strcpy(p, UserName); + p = p + strlen(UserName); + *p = 0; + + p = p + 1; + + strcpy(p, Con_Handle -> PDomain); + p = p + strlen(Con_Handle -> PDomain); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle -> OSName); + p = p + strlen(Con_Handle -> OSName); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle -> LMType); + p = p + strlen(Con_Handle -> LMType); + *p = 0; + + /* Now set up the TCON Part ... from WCT, make up a pointer that will + help us ... */ + + AndXCom = SMB_Hdr(pkt) + SMB_ssetpNTLM_len + param_len - SMB_hdr_wct_offset; + + } + + *(AndXCom + SMB_hdr_wct_offset) = 4; + *(AndXCom + SMB_tconx_axc_offset) = SMBopenX; + SSVAL(AndXCom, SMB_tconx_axo_offset, (header_len + + tcon_len + tcon_param_len)); + SSVAL(AndXCom, SMB_tconx_flg_offset, 0); /* Don't disconnect TID */ + SSVAL(AndXCom, SMB_tconx_pwl_offset, 0); /* No password */ + SSVAL(AndXCom, SMB_tconx_bcc_offset, tcon_param_len); + + p = (char *)(AndXCom + SMB_tconx_buf_offset); + +/* *p = 0; + p = p + 1; */ + strcpy(p, service); + p = p + strlen(service) + 1; + strcpy(p, service_type); + + /* Now the open bit ... */ + + AndXCom = AndXCom + tcon_len + tcon_param_len; /* Should get us there */ + + *(AndXCom + SMB_hdr_wct_offset) = 15; + *(AndXCom + SMB_openx_axc_offset) = 0xFF; + *(AndXCom + SMB_openx_axr_offset) = 0; + SSVAL(AndXCom, SMB_openx_axo_offset, 0); + SSVAL(AndXCom, SMB_openx_flg_offset, 0); + SSVAL(AndXCom, SMB_openx_mod_offset, mode); + SSVAL(AndXCom, SMB_openx_atr_offset, search); + SSVAL(AndXCom, SMB_openx_fat_offset, 0); + SIVAL(AndXCom, SMB_openx_tim_offset, 0); + SSVAL(AndXCom, SMB_openx_ofn_offset, 0x0011); /* Create or open */ + SIVAL(AndXCom, SMB_openx_als_offset, 0); + SSVAL(AndXCom, SMB_openx_bcc_offset, open_param_len); + + p = (char *)(AndXCom + SMB_openx_buf_offset); + + /* *p = SMBasciiID; */ + strcpy(p, filename); + + /* Now send it and get a response */ + + if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending SessSetupAndTCon request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + free(tree); + free(file_tmp); + SMBlib_errno = SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to SessSetupAndTCon\n"); +#endif + + RFCNB_Free_Pkt(pkt); + free(tree); + free(file_tmp); + 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_SessSetupAndTCon 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 + + /* Note, here, that we have not properly handled the error processing */ + /* and so we cannot tell how much of our request crapped out */ + + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + free(tree); + free(file_tmp); + SMBlib_errno = SMBlibE_Remote; + return(SMBlibE_BAD); + + } + +#ifdef DEBUG + fprintf(stderr, "SessSetupAndX response. Action = %i\n", + SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset)); +#endif + + /* Now pick up the UID for future reference ... */ + + Con_Handle -> uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset); + + /* And pick up the TID as well */ + + tree -> tid = SVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset); + tree -> mbs = Con_Handle -> max_xmit; /* We need this */ + +#ifdef DEBUG + fprintf(stderr, "mbs=%i\n", tree -> mbs); +#endif + + /* Now we populate the file hanble and pass it back ... */ + + strncpy(file_tmp -> filename, filename, sizeof(file_tmp -> filename) - 1); + file_tmp -> tree = tree; + + /* Pick up a pointer to the right part ... */ + + AndXCom = SMB_Hdr(pkt) + SVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset) - + SMB_hdr_wct_offset; + + /* Now skip the response to the TConX */ + + AndXCom = SMB_Hdr(pkt) + SVAL(AndXCom, SMB_tconxr_axo_offset) - + SMB_hdr_wct_offset; + +#ifdef DEBUG + fprintf(stderr, "Word Params = %x, AXO = %x\n", + CVAL(AndXCom, SMB_hdr_wct_offset), + SVAL(AndXCom, SMB_openxr_axo_offset)); +#endif + + /* Now pick up the things from the openX response that we need */ + + file_tmp -> fid = SVAL(AndXCom, SMB_openxr_fid_offset); + file_tmp -> lastmod = IVAL(AndXCom, SMB_openxr_tim_offset); + file_tmp -> size = IVAL(AndXCom, SMB_openxr_fsz_offset); + file_tmp -> access = SVAL(AndXCom, SMB_openxr_acc_offset); + file_tmp -> fileloc = 0; + + *File_Handle = file_tmp; + + /* Now link the tree into the right place ... */ + + 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); + + *Tree_Handle = tree; + + return(0); + +} + diff --git a/daemon/smblib/file.c b/daemon/smblib/file.c new file mode 100644 index 0000000..6a62da5 --- /dev/null +++ b/daemon/smblib/file.c @@ -0,0 +1,1306 @@ +/* UNIX SMBlib NetBIOS implementation + + Version 1.0 + SMBlib File Access 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" + +/* Open a file with file_name using desired mode and search attr */ +/* If File_Handle is null, then create and populate a file handle */ + +SMB_File *SMB_Open(SMB_Tree_Handle Tree_Handle, + SMB_File *File_Handle, + char *file_name, + WORD mode, + WORD search) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; char *p; + struct SMB_File_Def *file_tmp; + + /* We allocate a file object and copy some things ... */ + + file_tmp = File_Handle; + + if (File_Handle == NULL) { + + if ((file_tmp = (SMB_File *)malloc(sizeof(SMB_File))) == NULL){ + +#ifdef DEBUG + fprintf(stderr, "Could not allocate file handle space ..."); +#endif + + SMBlib_errno = SMBlibE_NoSpace; + return(NULL); + + } + + } + + strncpy(file_tmp -> filename, file_name, sizeof(file_tmp -> filename) - 1); + file_tmp -> tree = Tree_Handle; + file_tmp -> fid = 0xFFFF; /* Is this an invalid FID? */ + + param_len = strlen(file_name) + 2; /* 1 for null, 1 for ASCII marker */ + + pkt_len = SMB_open_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(max(pkt_len, SMB_openr_len)); + + if (pkt == NULL) { /* Really should do some error handling */ + + if (File_Handle == NULL) + free(file_tmp); + SMBlib_errno = SMBlibE_NoSpace; + return(NULL); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_open_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBopen; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle -> tid); + 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) = 2; + + SSVAL(SMB_Hdr(pkt), SMB_open_mod_offset, mode); + SSVAL(SMB_Hdr(pkt), SMB_open_atr_offset, search); + SSVAL(SMB_Hdr(pkt), SMB_open_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_open_buf_offset); + *p = SMBasciiID; + strcpy(p+1, file_name); + p = p + strlen(file_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Open request\n"); +#endif + + if (File_Handle == NULL) + free(file_tmp); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(NULL); + + } + + /* Now get the response ... */ + +#ifdef DEBUG + fprintf(stderr, "Pkt_Len for Open resp = %i\n", pkt_len); +#endif + + if (RFCNB_Recv(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to open request\n"); +#endif + + if (File_Handle = NULL) + free(file_tmp); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(NULL); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Open 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 (File_Handle = NULL) + free(file_tmp); + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(NULL); /* Should clean up ... */ + + } + + file_tmp -> fid = SVAL(SMB_Hdr(pkt), SMB_openr_fid_offset); + file_tmp -> lastmod = IVAL(SMB_Hdr(pkt), SMB_openr_tim_offset); + file_tmp -> size = IVAL(SMB_Hdr(pkt), SMB_openr_fsz_offset); + file_tmp -> access = SVAL(SMB_Hdr(pkt), SMB_openr_acc_offset); + file_tmp -> fileloc = 0; + + RFCNB_Free_Pkt(pkt); /* Free up this space */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Open succeeded, FID = %i\n", file_tmp -> fid); +#endif + + RFCNB_Free_Pkt(pkt); + + return(file_tmp); + +} + +/* Close the file referred to in File_Handle */ + +int SMB_Close(SMB_File *File_Handle) + +{ struct SMB_Close_Prot_Def *prot_pkt; + struct SMB_Hdr_Def_LM12 *resp_pkt; + struct RFCNB_Pkt *pkt; + int pkt_len; + + if (File_Handle == NULL) { /* Error */ + + /*SMBLIB_errno = SMBLIBE_BadHandle; */ + return(-1); + + } + + pkt_len = SMB_clos_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_clos_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBclose; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, File_Handle -> tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, File_Handle -> tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, File_Handle -> tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, File_Handle -> tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 3; + + SSVAL(SMB_Hdr(pkt), SMB_clos_fid_offset, File_Handle -> fid); + SIVAL(SMB_Hdr(pkt), SMB_clos_tim_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_clos_bcc_offset, 0); + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(File_Handle -> tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Open request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(File_Handle -> tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to open request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Close 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); /* Should clean up ... */ + + } + +#ifdef DEBUG + fprintf(stderr, "File %s closed successfully.\n", File_Handle -> filename); +#endif /* DEBUG */ + + /* We should deallocate the File_Handle now ... */ + + File_Handle -> tree = NULL; + File_Handle -> filename[0] = 0; + File_Handle -> fid = 0xFFFF; + + RFCNB_Free_Pkt(pkt); + free(File_Handle); + + return(0); +} + +/* Read numbytes into data from the file pointed to by File_Handle from */ +/* the offset in the File_Handle. */ + +int SMB_Read(SMB_File *File_Handle, char *data, int numbytes) + +{ int tot_read; + struct RFCNB_Pkt *snd_pkt, *recv_pkt, *data_ptr; + int snd_pkt_len, recv_pkt_len, this_read, bytes_left = numbytes; + int max_read_data, bytes_read = 0; + + /* We loop around, reading the data, accumulating it into the buffer */ + /* We build an SMB packet, where the data is pointed to by a fragment*/ + /* tagged onto the end */ + + data_ptr = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(0); + if (data_ptr == NULL) { + + /* We should handle the error here */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + snd_pkt_len = SMB_read_len; /* size for the read SMB */ + recv_pkt_len = SMB_readr_len + 3; /* + 3 for the datablockID and blklen */ + + snd_pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(snd_pkt_len); + + if (snd_pkt == NULL) { + + RFCNB_Free_Pkt(data_ptr); + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + recv_pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(recv_pkt_len); + + if (recv_pkt == NULL) { + + RFCNB_Free_Pkt(snd_pkt); + RFCNB_Free_Pkt(data_ptr); + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Put the recv pkt together */ + + recv_pkt -> next = data_ptr; + + /* Now build the read request and the receive packet etc ... */ + + bzero(SMB_Hdr(snd_pkt), SMB_read_len); + SIVAL(SMB_Hdr(snd_pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(snd_pkt) + SMB_hdr_com_offset) = SMBread; + SSVAL(SMB_Hdr(snd_pkt), SMB_hdr_pid_offset, File_Handle -> tree -> con -> pid); + SSVAL(SMB_Hdr(snd_pkt), SMB_hdr_tid_offset, File_Handle -> tree -> tid); + SSVAL(SMB_Hdr(snd_pkt), SMB_hdr_mid_offset, File_Handle -> tree -> con -> mid); + SSVAL(SMB_Hdr(snd_pkt), SMB_hdr_uid_offset, File_Handle -> tree -> con -> uid); + *(SMB_Hdr(snd_pkt) + SMB_hdr_wct_offset) = 5; + SSVAL(SMB_Hdr(snd_pkt), SMB_read_fid_offset, File_Handle -> fid); + + max_read_data = (File_Handle -> tree -> mbs) - recv_pkt_len; + + while (bytes_left > 0) { + + this_read = (bytes_left > max_read_data?max_read_data: bytes_left); + + SSVAL(SMB_Hdr(snd_pkt), SMB_read_cnt_offset, this_read); + SIVAL(SMB_Hdr(snd_pkt), SMB_read_ofs_offset, File_Handle -> fileloc); + SSVAL(SMB_Hdr(snd_pkt), SMB_read_clf_offset, 0x0); + SSVAL(SMB_Hdr(snd_pkt), SMB_read_bcc_offset, 0x0); + + /* Now send the packet and wait for a response */ + + if (RFCNB_Send(File_Handle -> tree -> con -> Trans_Connect, snd_pkt, snd_pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending read request\n"); +#endif + + data_ptr -> data = NULL; + data_ptr -> len = 0; + RFCNB_Free_Pkt(recv_pkt); + RFCNB_Free_Pkt(snd_pkt); + SMBlib_errno = SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... first point the data portion to the right */ + /* place in the read buffer ... what we are doing is ugly */ + + data_ptr -> data = (data + bytes_read); + data_ptr -> len = this_read; + + if (RFCNB_Recv(File_Handle -> tree -> con -> Trans_Connect, recv_pkt, recv_pkt_len + this_read) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to write\n"); +#endif + + data_ptr -> len = 0; + data_ptr -> data = NULL; + RFCNB_Free_Pkt(recv_pkt); + RFCNB_Free_Pkt(snd_pkt); + SMBlib_errno = SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + if (CVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Read failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(recv_pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset); + data_ptr -> data = NULL; + data_ptr -> len = 0; + RFCNB_Free_Pkt(recv_pkt); + RFCNB_Free_Pkt(snd_pkt); + SMBlib_errno = SMBlibE_Remote; + return(-1); + + } + + /* Ok, that worked, so update some things here ... */ + + bytes_read = bytes_read + SVAL(SMB_Hdr(recv_pkt), SMB_readr_cnt_offset); + bytes_left = bytes_left - SVAL(SMB_Hdr(recv_pkt), SMB_readr_cnt_offset); + + } + + /* Now free those packet headers that we allocated ... */ + + data_ptr -> data = NULL; /* Since recv_pkt points to data_ptr */ + data_ptr -> len = 0; /* it is freed too */ + RFCNB_Free_Pkt(recv_pkt); + RFCNB_Free_Pkt(snd_pkt); + + return(bytes_read); + +} + +/* Lseek seeks just like the UNIX version does ... */ + +off_t SMB_Lseek(SMB_File *File_Handle, off_t offset, int whence) + +{ + + /* We should check that the file handle is kosher ... We may also blow up + if we get a 64 bit offset ... should avoid wrap-around ... */ + + switch (whence) { + case SEEK_SET: + + File_Handle -> fileloc = offset; + break; + + case SEEK_CUR: + + File_Handle -> fileloc = File_Handle -> fileloc + offset; + break; + + case SEEK_END: + + File_Handle -> fileloc = File_Handle -> size + offset; + break; + + default: + return(-1); + + } + + return(File_Handle -> fileloc); + +} + + +/* Write numbytes from data to the file pointed to by the File_Handle at */ +/* the offset in the File_Handle. */ + +int SMB_Write(SMB_File *File_Handle, char *data, int numbytes) + +{ int tot_written = 0; + struct RFCNB_Pkt *pkt, *data_ptr; + int pkt_len, i, this_write, max_write_data, bytes_left = numbytes; + + /* We loop around, writing the data, accumulating what was written */ + /* We build an SMB packet, where the data is pointed to by a fragment */ + /* tagged onto the end ... */ + + data_ptr = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(0); + if (data_ptr == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + pkt_len = SMB_write_len + 3; /* + 3 for the datablockID and blklen */ + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + RFCNB_Free_Pkt(data_ptr); + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now init the things that will be the same across the possibly multiple + packets to write this data. */ + + bzero(SMB_Hdr(pkt), SMB_write_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBwrite; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, File_Handle -> tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, File_Handle -> tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, File_Handle -> tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, File_Handle -> tree -> con -> uid); + SSVAL(SMB_Hdr(pkt), SMB_write_fid_offset, File_Handle -> fid); + + /* We will program this as send/response for the moment, but if we could + only send the second block before getting the first, we could speed + things up a bit ... */ + + max_write_data = (File_Handle -> tree -> mbs) - pkt_len; + + /* the 3 is for the data block id and length that preceeds the data */ + + while (bytes_left > 0) { + + /* bytes to write? */ + + this_write = (bytes_left > max_write_data?max_write_data:bytes_left); + + data_ptr -> next = NULL; + data_ptr -> len = this_write; + data_ptr -> data = data + tot_written; + + pkt -> next = data_ptr; /* link the data on the end */ + + SSVAL(SMB_Hdr(pkt), SMB_hdr_flg_offset, 0); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 5; + SSVAL(SMB_Hdr(pkt), SMB_write_fid_offset, File_Handle -> fid); + SSVAL(SMB_Hdr(pkt), SMB_write_cnt_offset, this_write); + SIVAL(SMB_Hdr(pkt), SMB_write_ofs_offset, File_Handle -> fileloc); + SSVAL(SMB_Hdr(pkt), SMB_write_clf_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_write_bcc_offset, (this_write + 3)); + + *(SMB_Hdr(pkt) + SMB_write_buf_offset) = SMBdatablockID; + SSVAL(SMB_Hdr(pkt), SMB_write_buf_offset + 1, this_write); + + /* Now send the packet and wait for a response */ + + if (RFCNB_Send(File_Handle -> tree -> con -> Trans_Connect, pkt, pkt_len + this_write) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending write request\n"); +#endif + + data_ptr -> next = NULL; + data_ptr -> len = 0; + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(-1); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(File_Handle -> tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to write\n"); +#endif + + data_ptr -> next = NULL; + data_ptr -> len = 0; + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(-1); + + } + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Write 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); + data_ptr -> data = NULL; + data_ptr -> len = 0; + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(SMBlibE_BAD); + + } + + /* Ok, that worked, so update some things here ... */ + + tot_written = tot_written + this_write; + bytes_left = bytes_left - this_write; + + /* Assume that it is ok to update this now, but what about only part */ + /* of the write succeeding? */ + + File_Handle -> fileloc = File_Handle -> fileloc + this_write; + +#ifdef DEBUG + fprintf(stderr, "--This_write = %i, bytes_left = %i\n", + this_write, bytes_left); +#endif + + } + + /* Let's get rid of those packet headers we are using ... */ + + data_ptr -> data = NULL; + pkt -> next = NULL; + + RFCNB_Free_Pkt(pkt); + + return(tot_written); + +} + +/* Create file on the server with name file_name and attributes search */ + +SMB_File *SMB_Create(SMB_Tree_Handle Tree_Handle, + SMB_File *File_Handle, + char *file_name, + WORD search) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; char *p; + struct SMB_File_Def *file_tmp; + + /* We allocate a file object and copy some things ... */ + + file_tmp = File_Handle; + + if (File_Handle == NULL) { + + if ((file_tmp = (SMB_File *)malloc(sizeof(SMB_File))) == NULL){ + +#ifdef DEBUG + fprintf(stderr, "Could not allocate file handle space ..."); +#endif + + SMBlib_errno = SMBlibE_NoSpace; + return(NULL); + + } + + } + + strncpy(file_tmp -> filename, file_name, sizeof(file_tmp -> filename)); + file_tmp -> tree = Tree_Handle; + file_tmp -> fid = 0xFFFF; /* Is this an invalid FID? */ + + param_len = strlen(file_name) + 2; /* 1 for null, 1 for ASCII marker */ + + pkt_len = SMB_creat_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + if (File_Handle == NULL) + free(file_tmp); + SMBlib_errno = SMBlibE_NoSpace; + return(NULL); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_creat_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBcreate; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle -> tid); + 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) = 3; + + SSVAL(SMB_Hdr(pkt), SMB_creat_atr_offset, search); + SSVAL(SMB_Hdr(pkt), SMB_creat_tim_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_creat_dat_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_creat_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_creat_buf_offset); + *p = SMBasciiID; + strcpy(p+1, file_name); + p = p + strlen(file_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Open request\n"); +#endif + + if (File_Handle == NULL) + free(file_tmp); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(NULL); + + } + + /* Now get the response ... */ + +#ifdef DEBUG + fprintf(stderr, "Pkt_Len for Create resp = %i\n", pkt_len); +#endif + + if (RFCNB_Recv(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to create request\n"); +#endif + + if (File_Handle == NULL) + free(file_tmp); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(NULL); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Create 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 (File_Handle == NULL) + free(file_tmp); + SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_Remote; + return(NULL); /* Should clean up ... */ + + } + + file_tmp -> fid = SVAL(SMB_Hdr(pkt), SMB_creatr_fid_offset); + file_tmp -> lastmod = 0; + file_tmp -> size = 0; + file_tmp -> access = SMB_AMODE_OPENRW; + file_tmp -> fileloc = 0; + + RFCNB_Free_Pkt(pkt); /* Free up this space */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Create succeeded, FID = %i\n", file_tmp -> fid); +#endif + + return(file_tmp); + +} + +/* Delete the file passed in as file_name. */ + +int SMB_Delete(SMB_Tree_Handle tree, char *file_name, WORD search) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; + char *p; + + param_len = strlen(file_name) + 2; + pkt_len = SMB_delet_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_delet_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBunlink; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 1; + + SIVAL(SMB_Hdr(pkt), SMB_delet_sat_offset, search); + SSVAL(SMB_Hdr(pkt), SMB_delet_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_delet_buf_offset); + *p = SMBasciiID; + strcpy(p+1, file_name); + p = p + strlen(file_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Delete request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to delete request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Delete 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); /* Should clean up ... */ + + } + +#ifdef DEBUG + fprintf(stderr, "File %s deleted successfully.\n", file_name); +#endif /* DEBUG */ + + RFCNB_Free_Pkt(pkt); + + return(0); +} + +/* Create the directory passed in as dir_name */ + +int SMB_Create_Dir(SMB_Tree_Handle tree, char *dir_name) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; + char *p; + + param_len = strlen(dir_name) + 2; /* + null and + asciiID */ + pkt_len = SMB_creatdir_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_creatdir_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBmkdir; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; + + SSVAL(SMB_Hdr(pkt), SMB_creatdir_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_creatdir_buf_offset); + *p = SMBasciiID; + strcpy(p+1, dir_name); + p = p + strlen(dir_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Create Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to Create Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Create_Dir 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); /* Should clean up ... */ + + } + +#ifdef DEBUG + fprintf(stderr, "Directory %s created successfully.\n", dir_name); +#endif + + RFCNB_Free_Pkt(pkt); + + return(0); +} + +/* Delete the directory passed as dir_name, as long as it is empty ... */ + +int SMB_Delete_Dir(SMB_Tree_Handle tree, char *dir_name) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; + char *p; + + param_len = strlen(dir_name) + 2; /* + null and + asciiID */ + pkt_len = SMB_deletdir_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_deletdir_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBrmdir; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; + + SSVAL(SMB_Hdr(pkt), SMB_deletdir_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_deletdir_buf_offset); + *p = SMBasciiID; + strcpy(p+1, dir_name); + p = p + strlen(dir_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Delete Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to Delete Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Delete_Dir 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); /* Should clean up ... */ + + } + +#ifdef DEBUG + fprintf(stderr, "Directory %s deleted successfully.\n", dir_name); +#endif + + RFCNB_Free_Pkt(pkt); + + return(0); +} + +/* Check for the existence of the directory in dir_name */ + +int SMB_Check_Dir(SMB_Tree_Handle tree, char *dir_name) + +{ struct RFCNB_Pkt *pkt; + int pkt_len, param_len; + char *p; + + param_len = strlen(dir_name) + 2; /* + null and + asciiID */ + pkt_len = SMB_checkdir_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_checkdir_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBchkpth; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0; + + SSVAL(SMB_Hdr(pkt), SMB_checkdir_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_checkdir_buf_offset); + *p = SMBasciiID; + strcpy(p+1, dir_name); + p = p + strlen(dir_name); + *(p+1) = 0; /* plug in a null ... */ + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Check Dir Path request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to Check Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Check_Dir 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); /* Should clean up ... */ + + } + +#ifdef DEBUG + fprintf(stderr, "Directory %s checked successfully.\n", dir_name); +#endif + + RFCNB_Free_Pkt(pkt); + + return(0); +} + +/* Search directory for the files listed ... Relative to the TID in the */ +/* Con Handle. Return number of Dir Ents returned as the result. */ + +int SMB_Search(SMB_Tree_Handle tree, + char *dir_name, + WORD search, + SMB_CP_dirent *dirents, + int direntc, + char *resumekey, + int resumekey_len) + +{ struct RFCNB_Pkt *pkt, *recv_pkt; + int pkt_len, param_len, recv_param_len, recv_pkt_len, ret_count, i; + char *p; + + param_len = strlen(dir_name) + 2 + resumekey_len + 3; /* You have to know */ + pkt_len = SMB_search_len + param_len; + + recv_param_len = direntc * SMB_searchr_dirent_len + 3; + recv_pkt_len = SMB_searchr_len + recv_param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { /* Really should do some error handling */ + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + recv_pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(recv_pkt_len); + + if (recv_pkt == NULL) { /* Really should do some error handling */ + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); + + } + + + /* Now plug in the bits we need */ + + bzero(SMB_Hdr(pkt), SMB_search_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsearch; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + + /* Tell server we known about non-dos names and extended attibutes */ + + SSVAL(SMB_Hdr(pkt), SMB_hdr_flg2_offset, + (SMB_FLG2_NON_DOS | SMB_FLG2_EXT_ATR)); + + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 2; + + SSVAL(SMB_Hdr(pkt), SMB_search_mdc_offset, direntc); /* How many we want */ + SSVAL(SMB_Hdr(pkt), SMB_search_atr_offset, search); + SSVAL(SMB_Hdr(pkt), SMB_search_bcc_offset, param_len); + + /* Now plug in the file name ... */ + + p = (char *)(SMB_Hdr(pkt) + SMB_search_buf_offset); + *p = SMBasciiID; + strcpy(p+1, dir_name); + p = p + strlen(dir_name) + 2; /* Skip the null */ + + + + *p = SMBvariableblockID; + p = p + 1; + + /* And now the resume key */ + + SSVAL(p, 0, resumekey_len); + + p = p + 2; + + bcopy(resumekey, p, resumekey_len); + + /* Now send the packet and get the response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending search request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + RFCNB_Free_Pkt(recv_pkt); + SMBlib_errno = -SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, recv_pkt, recv_pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to Check Dir request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + RFCNB_Free_Pkt(recv_pkt); + SMBlib_errno = -SMBlibE_RecvFailed; + return(SMBlibE_BAD); + + } + + /* Now parse the response and pass back any error ... */ + + if (CVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */ + +#ifdef DEBUG + fprintf(stderr, "SMB_Check_Dir failed with errorclass = %i, Error Code = %i\n", + CVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset), + SVAL(SMB_Hdr(recv_pkt), SMB_hdr_err_offset)); +#endif + + SMBlib_SMB_Error = IVAL(SMB_Hdr(recv_pkt), SMB_hdr_rcls_offset); + RFCNB_Free_Pkt(pkt); + RFCNB_Free_Pkt(recv_pkt); + SMBlib_errno = SMBlibE_Remote; + return(SMBlibE_BAD); /* Should clean up ... */ + + } + + /* Now copy the results into the user's structure */ + + ret_count = SVAL(SMB_Hdr(recv_pkt), SMB_searchr_dec_offset); + + p = SMB_Hdr(recv_pkt) + SMB_searchr_buf_offset + 3; + + /* Hmmm, should check that we have the right number of bytes ... */ + + for (i = 0; i < ret_count; i++) { + + bcopy(p, dirents[i].resume_key, 21); + + p = p + 21; + + dirents[i].file_attributes = (unsigned char)*p; + + p = p + 1; + + dirents[i].date_time = IVAL(p, 0); /* Should this be IVAL? */ + + p = p + 4; + + dirents[i].size = IVAL(p, 0); + + p = p + 4; + + bcopy(p, dirents[i].filename, 13); /* Copy in file name */ + + p = p + 13; + + } + + return(ret_count); + +} diff --git a/daemon/smblib/find_password.c b/daemon/smblib/find_password.c new file mode 100644 index 0000000..c444732 --- /dev/null +++ b/daemon/smblib/find_password.c @@ -0,0 +1,281 @@ +/* Find passwords ... */ +/* We do it in a brute force way ... Cycle through all the possible passwords + sending a logon to see if all it works ... We have to wait for any timeout + the the server implements before we try the next one. We could open lots + of connections to the server and then send the logon request and not wait + for the reply. This would allow us to have lots of outstanding attempts at + a time. */ + +#include <sys/types.h> +#include <unistd.h> + +#include "smblib.h" + +int verbose = FALSE; +int lotc = FALSE; + +char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0", + "MICROSOFT NETWORKS 1.03", + "MICROSOFT NETWORKS 3.0", + "LANMAN1.0", + "LM1.2X002", + "LANMAN2.1", + "NT LM 0.12", + "NT LANMAN 1.0", + NULL}; + +void usage() + +{ + fprintf(stderr,"Usage: find_password -u <user> -l <pwd-len-max> server\n"); +} + +/* figure out next password */ + +static int pwinit = FALSE, pwpos = 0; + +int next_password(char *pw, int pwlen) + +{ int i, carry = FALSE; + + if (pwinit == FALSE) { + + pwinit = TRUE; + bzero(pw, pwlen + 1); + pwpos = 0; + + } + + i = pwpos; + + while (TRUE) { + + pw[i] = pw[i] + 1; + + /* If it has wrapped around, then inc to 1 and carry up the chain */ + + if (pw[i] == 0) { + + pw[i] = 1; + i = i - 1; + + if (i < 0) { /* If we went off the end, increment pwpos */ + + pwpos = pwpos + 1; + if (pwpos >= pwlen) return(FALSE); /* No more passwords */ + + pw[pwpos] = 1; + return(TRUE); + + } + + } + else + return(TRUE); + + return(FALSE); + } +} + +static char pwd_str[1024]; /* Where we put passwords as we convert them */ + +char *print_password(char * password) + +{ int i,j; + char temp[4]; + + j = 0; + + for (i = 0; i < strlen(password); i++){ + + if (((unsigned)password[i] <= ' ') || ((unsigned)password[i] > 127)) { + + pwd_str[j] = '\\'; + sprintf(temp, "%03i", (int)password[i]); + strcpy(&pwd_str[j + 1], temp); + j = j + 3; /* Space for \ accounted for below */ + + } + else + pwd_str[j] = password[i]; + + j = j + 1; + + } + + pwd_str[j] = 0; /* Put a null on the end ... */ + + return(pwd_str); + +} + +main(int argc, char *argv[]) + +{ void *con, *tree; + extern char *optarg; + extern int optind; + int opt, error, SMB_Error, err_class, err_code, pwlen, tries = 0; + char server[80], service[80], service_name[160], password[80], username[80]; + char old_password[80], err_string[1024]; + + server[0] = 0; + strncpy(service, "IPC$", sizeof(service) - 1); + service_name[0] = 0; + username[0] = 0; + password[0] = 0; + old_password[0] = 0; + + while ((opt = getopt(argc, argv, "s:u:l:v")) != EOF) { + + switch (opt) { + case 's': + + strcpy(service, optarg); + break; + + case 'u': /* Pick up the user name */ + + strncpy(username, optarg, sizeof(username) - 1); + break; + + case 'l': /* pick up password len */ + + pwlen = atoi(optarg); + break; + + case 'v': /* Verbose? */ + verbose = TRUE; + break; + + default: + + usage(); + exit(1); + break; + } + + } + + if (optind < argc) { /* Some more parameters, assume is the server */ + strncpy(server, argv[optind], sizeof(server) - 1); + optind++; + } + else { + strcpy(server, "nemesis"); + } + + if (verbose == TRUE) { /* Print out all we know */ + + fprintf(stderr, "Finding password for User: %s, on server: %s\n", + username, server); + fprintf(stderr, "with a pwlen = %i\n", pwlen); + + } + + SMB_Init(); /* Initialize things ... */ + + /* We connect to the server and negotiate */ + + con = SMB_Connect_Server(NULL, server); + + if (con == NULL) { /* Error processing */ + + fprintf(stderr, "Unable to connect to server %s ...\n", server); + + if (SMB_Get_Last_Error() == SMBlibE_Remote) { + + SMB_Error = SMB_Get_Last_SMB_Err(); + SMB_Get_SMB_Error_Msg(SMBlib_Error_Class(SMB_Error), + SMBlib_Error_Code(SMB_Error), + err_string, + sizeof(err_string) - 1); + + } + else { + SMB_Get_Error_Msg(SMB_Get_Last_Error(), err_string, sizeof(err_string) - 1); + } + + printf(" %s\n", err_string); + exit(1); + + } + + /* We need to negotiate a protocol better than PC NetWork Program */ + + if (SMB_Negotiate(con, SMB_Prots) < 0) { + + fprintf(stderr, "Unable to negotiate a protocol with server %s ...\n", + server); + + if (SMB_Get_Last_Error() == SMBlibE_Remote) { + + SMB_Error = SMB_Get_Last_SMB_Err(); + SMB_Get_SMB_Error_Msg(SMBlib_Error_Class(SMB_Error), + SMBlib_Error_Code(SMB_Error), + err_string, + sizeof(err_string) - 1); + + } + else { + SMB_Get_Error_Msg(SMB_Get_Last_Error(), err_string, sizeof(err_string) - 1); + } + + printf(" %s\n", err_string); + exit(1); + + } + + sprintf(service_name, "\\\\%s\\%s", server, service); /* Could blow up */ + + /* Now loop through all password possibilities ... */ + + bzero(password, sizeof(password)); + + while (next_password(password, pwlen) == TRUE) { + + if ((tree = SMB_Logon_And_TCon(con, + NULL, + username, + password, + service_name, "?????")) == NULL) { + + if (verbose == TRUE) { /* Lets hear about the error */ + + fprintf(stderr, "Unable to logon and tree connect to server %s ...\n", + server); + fprintf(stderr, "With username: %s, and password: %s\n", + username, print_password(password)); + + if (SMB_Get_Last_Error() == SMBlibE_Remote) { + + SMB_Error = SMB_Get_Last_SMB_Err(); + SMB_Get_SMB_Error_Msg(SMBlib_Error_Class(SMB_Error), + SMBlib_Error_Code(SMB_Error), + err_string, + sizeof(err_string) - 1); + + } + else { + SMB_Get_Error_Msg(SMB_Get_Last_Error(), err_string, sizeof(err_string) - 1); + } + + printf(" %s\n", err_string); + + } + } + else { /* Password match */ + + fprintf(stderr, "Logged in with password:%s\n", + print_password(password)); + + /* Exit now ... */ + + exit(0); + + } + + } + + fprintf(stderr, "Passwords exhausted."); + +} diff --git a/daemon/smblib/smb-errors.c b/daemon/smblib/smb-errors.c new file mode 100644 index 0000000..c2af25d --- /dev/null +++ b/daemon/smblib/smb-errors.c @@ -0,0 +1,220 @@ +/* UNIX SMBlib NetBIOS implementation + + Version 1.0 + SMBlib Error values etc ... + + Copyright (C) Richard Sharpe, Andrew Tridgell, and Merik Karman, 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. +*/ + +/* This code ripped out of smbclient, where it was attributed to Merik */ +/* Karman merik@blackadder.dsh.oz.au */ +/* Modified by Richard Sharpe to try to make it more bullit proof and */ +/* ensure we don't overwrite strings when not passed enough space. Also */ +/* added code to say unknown error codes if we see any */ + + +#include <stdio.h> + +typedef struct +{ + char *name; + int code; + char *message; +} err_code_struct; + +/* Dos Error Messages */ +err_code_struct dos_msgs[] = { + {"ERRbadfunc",1,"Invalid function."}, + {"ERRbadfile",2,"File not found."}, + {"ERRbadpath",3,"Directory invalid."}, + {"ERRnofids",4,"No file descriptors available"}, + {"ERRnoaccess",5,"Access denied."}, + {"ERRbadfid",6,"Invalid file handle."}, + {"ERRbadmcb",7,"Memory control blocks destroyed."}, + {"ERRnomem",8,"Insufficient server memory to perform the requested function."} +, + {"ERRbadmem",9,"Invalid memory block address."}, + {"ERRbadenv",10,"Invalid environment."}, + {"ERRbadformat",11,"Invalid format."}, + {"ERRbadaccess",12,"Invalid open mode."}, + {"ERRbaddata",13,"Invalid data."}, + {"ERR",14,"reserved."}, + {"ERRbaddrive",15,"Invalid drive specified."}, + {"ERRremcd",16,"A Delete Directory request attempted to remove the server's current directory."}, + {"ERRdiffdevice",17,"Not same device."}, + {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."}, + {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing FIDs on the file."}, + {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, + {"ERRbaddevtyp",66,"The device type is incorrect for a tree connect."}, + {"ERRbadnetnam",67,"The network name is incorrect or inappropriate."}, + {"ERRfilexists",80,"The file named in a Create Directory, Make New File or Link request already exists."}, + {"ERRbadpipe",230,"Pipe invalid."}, + {"ERRpipebusy",231,"All instances of the requested pipe are busy."}, + {"ERRpipeclosing",232,"Pipe close in progress."}, + {"ERRnotconnected",233,"No process on other end of pipe."}, + {"ERRmoredata",234,"There is more data to be returned."}, + {"ERRinvapi", 2142, "The API is invalid."}, + {NULL,-1,NULL}}; + +/* Server Error Messages */ +err_code_struct server_msgs[] = { + {"ERRerror",1,"Non-specific error code."}, + {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."}, + {"ERRbadtype",3,"reserved."}, + {"ERRaccess",4,"Network access denied. The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."}, + {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."}, + {"ERRinvnetname",6,"Invalid network name in tree connect."}, + {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."}, + {"ERRqfull",49,"Print queue full (files) -- returned by open print file."}, + {"ERRqtoobig",50,"Print queue full -- no space."}, + {"ERRqeof",51,"EOF on print queue dump."}, + {"ERRinvpfid",52,"Invalid print file FID."}, + {"ERRsmbcmd",64,"The server did not recognize the command received."}, + {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."}, + {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."}, + {"ERRreserved",68,"reserved."}, + {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."}, + {"ERRreserved",70,"reserved."}, + {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."}, + {"ERRpaused",81,"Server is paused."}, + {"ERRmsgoff",82,"Not receiving messages."}, + {"ERRnoroom",83,"No room to buffer message."}, + {"ERRrmuns",87,"Too many remote user names."}, + {"ERRtimeout",88,"Operation timed out."}, + {"ERRnoresource",89,"No resources currently available for request."}, + {"ERRtoomanyuids",90,"Too many UIDs active on this session."}, + {"ERRbaduid",91,"The UID is not known as a valid ID on this session."}, + {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."}, + {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."}, + {"ERRcontmpx",252,"Continue in MPX mode."}, + {"ERRreserved",253,"reserved."}, + {"ERRreserved",254,"reserved."}, + {"ERRpwdexp",2242,"Password has expired."}, + {"ERRnosupport",0xFFFF,"Function not supported."}, + {NULL,-1,NULL}}; + +/* Hard Error Messages */ +err_code_struct hard_msgs[] = { + {"ERRnowrite",19,"Attempt to write on write-protected diskette."}, + {"ERRbadunit",20,"Unknown unit."}, + {"ERRnotready",21,"Drive not ready."}, + {"ERRbadcmd",22,"Unknown command."}, + {"ERRdata",23,"Data error (CRC)."}, + {"ERRbadreq",24,"Bad request structure length."}, + {"ERRseek",25 ,"Seek error."}, + {"ERRbadmedia",26,"Unknown media type."}, + {"ERRbadsector",27,"Sector not found."}, + {"ERRnopaper",28,"Printer out of paper."}, + {"ERRwrite",29,"Write fault."}, + {"ERRread",30,"Read fault."}, + {"ERRgeneral",31,"General failure."}, + {"ERRbadshare",32,"A open conflicts with an existing open."}, + {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, + {"ERRwrongdisk",34,"The wrong disk was found in a drive."}, + {"ERRFCBUnavail",35,"No FCBs are available to process request."}, + {"ERRsharebufexc",36,"A sharing buffer has been exceeded."}, + {"ERRdiskfull",39,"The disk is full."}, + {NULL,-1,NULL}}; + +struct +{ + int code; + char *class; + err_code_struct *err_msgs; +} err_classes[] = { + {0,"SUCCESS",NULL}, + {0x01,"ERRDOS",dos_msgs}, + {0x02,"ERRSRV",server_msgs}, + {0x03,"ERRHRD",hard_msgs}, + {0x04,"ERRXOS",NULL}, + {0xE1,"ERRRMX1",NULL}, + {0xE2,"ERRRMX2",NULL}, + {0xE3,"ERRRMX3",NULL}, + {0xFF,"ERRCMD",NULL}, + {-1,NULL,NULL}}; + +/* Return in the string an error message after decoding the class and code */ + +int SMB_Get_SMB_Error_Msg(int err_class, int err_code, char *msg_buf, int len) + +{ int i,j; + char internal_buf[80]; + + for (i=0;err_classes[i].class;i++) + + if (err_classes[i].code == err_class) { + + if (err_classes[i].err_msgs) { + + err_code_struct *err = err_classes[i].err_msgs; + + for (j=0;err[j].name;j++) + + if (err_code == err[j].code) { + + /* Put together the message */ + + strncpy(msg_buf, err_classes[i].class, len); + strncat(msg_buf, " - ", len - strlen(msg_buf)); + strncat(msg_buf, err[j].name, len - strlen(msg_buf)); + strncat(msg_buf, " (", len - strlen(msg_buf)); + strncat(msg_buf, err[j].message, len - strlen(msg_buf)); + strncat(msg_buf, ").", len - strlen(msg_buf)); + + return(strlen(msg_buf)); + } + + /* We only get here if the error code is one we don't know about */ + /* Just print out the code etc ... */ + + strncpy(msg_buf, err_classes[i].class, len); + strncat(msg_buf, " - ", len - strlen(msg_buf)); + sprintf(internal_buf, "%d", err_code); + strncat(msg_buf, internal_buf, len - strlen(msg_buf)); + strncat(msg_buf, " (Unknown error code).", len - strlen(msg_buf)); + + return(strlen(msg_buf)); + + } + else { + + strncpy(msg_buf, err_classes[i].class, len); + strncat(msg_buf, " - ", len - strlen(msg_buf)); + sprintf(internal_buf, "%d", err_code); + strncat(msg_buf, internal_buf, len - strlen(msg_buf)); + + return(strlen(msg_buf)); + + } + + } + + /* If we get here, we did not recognize the error class */ + + sprintf(internal_buf, "%d", err_class); + strncat(msg_buf, internal_buf, len - strlen(msg_buf)); + strncat(msg_buf, " (Unknown Error Class) - ", len - strlen(msg_buf)); + sprintf(internal_buf, "%d", err_code); + strncat(msg_buf, internal_buf, len - strlen(msg_buf)); + strncat(msg_buf, "(error code).", len - strlen(msg_buf)); + + return(strlen(msg_buf)); + +} diff --git a/daemon/smblib/smbencrypt.c b/daemon/smblib/smbencrypt.c new file mode 100644 index 0000000..d46adc9 --- /dev/null +++ b/daemon/smblib/smbencrypt.c @@ -0,0 +1,202 @@ +#ifdef SMB_PASSWD +/* + Unix SMB/Netbios implementation. + Version 1.9. + SMB parameters and setup + Copyright (C) Andrew Tridgell 1992-1995 + Modified by Jeremy Allison 1995. + + 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 "includes.h" +#include "loadparm.h" +#include "des.h" +#include "md4.h" + +extern int DEBUGLEVEL; + +#ifndef uchar +#define uchar unsigned char +#endif +#ifndef int16 +#define int16 unsigned short +#endif +#ifndef uint16 +#define uint16 unsigned short +#endif +#ifndef uint32 +#define uint32 unsigned int +#endif + +#include "byteorder.h" + +void str_to_key(uchar *str,uchar *key) +{ + void des_set_odd_parity(des_cblock *); + int i; + + key[0] = str[0]>>1; + key[1] = ((str[0]&0x01)<<6) | (str[1]>>2); + key[2] = ((str[1]&0x03)<<5) | (str[2]>>3); + key[3] = ((str[2]&0x07)<<4) | (str[3]>>4); + key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5); + key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6); + key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7); + key[7] = str[6]&0x7F; + for (i=0;i<8;i++) { + key[i] = (key[i]<<1); + } + des_set_odd_parity((des_cblock *)key); +} + +void D1(uchar *k, uchar *d, uchar *out) +{ + des_key_schedule ks; + des_cblock deskey; + + str_to_key(k,(uchar *)deskey); + des_set_key(deskey,ks); + des_ecb_encrypt(d, out, ks, DES_DECRYPT); +} + +void E1(uchar *k, uchar *d, uchar *out) +{ + des_key_schedule ks; + des_cblock deskey; + + str_to_key(k,(uchar *)deskey); + des_set_key(deskey,ks); + des_ecb_encrypt(d, out, ks, DES_ENCRYPT); +} + +void E_P16(uchar *p14,uchar *p16) +{ + uchar sp7[7]; + /* the following constant makes us compatible with other + implementations. Note that publishing this constant does not reduce the + security of the encryption mechanism */ + uchar sp8[] = {0xAA,0xD3,0xB4,0x35,0xB5,0x14,0x4,0xEE}; + uchar x[8]; + + memset(sp7,'\0',7); + + D1(sp7, sp8, x); + E1(p14, x, p16); + E1(p14+7, x, p16+8); +} + +void E_P24(uchar *p21, uchar *c8, uchar *p24) +{ + E1(p21, c8, p24); + E1(p21+7, c8, p24+8); + E1(p21+14, c8, p24+16); +} + + +/* + This implements the X/Open SMB password encryption + It takes a password, a 8 byte "crypt key" and puts 24 bytes of + encrypted password into p24 */ +void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24) +{ + uchar p14[15], p21[21]; + + memset(p21,'\0',21); + memset(p14,'\0',14); + StrnCpy((char *)p14,(char *)passwd,14); + + strupper((char *)p14); + E_P16(p14, p21); + E_P24(p21, c8, p24); +} + +/* Routines for Windows NT MD4 Hash functions. */ +static int _my_wcslen(int16 *str) +{ + int len = 0; + while(*str++ != 0) + len++; + return len; +} + +/* + * Convert a string into an NT UNICODE string. + * Note that regardless of processor type + * this must be in intel (little-endian) + * format. + */ + +static int _my_mbstowcs(int16 *dst, uchar *src, int len) +{ + int i; + int16 val; + + for(i = 0; i < len; i++) { + val = *src; + SSVAL(dst,0,val); + dst++; + src++; + if(val == 0) + break; + } + return i; +} + +/* + * Creates the MD4 Hash of the users password in NT UNICODE. + */ + +void E_md4hash(uchar *passwd, uchar *p16) +{ + int i, len; + int16 wpwd[129]; + MDstruct MD; + + /* Password cannot be longer than 128 characters */ + len = strlen(passwd); + if(len > 128) + len = 128; + /* Password must be converted to NT unicode */ + _my_mbstowcs( wpwd, passwd, len); + wpwd[len] = 0; /* Ensure string is null terminated */ + /* Calculate length in bytes */ + len = _my_wcslen(wpwd) * sizeof(int16); + + MDbegin(&MD); + for(i = 0; i + 64 <= len; i += 64) + MDupdate(&MD,wpwd + (i/2), 512); + MDupdate(&MD,wpwd + (i/2),(len-i)*8); + SIVAL(p16,0,MD.buffer[0]); + SIVAL(p16,4,MD.buffer[1]); + SIVAL(p16,8,MD.buffer[2]); + SIVAL(p16,12,MD.buffer[3]); +} + +/* Does the NT MD4 hash then des encryption. */ + +void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24) +{ + uchar p21[21]; + + memset(p21,'\0',21); + + E_md4hash(passwd, p21); + E_P24(p21, c8, p24); +} + +#else +void smbencrypt_dummy(void){} +#endif diff --git a/daemon/smblib/smblib-api.c b/daemon/smblib/smblib-api.c new file mode 100644 index 0000000..f74e5fd --- /dev/null +++ b/daemon/smblib/smblib-api.c @@ -0,0 +1,379 @@ +/* UNIX SMBlib NetBIOS implementation + + Version 1.0 + SMB API Calls ... + + 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" + +SMB_Tree_Handle SMBapi_Tree = NULL; + +/* Send an api request to the \\server\IPC$ tree, with a \PIPE\LANMAN api */ +/* request to change the user's password */ + +#define SMB_LMAPI_SLOT "\\PIPE\\LANMAN" +#define SMB_LMAPI_SUPW_DESC "zb16b16WW" + +int SMBapi_NetUserPasswordSet(SMB_Tree_Handle tree, char *user, + char *oldpass, char *newpass, int *apiStatus) + +{ struct RFCNB_Pkt *pkt; + int param_len, i, pkt_len, pad_api_name = FALSE; + char *p; + + /* Get a packet, we need one with space for a transact plus. The calc */ + /* below lays it all out as it is, including the empty string after the */ + /* descriptor and before the username */ + + param_len = 2 + strlen(SMB_LMAPI_SUPW_DESC) + 1 + + 1 /* for empty string :-) */ + strlen(user) + + 1 + 16 + 16 + 2 + 2; + + /* We have no setup words, wo we don't account for them */ + + pkt_len = SMB_trans_len + 2 /* for bcc */ + strlen(SMB_LMAPI_SLOT) + 1; + + /* Pad things onto a word boundary ... */ + + if (pkt_len & 0x0001) { + pkt_len = pkt_len + 1; + pad_api_name = TRUE; + } + + + pkt_len = pkt_len + param_len; + + /* Now allocate space for the packet, build it and send it */ + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); /* Should handle the error */ + + } + + bzero(SMB_Hdr(pkt), SMB_trans_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtrans; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 14; + + SSVAL(SMB_Hdr(pkt), SMB_trans_tpc_offset, param_len); + SSVAL(SMB_Hdr(pkt), SMB_trans_tdc_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_trans_mpc_offset, 4); + SSVAL(SMB_Hdr(pkt), SMB_trans_mdc_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_trans_msc_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_trans_flg_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_trans_tmo_offset, 5000); + SSVAL(SMB_Hdr(pkt), SMB_trans_pbc_offset, param_len); + SSVAL(SMB_Hdr(pkt), SMB_trans_pbo_offset, SMB_trans_len + 2 + + strlen(SMB_LMAPI_SLOT) + 1); + SSVAL(SMB_Hdr(pkt), SMB_trans_dbc_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_trans_dbo_offset, 0); + + /* Now put in the bcc and the rest of the info ... */ + + SSVAL(SMB_Hdr(pkt), SMB_trans_len, param_len + strlen(SMB_LMAPI_SLOT) + 1); + + p = SMB_Hdr(pkt) + SMB_trans_len + 2; /* Skip the BCC and ect */ + + strcpy(p, SMB_LMAPI_SLOT); + p = p + strlen(SMB_LMAPI_SLOT) + 1; + + if (pad_api_name == TRUE) /* Pad if we need to */ + p = p + 1; + +/* SSVAL(p, 0, 65000); /* Check the result */ + SSVAL(p, 0, SMB_LMapi_UserPasswordSet); /* The api call */ + + p = p + 2; + + strcpy(p, SMB_LMAPI_SUPW_DESC); /* Copy in the param desc */ + + p = p + strlen(SMB_LMAPI_SUPW_DESC) + 1; + + *p = 0; /* Stick in that null string */ + p = p + 1; + + strcpy(p, user); + + p = p + strlen(user) + 1; + + strncpy(p, oldpass, 16); + + p = p + 16; + + strncpy(p, newpass, 16); + + p = p + 16; + + SSVAL(p, 0, 0); /* Seems to be zero always? */ + SSVAL(p, 2, strlen(newpass)); /* Length of new password ...*/ + + /* Now send the lot and get a response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Trans request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to Trans request\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_trans 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); + + } + + /* All ok, pass back the status */ + + *apiStatus = SVAL(SMB_Hdr(pkt), SVAL(SMB_Hdr(pkt), SMB_transr_pbo_offset)); + RFCNB_Free_Pkt(pkt); + + return(0); + +} + +#define SMB_LMAPI_SUI_DESC "zWsTPWW" +#define SMB_LMAPI_SUI_DATA_DESC "B16" + + +/* Set user info ... specifically, password */ + +int SMBapi_NetSetUserInfo(SMB_Tree_Handle tree, char *user, + char *newpass, int *apiStatus) + +{ struct RFCNB_Pkt *pkt; + int param_len, i, pkt_len, data_len, pad_api_name = FALSE; + int pad_params = FALSE; + char *p; + + /* Get a packet, we need one with space for a transact plus. The calc */ + /* below lays it all out as it is, including the empty string after the */ + /* descriptor and before the username */ + + param_len = 2 + strlen(SMB_LMAPI_SUI_DESC) + 1 + + + strlen(SMB_LMAPI_SUI_DATA_DESC) + 1 + strlen(user) + + 1 + 2 + 2 + 2 + 2; + + data_len = 16; + + /* We have no setup words, so we don't account for them */ + + pkt_len = SMB_trans_len + 2 /* for bcc */ + strlen(SMB_LMAPI_SLOT) + 1; + + if (pkt_len & 0x0001) { /* Pad to a WORD boundary */ + + pad_api_name = TRUE; + + } + + if (param_len & 0x0001) { /* pad to a WORD boundary */ + + pad_params = TRUE; + + } + + pkt_len = pkt_len + param_len + data_len; + + if (pad_api_name == TRUE) pkt_len = pkt_len + 1; + if (pad_params == TRUE) pkt_len = pkt_len + 1; + + /* Now allocate space for the packet, build it and send it */ + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); /* Should handle the error */ + + } + + bzero(SMB_Hdr(pkt), SMB_trans_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtrans; + SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, tree -> con -> pid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, tree -> tid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, tree -> con -> mid); + SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, tree -> con -> uid); + *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 14; + + SSVAL(SMB_Hdr(pkt), SMB_trans_tpc_offset, param_len); + SSVAL(SMB_Hdr(pkt), SMB_trans_tdc_offset, data_len); + SSVAL(SMB_Hdr(pkt), SMB_trans_mpc_offset, 4); + SSVAL(SMB_Hdr(pkt), SMB_trans_mdc_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_trans_msc_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_trans_flg_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_trans_tmo_offset, 5000); + SSVAL(SMB_Hdr(pkt), SMB_trans_pbc_offset, param_len); + SSVAL(SMB_Hdr(pkt), SMB_trans_pbo_offset, SMB_trans_len + 2 + + strlen(SMB_LMAPI_SLOT) + 1); + SSVAL(SMB_Hdr(pkt), SMB_trans_dbc_offset, data_len); + SSVAL(SMB_Hdr(pkt), SMB_trans_dbo_offset, pkt_len - data_len); + + /* Now put in the bcc and the rest of the info ... */ + + SSVAL(SMB_Hdr(pkt), SMB_trans_len, param_len + strlen(SMB_LMAPI_SLOT) + + 1 + data_len); + + p = SMB_Hdr(pkt) + SMB_trans_len + 2; /* Skip the BCC and ect */ + + strcpy(p, SMB_LMAPI_SLOT); + p = p + strlen(SMB_LMAPI_SLOT) + 1; + + if (pad_api_name == TRUE) /* Pad to a word boundary */ + p = p + 1; + +/* SSVAL(p, 0, 65000); /* Check the result */ + SSVAL(p, 0, SMB_LMapi_SetUserInfo); /* The api call */ + + p = p + 2; + + strcpy(p, SMB_LMAPI_SUI_DESC); /* Copy in the param desc */ + + p = p + strlen(SMB_LMAPI_SUI_DESC) + 1; + + strcpy(p, SMB_LMAPI_SUI_DATA_DESC); /* Copy in second descriptor */ + + p = p + strlen(SMB_LMAPI_SUI_DATA_DESC) + 1; + + strcpy(p, user); + + p = p + strlen(user) + 1; + + SSVAL(p, 0, 1); /* Claim that we have a level 1 struct ? */ + + p = p + 2; + + SSVAL(p, 0, 3); /* Set the password */ + SSVAL(p, 2, 1); /* Seems to be one ... */ + SSVAL(p, 4, strlen(newpass)); /* Length of new password ...*/ + + /* Now copy the data in ... */ + + p = p + 6; + + if (pad_params == TRUE) + p = p + 1; + + strcpy(p, newpass); + + /* Now send the lot and get a response ... */ + + if (RFCNB_Send(tree -> con -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending Trans SetUserInfo request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(tree -> con -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to Trans SetUserInfo request\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_trans SetUserInfo 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); + + } + + /* All ok, pass back the status */ + + *apiStatus = SVAL(SMB_Hdr(pkt), SVAL(SMB_Hdr(pkt), SMB_transr_pbo_offset)); + RFCNB_Free_Pkt(pkt); + + return(0); + +} + +/* List all the shares available on a server */ + +int SMBapi_NetShareEnum(SMB_Tree_Handle tree, char *enum_buf, int bufsiz, + int *shares_returned, int *shares_total) + +{ + + +} diff --git a/daemon/smblib/smblib-common.h b/daemon/smblib/smblib-common.h new file mode 100644 index 0000000..ff2a160 --- /dev/null +++ b/daemon/smblib/smblib-common.h @@ -0,0 +1,184 @@ +/* UNIX SMBlib NetBIOS implementation + + Version 1.0 + SMBlib Common Defines + + 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. +*/ + +/* To get the error class we want the first 8 bits */ +/* Because we just grab 4bytes from the SMB header, we have to re-order */ +/* here, but it makes the NtStatus part easier in future */ + +#define SMBlib_Error_Class(p) (p & 0x000000FF) + +/* To get the error code, we want the bottom 16 bits */ + +#define SMBlib_Error_Code(p) (((unsigned int)p & 0xFFFF0000) >>16) + +/* Error CLASS codes and etc ... */ + +#define SMBC_SUCCESS 0 +#define SMBC_ERRDOS 0x01 +#define SMBC_ERRSRV 0x02 +#define SMBC_ERRHRD 0x03 +#define SMBC_ERRCMD 0xFF + +/* Success error codes */ + +#define SMBS_BUFFERED 0x54 +#define SMBS_LOGGED 0x55 +#define SMBS_DISPLAYED 0x56 + +/* ERRDOS Error codes */ + +#define SMBD_badfunc 0x01 +#define SMBD_badfile 0x02 +#define SMBD_badpath 0x03 +#define SMBD_nofids 0x04 +#define SMBD_noaccess 0x05 +#define SMBD_badfid 0x06 +#define SMBD_badmcb 0x07 +#define SMBD_nomem 0x08 +#define SMBD_badmem 0x09 +#define SMBD_badenv 0x0A +#define SMBD_badformat 0x0B +#define SMBD_badaccess 0x0C +#define SMBD_baddata 0x0D +#define SMBD_reserved 0x0E +#define SMBD_baddrive 0x0F +#define SMBD_remcd 0x10 +#define SMBD_diffdevice 0x11 +#define SMBD_nofiles 0x12 +#define SMBD_badshare 0x20 +#define SMBD_errlock 0x21 +#define SMBD_filexists 0x50 + +/* Server errors ... */ + +#define SMBV_error 0x01 /* Generic error */ +#define SMBV_badpw 0x02 +#define SMBV_badtype 0x03 +#define SMBV_access 0x04 +#define SMBV_invnid 0x05 +#define SMBV_invnetname 0x06 +#define SMBV_invdevice 0x07 +#define SMBV_qfull 0x31 +#define SMBV_qtoobig 0x32 +#define SMBV_qeof 0x33 +#define SMBV_invpfid 0x34 +#define SMBV_paused 0x51 +#define SMBV_msgoff 0x52 +#define SMBV_noroom 0x53 +#define SMBV_rmuns 0x57 +#define SMBV_nosupport 0xFFFF + +/* Hardware error codes ... */ + +#define SMBH_nowrite 0x13 +#define SMBH_badunit 0x14 +#define SMBH_notready 0x15 +#define SMBH_badcmd 0x16 +#define SMBH_data 0x17 +#define SMBH_badreq 0x18 +#define SMBH_seek 0x19 +#define SMBH_badmedia 0x1A +#define SMBH_badsector 0x1B +#define SMBH_nopaper 0x1C +#define SMBH_write 0x1D +#define SMBH_read 0x1E +#define SMBH_general 0x1F +#define SMBH_badshare 0x20 + +/* Access mode defines ... */ + +#define SMB_AMODE_WTRU 0x4000 +#define SMB_AMODE_NOCACHE 0x1000 +#define SMB_AMODE_COMPAT 0x0000 +#define SMB_AMODE_DENYRWX 0x0010 +#define SMB_AMODE_DENYW 0x0020 +#define SMB_AMODE_DENYRX 0x0030 +#define SMB_AMODE_DENYNONE 0x0040 +#define SMB_AMODE_OPENR 0x0000 +#define SMB_AMODE_OPENW 0x0001 +#define SMB_AMODE_OPENRW 0x0002 +#define SMB_AMODE_OPENX 0x0003 +#define SMB_AMODE_FCBOPEN 0x00FF +#define SMB_AMODE_LOCUNKN 0x0000 +#define SMB_AMODE_LOCMSEQ 0x0100 +#define SMB_AMODE_LOCMRAN 0x0200 +#define SMB_AMODE_LOCRAL 0x0300 + +/* File attribute encoding ... */ + +#define SMB_FA_ORD 0x00 +#define SMB_FA_ROF 0x01 +#define SMB_FA_HID 0x02 +#define SMB_FA_SYS 0x04 +#define SMB_FA_VOL 0x08 +#define SMB_FA_DIR 0x10 +#define SMB_FA_ARC 0x20 + +/* Define the protocol types ... */ + +#define SMB_P_Unknown -1 /* Hmmm, is this smart? */ +#define SMB_P_Core 0 +#define SMB_P_CorePlus 1 +#define SMB_P_DOSLanMan1 2 +#define SMB_P_LanMan1 3 +#define SMB_P_DOSLanMan2 4 +#define SMB_P_LanMan2 5 +#define SMB_P_DOSLanMan2_1 6 +#define SMB_P_LanMan2_1 7 +#define SMB_P_NT1 8 + +/* SMBlib return codes */ +/* We want something that indicates whether or not the return code was a */ +/* remote error, a local error in SMBlib or returned from lower layer ... */ +/* Wonder if this will work ... */ +/* SMBlibE_Remote = 1 indicates remote error */ +/* SMBlibE_ values < 0 indicate local error with more info available */ +/* SMBlibE_ values >1 indicate local from SMBlib code errors? */ + +#define SMBlibE_Success 0 +#define SMBlibE_Remote 1 /* Remote error, get more info from con */ +#define SMBlibE_BAD -1 +#define SMBlibE_LowerLayer 2 /* Lower layer error */ +#define SMBlibE_NotImpl 3 /* Function not yet implemented */ +#define SMBlibE_ProtLow 4 /* Protocol negotiated does not support req */ +#define SMBlibE_NoSpace 5 /* No space to allocate a structure */ +#define SMBlibE_BadParam 6 /* Bad parameters */ +#define SMBlibE_NegNoProt 7 /* None of our protocols was liked */ +#define SMBlibE_SendFailed 8 /* Sending an SMB failed */ +#define SMBlibE_RecvFailed 9 /* Receiving an SMB failed */ +#define SMBlibE_GuestOnly 10 /* Logged in as guest */ +#define SMBlibE_CallFailed 11 /* Call remote end failed */ +#define SMBlibE_ProtUnknown 12 /* Protocol unknown */ +#define SMBlibE_NoSuchMsg 13 /* Keep this up to date */ + +typedef struct { /* A structure for a Dirent */ + + unsigned char resume_key[21]; /* Don't touch this */ + unsigned char file_attributes; /* Attributes of file */ + unsigned int date_time; /* date and time of last mod */ + unsigned int size; + char filename[13]; /* The name of the file */ + +} SMB_CP_dirent; diff --git a/daemon/smblib/smblib-priv.h b/daemon/smblib/smblib-priv.h new file mode 100644 index 0000000..58cda9d --- /dev/null +++ b/daemon/smblib/smblib-priv.h @@ -0,0 +1,624 @@ +/* UNIX SMBlib NetBIOS implementation + + Version 1.0 + SMBlib private Defines + + 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 "std-defines.h" +#include "smblib-common.h" +#include <sys/types.h> +#include <unistd.h> + +typedef unsigned short uint16; +typedef unsigned int uint32; + +#include "../rfcnb/byteorder.h" /* Hmmm ... hot good */ + +#define max(a,b) (a < b ? b : a) + +#define SMB_DEF_IDF 0x424D53FF /* "\377SMB" */ + +/* Core protocol commands */ + +#define SMBmkdir 0x00 /* create directory */ +#define SMBrmdir 0x01 /* delete directory */ +#define SMBopen 0x02 /* open file */ +#define SMBcreate 0x03 /* create file */ +#define SMBclose 0x04 /* close file */ +#define SMBflush 0x05 /* flush file */ +#define SMBunlink 0x06 /* delete file */ +#define SMBmv 0x07 /* rename file */ +#define SMBgetatr 0x08 /* get file attributes */ +#define SMBsetatr 0x09 /* set file attributes */ +#define SMBread 0x0A /* read from file */ +#define SMBwrite 0x0B /* write to file */ +#define SMBlock 0x0C /* lock byte range */ +#define SMBunlock 0x0D /* unlock byte range */ +#define SMBctemp 0x0E /* create temporary file */ +#define SMBmknew 0x0F /* make new file */ +#define SMBchkpth 0x10 /* check directory path */ +#define SMBexit 0x11 /* process exit */ +#define SMBlseek 0x12 /* seek */ +#define SMBtcon 0x70 /* tree connect */ +#define SMBtdis 0x71 /* tree disconnect */ +#define SMBnegprot 0x72 /* negotiate protocol */ +#define SMBdskattr 0x80 /* get disk attributes */ +#define SMBsearch 0x81 /* search directory */ +#define SMBsplopen 0xC0 /* open print spool file */ +#define SMBsplwr 0xC1 /* write to print spool file */ +#define SMBsplclose 0xC2 /* close print spool file */ +#define SMBsplretq 0xC3 /* return print queue */ +#define SMBsends 0xD0 /* send single block message */ +#define SMBsendb 0xD1 /* send broadcast message */ +#define SMBfwdname 0xD2 /* forward user name */ +#define SMBcancelf 0xD3 /* cancel forward */ +#define SMBgetmac 0xD4 /* get machine name */ +#define SMBsendstrt 0xD5 /* send start of multi-block message */ +#define SMBsendend 0xD6 /* send end of multi-block message */ +#define SMBsendtxt 0xD7 /* send text of multi-block message */ + +/* CorePlus protocol */ + +#define SMBlockread 0x13 /* Lock a range and read it */ +#define SMBwriteunlock 0x14 /* Unlock a range and then write */ +#define SMBreadbraw 0x1a /* read a block of data without smb header ohead*/ +#define SMBwritebraw 0x1d /* write a block of data without smb header ohead*/ +#define SMBwritec 0x20 /* secondary write request */ +#define SMBwriteclose 0x2c /* write a file and then close it */ + +/* DOS Extended Protocol */ + +#define SMBreadBraw 0x1A /* read block raw */ +#define SMBreadBmpx 0x1B /* read block multiplexed */ +#define SMBreadBs 0x1C /* read block (secondary response) */ +#define SMBwriteBraw 0x1D /* write block raw */ +#define SMBwriteBmpx 0x1E /* write block multiplexed */ +#define SMBwriteBs 0x1F /* write block (secondary request) */ +#define SMBwriteC 0x20 /* write complete response */ +#define SMBsetattrE 0x22 /* set file attributes expanded */ +#define SMBgetattrE 0x23 /* get file attributes expanded */ +#define SMBlockingX 0x24 /* lock/unlock byte ranges and X */ +#define SMBtrans 0x25 /* transaction - name, bytes in/out */ +#define SMBtranss 0x26 /* transaction (secondary request/response) */ +#define SMBioctl 0x27 /* IOCTL */ +#define SMBioctls 0x28 /* IOCTL (secondary request/response) */ +#define SMBcopy 0x29 /* copy */ +#define SMBmove 0x2A /* move */ +#define SMBecho 0x2B /* echo */ +#define SMBopenX 0x2D /* open and X */ +#define SMBreadX 0x2E /* read and X */ +#define SMBwriteX 0x2F /* write and X */ +#define SMBsesssetupX 0x73 /* Session Set Up & X (including User Logon) */ +#define SMBtconX 0x75 /* tree connect and X */ +#define SMBffirst 0x82 /* find first */ +#define SMBfunique 0x83 /* find unique */ +#define SMBfclose 0x84 /* find close */ +#define SMBinvalid 0xFE /* invalid command */ + +/* Any more ? */ + +#define SMBdatablockID 0x01 /* A data block identifier */ +#define SMBdialectID 0x02 /* A dialect id */ +#define SMBpathnameID 0x03 /* A pathname ID */ +#define SMBasciiID 0x04 /* An ascii string ID */ +#define SMBvariableblockID 0x05 /* A variable block ID */ + +/* some other defines we need */ + +/* Flags defines ... */ + +#define SMB_FLG2_NON_DOS 0x01 /* We know non dos names */ +#define SMB_FLG2_EXT_ATR 0x02 /* We know about Extended Attributes */ +#define SMB_FLG2_LNG_NAM 0x04 /* Long names ? */ + +typedef unsigned short WORD; +typedef unsigned short UWORD; +typedef unsigned int ULONG; +typedef unsigned char BYTE; +typedef unsigned char UCHAR; + +/* Some macros to allow access to actual packet data so that we */ +/* can change the underlying representation of packets. */ +/* */ +/* The current formats vying for attention are a fragment */ +/* approach where the SMB header is a fragment linked to the */ +/* data portion with the transport protocol (rfcnb or whatever) */ +/* being linked on the front. */ +/* */ +/* The other approach is where the whole packet is one array */ +/* of bytes with space allowed on the front for the packet */ +/* headers. */ + +#define SMB_Hdr(p) (char *)(p -> data) + +/* SMB Hdr def for File Sharing Protocol? From MS and Intel, */ +/* Intel PN 138446 Doc Version 2.0, Nov 7, 1988. This def also */ +/* applies to LANMAN1.0 as well as the Core Protocol */ +/* The spec states that wct and bcc must be present, even if 0 */ + +/* We define these as offsets into a char SMB[] array for the */ +/* sake of portability */ + +/* NOTE!. Some of the lenght defines, SMB_<protreq>_len do not include */ +/* the data that follows in the SMB packet, so the code will have to */ +/* take that into account. */ + +#define SMB_hdr_idf_offset 0 /* 0xFF,'SMB' 0-3 */ +#define SMB_hdr_com_offset 4 /* BYTE 4 */ +#define SMB_hdr_rcls_offset 5 /* BYTE 5 */ +#define SMB_hdr_reh_offset 6 /* BYTE 6 */ +#define SMB_hdr_err_offset 7 /* WORD 7 */ +#define SMB_hdr_reb_offset 9 /* BYTE 9 */ +#define SMB_hdr_flg_offset 9 /* same as reb ...*/ +#define SMB_hdr_res_offset 10 /* 7 WORDs 10 */ +#define SMB_hdr_res0_offset 10 /* WORD 10 */ +#define SMB_hdr_flg2_offset 10 /* WORD */ +#define SMB_hdr_res1_offset 12 /* WORD 12 */ +#define SMB_hdr_res2_offset 14 +#define SMB_hdr_res3_offset 16 +#define SMB_hdr_res4_offset 18 +#define SMB_hdr_res5_offset 20 +#define SMB_hdr_res6_offset 22 +#define SMB_hdr_tid_offset 24 +#define SMB_hdr_pid_offset 26 +#define SMB_hdr_uid_offset 28 +#define SMB_hdr_mid_offset 30 +#define SMB_hdr_wct_offset 32 + +#define SMB_hdr_len 33 /* 33 byte header? */ + +#define SMB_hdr_axc_offset 33 /* AndX Command */ +#define SMB_hdr_axr_offset 34 /* AndX Reserved */ +#define SMB_hdr_axo_offset 35 /* Offset from start to WCT of AndX cmd */ + +/* Format of the Negotiate Protocol SMB */ + +#define SMB_negp_bcc_offset 33 +#define SMB_negp_buf_offset 35 /* Where the buffer starts */ +#define SMB_negp_len 35 /* plus the data */ + +/* Format of the Negotiate Response SMB, for CoreProtocol, LM1.2 and */ +/* NT LM 0.12. wct will be 1 for CoreProtocol, 13 for LM 1.2, and 17 */ +/* for NT LM 0.12 */ + +#define SMB_negrCP_idx_offset 33 /* Response to the neg req */ +#define SMB_negrCP_bcc_offset 35 +#define SMB_negrLM_idx_offset 33 /* dialect index */ +#define SMB_negrLM_sec_offset 35 /* Security mode */ +#define SMB_sec_user_mask 0x01 /* 0 = share, 1 = user */ +#define SMB_sec_encrypt_mask 0x02 /* pick out encrypt */ +#define SMB_negrLM_mbs_offset 37 /* max buffer size */ +#define SMB_negrLM_mmc_offset 39 /* max mpx count */ +#define SMB_negrLM_mnv_offset 41 /* max number of VCs */ +#define SMB_negrLM_rm_offset 43 /* raw mode support bit vec*/ +#define SMB_read_raw_mask 0x01 +#define SMB_write_raw_mask 0x02 +#define SMB_negrLM_sk_offset 45 /* session key, 32 bits */ +#define SMB_negrLM_st_offset 49 /* Current server time */ +#define SMB_negrLM_sd_offset 51 /* Current server date */ +#define SMB_negrLM_stz_offset 53 /* Server Time Zone */ +#define SMB_negrLM_ekl_offset 55 /* encryption key length */ +#define SMB_negrLM_res_offset 57 /* reserved */ +#define SMB_negrLM_bcc_offset 59 /* bcc */ +#define SMB_negrLM_len 61 /* 61 bytes ? */ +#define SMB_negrLM_buf_offset 61 /* Where the fun begins */ + +#define SMB_negrNTLM_idx_offset 33 /* Selected protocol */ +#define SMB_negrNTLM_sec_offset 35 /* Security more */ +#define SMB_negrNTLM_mmc_offset 36 /* Different format above */ +#define SMB_negrNTLM_mnv_offset 38 /* Max VCs */ +#define SMB_negrNTLM_mbs_offset 40 /* MBS now a long */ +#define SMB_negrNTLM_mrs_offset 44 /* Max raw size */ +#define SMB_negrNTLM_sk_offset 48 /* Session Key */ +#define SMB_negrNTLM_cap_offset 52 /* Capabilities */ +#define SMB_negrNTLM_stl_offset 56 /* Server time low */ +#define SMB_negrNTLM_sth_offset 60 /* Server time high */ +#define SMB_negrNTLM_stz_offset 64 /* Server time zone */ +#define SMB_negrNTLM_ekl_offset 66 /* Encrypt key len */ +#define SMB_negrNTLM_bcc_offset 67 /* Bcc */ +#define SMB_negrNTLM_len 69 +#define SMB_negrNTLM_buf_offset 69 + +/* Offsets related to Tree Connect */ + +#define SMB_tcon_bcc_offset 33 +#define SMB_tcon_buf_offset 35 /* where the data is for tcon */ +#define SMB_tcon_len 35 /* plus the data */ + +#define SMB_tconr_mbs_offset 33 /* max buffer size */ +#define SMB_tconr_tid_offset 35 /* returned tree id */ +#define SMB_tconr_bcc_offset 37 +#define SMB_tconr_len 39 + +#define SMB_tconx_axc_offset 33 /* And X Command */ +#define SMB_tconx_axr_offset 34 /* reserved */ +#define SMB_tconx_axo_offset 35 /* Next command offset */ +#define SMB_tconx_flg_offset 37 /* Flags, bit0=1 means disc TID */ +#define SMB_tconx_pwl_offset 39 /* Password length */ +#define SMB_tconx_bcc_offset 41 /* bcc */ +#define SMB_tconx_buf_offset 43 /* buffer */ +#define SMB_tconx_len 43 /* up to data ... */ + +#define SMB_tconxr_axc_offset 33 /* Where the AndX Command is */ +#define SMB_tconxr_axr_offset 34 /* Reserved */ +#define SMB_tconxr_axo_offset 35 /* AndX offset location */ + +/* Offsets related to tree_disconnect */ + +#define SMB_tdis_bcc_offset 33 /* bcc */ +#define SMB_tdis_len 35 /* total len */ + +#define SMB_tdisr_bcc_offset 33 /* bcc */ +#define SMB_tdisr_len 35 + +/* Offsets related to Open Request */ + +#define SMB_open_mod_offset 33 /* Mode to open with */ +#define SMB_open_atr_offset 35 /* Attributes of file */ +#define SMB_open_bcc_offset 37 /* bcc */ +#define SMB_open_buf_offset 39 /* File name */ +#define SMB_open_len 39 /* Plus the file name */ + +#define SMB_openx_axc_offset 33 /* Next command */ +#define SMB_openx_axr_offset 34 /* Reserved */ +#define SMB_openx_axo_offset 35 /* offset of next wct */ +#define SMB_openx_flg_offset 37 /* Flags, bit0 = need more info */ + /* bit1 = exclusive oplock */ + /* bit2 = batch oplock */ +#define SMB_openx_mod_offset 39 /* mode to open with */ +#define SMB_openx_atr_offset 41 /* search attributes */ +#define SMB_openx_fat_offset 43 /* File attributes */ +#define SMB_openx_tim_offset 45 /* time and date of creat */ +#define SMB_openx_ofn_offset 49 /* Open function */ +#define SMB_openx_als_offset 51 /* Space to allocate on */ +#define SMB_openx_res_offset 55 /* reserved */ +#define SMB_openx_bcc_offset 63 /* bcc */ +#define SMB_openx_buf_offset 65 /* Where file name goes */ +#define SMB_openx_len 65 + +#define SMB_openr_fid_offset 33 /* FID returned */ +#define SMB_openr_atr_offset 35 /* Attributes opened with */ +#define SMB_openr_tim_offset 37 /* Last mod time of file */ +#define SMB_openr_fsz_offset 41 /* File size 4 bytes */ +#define SMB_openr_acc_offset 45 /* Access allowed */ +#define SMB_openr_bcc_offset 47 +#define SMB_openr_len 49 + +#define SMB_openxr_axc_offset 33 /* And X command */ +#define SMB_openxr_axr_offset 34 /* reserved */ +#define SMB_openxr_axo_offset 35 /* offset to next command */ +#define SMB_openxr_fid_offset 37 /* FID returned */ +#define SMB_openxr_fat_offset 39 /* File attributes returned*/ +#define SMB_openxr_tim_offset 41 /* File creation date etc */ +#define SMB_openxr_fsz_offset 45 /* Size of file */ +#define SMB_openxr_acc_offset 49 /* Access granted */ + +#define SMB_clos_fid_offset 33 /* FID to close */ +#define SMB_clos_tim_offset 35 /* Last mod time */ +#define SMB_clos_bcc_offset 39 /* bcc */ +#define SMB_clos_len 41 + +/* Offsets related to Write requests */ + +#define SMB_write_fid_offset 33 /* FID to write */ +#define SMB_write_cnt_offset 35 /* bytes to write */ +#define SMB_write_ofs_offset 37 /* location to write to */ +#define SMB_write_clf_offset 41 /* advisory count left */ +#define SMB_write_bcc_offset 43 /* bcc = data bytes + 3 */ +#define SMB_write_buf_offset 45 /* Data=0x01, len, data */ +#define SMB_write_len 45 /* plus the data ... */ + +#define SMB_writr_cnt_offset 33 /* Count of bytes written */ +#define SMB_writr_bcc_offset 35 /* bcc */ +#define SMB_writr_len 37 + +/* Offsets related to read requests */ + +#define SMB_read_fid_offset 33 /* FID of file to read */ +#define SMB_read_cnt_offset 35 /* count of words to read */ +#define SMB_read_ofs_offset 37 /* Where to read from */ +#define SMB_read_clf_offset 41 /* Advisory count to go */ +#define SMB_read_bcc_offset 43 +#define SMB_read_len 45 + +#define SMB_readr_cnt_offset 33 /* Count of bytes returned */ +#define SMB_readr_res_offset 35 /* 4 shorts reserved, 8 bytes */ +#define SMB_readr_bcc_offset 43 /* bcc */ +#define SMB_readr_bff_offset 45 /* buffer format char = 0x01 */ +#define SMB_readr_len_offset 46 /* buffer len */ +#define SMB_readr_len 45 /* length of the readr before data */ + +/* Offsets for Create file */ + +#define SMB_creat_atr_offset 33 /* Attributes of new file ... */ +#define SMB_creat_tim_offset 35 /* Time of creation */ +#define SMB_creat_dat_offset 37 /* 4004BCE :-) */ +#define SMB_creat_bcc_offset 39 /* bcc */ +#define SMB_creat_buf_offset 41 +#define SMB_creat_len 41 /* Before the data */ + +#define SMB_creatr_fid_offset 33 /* FID of created file */ + +/* Offsets for Delete file */ + +#define SMB_delet_sat_offset 33 /* search attribites */ +#define SMB_delet_bcc_offset 35 /* bcc */ +#define SMB_delet_buf_offset 37 +#define SMB_delet_len 37 + +/* Offsets for SESSION_SETUP_ANDX for both LM and NT LM protocols */ + +#define SMB_ssetpLM_mbs_offset 37 /* Max buffer Size, allow for AndX */ +#define SMB_ssetpLM_mmc_offset 39 /* max multiplex count */ +#define SMB_ssetpLM_vcn_offset 41 /* VC number if new VC */ +#define SMB_ssetpLM_snk_offset 43 /* Session Key */ +#define SMB_ssetpLM_pwl_offset 47 /* password length */ +#define SMB_ssetpLM_res_offset 49 /* reserved */ +#define SMB_ssetpLM_bcc_offset 53 /* bcc */ +#define SMB_ssetpLM_len 55 /* before data ... */ +#define SMB_ssetpLM_buf_offset 55 + +#define SMB_ssetpNTLM_mbs_offset 37 /* Max Buffer Size for NT LM 0.12 */ + /* and above */ +#define SMB_ssetpNTLM_mmc_offset 39 /* Max Multiplex count */ +#define SMB_ssetpNTLM_vcn_offset 41 /* VC Number */ +#define SMB_ssetpNTLM_snk_offset 43 /* Session key */ +#define SMB_ssetpNTLM_cipl_offset 47 /* Case Insensitive PW Len */ +#define SMB_ssetpNTLM_cspl_offset 49 /* Unicode pw len */ +#define SMB_ssetpNTLM_res_offset 51 /* reserved */ +#define SMB_ssetpNTLM_cap_offset 55 /* server capabilities */ +#define SMB_ssetpNTLM_bcc_offset 59 /* bcc */ +#define SMB_ssetpNTLM_len 61 /* before data */ +#define SMB_ssetpNTLM_buf_offset 61 + +#define SMB_ssetpr_axo_offset 35 /* Offset of next response ... */ +#define SMB_ssetpr_act_offset 37 /* action, bit 0 = 1 => guest */ +#define SMB_ssetpr_bcc_offset 39 /* bcc */ +#define SMB_ssetpr_buf_offset 41 /* Native OS etc */ + +/* Offsets for SMB create directory */ + +#define SMB_creatdir_bcc_offset 33 /* only a bcc here */ +#define SMB_creatdir_buf_offset 35 /* Where things start */ +#define SMB_creatdir_len 35 + +/* Offsets for SMB delete directory */ + +#define SMB_deletdir_bcc_offset 33 /* only a bcc here */ +#define SMB_deletdir_buf_offset 35 /* where things start */ +#define SMB_deletdir_len 35 + +/* Offsets for SMB check directory */ + +#define SMB_checkdir_bcc_offset 33 /* Only a bcc here */ +#define SMB_checkdir_buf_offset 35 /* where things start */ +#define SMB_checkdir_len 35 + +/* Offsets for SMB search */ + +#define SMB_search_mdc_offset 33 /* Max Dir ents to return */ +#define SMB_search_atr_offset 35 /* Search attributes */ +#define SMB_search_bcc_offset 37 /* bcc */ +#define SMB_search_buf_offset 39 /* where the action is */ +#define SMB_search_len 39 + +#define SMB_searchr_dec_offset 33 /* Dir ents returned */ +#define SMB_searchr_bcc_offset 35 /* bcc */ +#define SMB_searchr_buf_offset 37 /* Where the action starts */ +#define SMB_searchr_len 37 /* before the dir ents */ + +#define SMB_searchr_dirent_len 43 /* 53 bytes */ + +/* Defines for SMB transact and transact2 calls */ + +#define SMB_trans_tpc_offset 33 /* Total param count */ +#define SMB_trans_tdc_offset 35 /* total Data count */ +#define SMB_trans_mpc_offset 37 /* Max params bytes to return */ +#define SMB_trans_mdc_offset 39 /* Max data bytes to return */ +#define SMB_trans_msc_offset 41 /* Max setup words to return */ +#define SMB_trans_rs1_offset 42 /* Reserved byte */ +#define SMB_trans_flg_offset 43 /* flags */ +#define SMB_trans_tmo_offset 45 /* Timeout, long */ +#define SMB_trans_rs2_offset 49 /* Next reserved */ +#define SMB_trans_pbc_offset 51 /* Param Byte count in buf */ +#define SMB_trans_pbo_offset 53 /* Offset to param bytes */ +#define SMB_trans_dbc_offset 55 /* Data byte count in buf */ +#define SMB_trans_dbo_offset 57 /* Data byte offset */ +#define SMB_trans_suc_offset 59 /* Setup count - byte */ +#define SMB_trans_rs3_offset 60 /* Reserved to pad ... */ +#define SMB_trans_len 61 /* Up to setup, still need bcc */ + +#define SMB_transr_tpc_offset 33 /* Total param bytes returned */ +#define SMB_transr_tdc_offset 35 +#define SMB_transr_rs1_offset 37 +#define SMB_transr_pbc_offset 39 +#define SMB_transr_pbo_offset 41 +#define SMB_transr_pdi_offset 43 /* parameter displacement */ +#define SMB_transr_dbc_offset 45 +#define SMB_transr_dbo_offset 47 +#define SMB_transr_ddi_offset 49 +#define SMB_transr_suc_offset 51 +#define SMB_transr_rs2_offset 52 +#define SMB_transr_len 53 + +/* Bit masks for SMB Capabilities ... */ + +#define SMB_cap_raw_mode 0x0001 +#define SMB_cap_mpx_mode 0x0002 +#define SMB_cap_unicode 0x0004 +#define SMB_cap_large_files 0x0008 +#define SMB_cap_nt_smbs 0x0010 +#define SMB_rpc_remote_apis 0x0020 +#define SMB_cap_nt_status 0x0040 +#define SMB_cap_level_II_oplocks 0x0080 +#define SMB_cap_lock_and_read 0x0100 +#define SMB_cap_nt_find 0x0200 + +/* SMB LANMAN api call defines */ + +#define SMB_LMapi_SetUserInfo 0x0072 +#define SMB_LMapi_UserPasswordSet 0x0073 + +/* Structures and defines we use in the client interface */ + +/* The protocols we might support. Perhaps a bit ambitious, as only RFCNB */ +/* has any support so far 0(sometimes called NBT) */ + +typedef enum {SMB_RFCNB, SMB_IPXNB, SMB_NETBEUI, SMB_X25} SMB_Transport_Types; + +typedef enum {SMB_Con_FShare, SMB_Con_PShare, SMB_Con_IPC} SMB_Con_Types; + +typedef enum {SMB_State_NoState, SMB_State_Stopped, SMB_State_Started} SMB_State_Types; + +/* The following two arrays need to be in step! */ +/* We must make it possible for callers to specify these ... */ + + +static char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0", + "MICROSOFT NETWORKS 1.03", + "MICROSOFT NETWORKS 3.0", + "DOS LANMAN1.0", + "LANMAN1.0", + "DOS LM1.2X002", + "LM1.2X002", + "DOS LANMAN2.1", + "LANMAN2.1", + "Samba", + "NT LM 0.12", + "NT LANMAN 1.0", + NULL}; + +static int SMB_Types[] = {SMB_P_Core, + SMB_P_CorePlus, + SMB_P_DOSLanMan1, + SMB_P_DOSLanMan1, + SMB_P_LanMan1, + SMB_P_DOSLanMan2, + SMB_P_LanMan2, + SMB_P_LanMan2_1, + SMB_P_LanMan2_1, + SMB_P_NT1, + SMB_P_NT1, + SMB_P_NT1, + -1}; + +typedef struct SMB_Status { + + union { + struct { + unsigned char ErrorClass; + unsigned char Reserved; + unsigned short Error; + } DosError; + unsigned int NtStatus; + } status; +} SMB_Status; + +typedef struct SMB_Tree_Structure * SMB_Tree_Handle; + +typedef struct SMB_Connect_Def * SMB_Handle_Type; + +struct SMB_Connect_Def { + + SMB_Handle_Type Next_Con, Prev_Con; /* Next and previous conn */ + int protocol; /* What is the protocol */ + int prot_IDX; /* And what is the index */ + void *Trans_Connect; /* The connection */ + + /* All these strings should be malloc'd */ + + char service[80], username[80], password[80], desthost[80], sock_options[80]; + char address[80], myname[80]; + + SMB_Tree_Handle first_tree, last_tree; /* List of trees on this server */ + + int gid; /* Group ID, do we need it? */ + int mid; /* Multiplex ID? We might need one per con */ + int pid; /* Process ID */ + + int uid; /* Authenticated user id. */ + + /* It is pretty clear that we need to bust some of */ + /* these out into a per TCon record, as there may */ + /* be multiple TCon's per server, etc ... later */ + + int port; /* port to use in case not default, this is a TCPism! */ + + int max_xmit; /* Max xmit permitted by server */ + int Security; /* 0 = share, 1 = user */ + int Raw_Support; /* bit 0 = 1 = Read Raw supported, 1 = 1 Write raw */ + BOOL encrypt_passwords; /* FALSE = don't */ + int MaxMPX, MaxVC, MaxRaw; + unsigned int SessionKey, Capabilities; + int SvrTZ; /* Server Time Zone */ + int Encrypt_Key_Len; + char Encrypt_Key[80], Domain[80], PDomain[80], OSName[80], LMType[40]; + char Svr_OS[80], Svr_LMType[80], Svr_PDom[80]; + +}; + +#define SMBLIB_DEFAULT_DOMAIN "SMBlib_dom" +#define SMBLIB_DEFAULT_OSNAME "UNIX of some type" +#define SMBLIB_DEFAULT_LMTYPE "SMBlib LM2.1 minus a bit" +#define SMBLIB_MAX_XMIT 65535 + +#define SMB_Sec_Mode_Share 0 +#define SMB_Sec_Mode_User 1 + +/* A Tree_Structure */ + +struct SMB_Tree_Structure { + + SMB_Tree_Handle next, prev; + SMB_Handle_Type con; + char path[129]; + char device_type[20]; + int mbs; /* Local MBS */ + int tid; + +}; + +typedef struct SMB_File_Def SMB_File; + +struct SMB_File_Def { + + SMB_Tree_Handle tree; + char filename[256]; /* We should malloc this ... */ + UWORD fid; + unsigned int lastmod; + unsigned int size; /* Could blow up if 64bit files supported */ + UWORD access; + off_t fileloc; + +}; + +/* global Variables for the library */ + +extern SMB_State_Types SMBlib_State; + +#ifndef SMBLIB_ERRNO +extern int SMBlib_errno; +extern int SMBlib_SMB_Error; /* last Error */ +#endif + +SMB_Tree_Handle SMB_TreeConnect(SMB_Handle_Type con, SMB_Tree_Handle tree, + char *path, char *password, char *dev); 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)); + + } + } + +} diff --git a/daemon/smblib/smblib.c b/daemon/smblib/smblib.c new file mode 100644 index 0000000..2074420 --- /dev/null +++ b/daemon/smblib/smblib.c @@ -0,0 +1,549 @@ +/* UNIX SMBlib NetBIOS implementation + + Version 1.0 + SMBlib 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. +*/ + +int SMBlib_errno; +int SMBlib_SMB_Error; +#define SMBLIB_ERRNO + +#include <string.h> +#include "smblib-priv.h" + +#include "../rfcnb/rfcnb.h" + +#include <signal.h> + +SMB_State_Types SMBlib_State; + +/* Initialize the SMBlib package */ + +int SMB_Init() + +{ + + SMBlib_State = SMB_State_Started; + + signal(SIGPIPE, SIG_IGN); /* Ignore these ... */ + +/* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */ +#ifdef SMBLIB_INSTRUMENT + + SMBlib_Instrument_Init(); + +#endif + + return 0; + +} + +int SMB_Term() + +{ + +#ifdef SMBLIB_INSTRUMENT + + SMBlib_Instrument_Term(); /* Clean up and print results */ + +#endif + + return 0; + +} + +/* SMB_Create: Create a connection structure and return for later use */ +/* We have other helper routines to set variables */ + +SMB_Handle_Type SMB_Create_Con_Handle() + +{ + + SMBlib_errno = SMBlibE_NotImpl; + return(NULL); + +} + +int SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn) + +{ + + + if (RFCNB_Set_Sock_NoDelay(Con_Handle -> Trans_Connect, yn) < 0) { + +#ifdef DEBUG +#endif + + fprintf(stderr, "Setting no-delay on TCP socket failed ...\n"); + + } + + return(0); + +} + +/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */ +/* or anything else ... */ + +SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle, + char *server) + +{ SMB_Handle_Type con; + char temp[80], called[80], calling[80], *address; + int i; + + /* Get a connection structure if one does not exist */ + + con = Con_Handle; + + if (Con_Handle == NULL) { + + if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) { + + + SMBlib_errno = SMBlibE_NoSpace; + return NULL; + } + + } + + /* Init some things ... */ + + strcpy(con -> service, ""); + strcpy(con -> username, ""); + strcpy(con -> password, ""); + strcpy(con -> sock_options, ""); + strcpy(con -> address, ""); + strcpy(con -> desthost, server); + strcpy(con -> PDomain, SMBLIB_DEFAULT_DOMAIN); + strcpy(con -> OSName, SMBLIB_DEFAULT_OSNAME); + strcpy(con -> LMType, SMBLIB_DEFAULT_LMTYPE); + con -> first_tree = con -> last_tree = NULL; + + SMB_Get_My_Name(con -> myname, sizeof(con -> myname)); + + con -> port = 0; /* No port selected */ + + /* Get some things we need for the SMB Header */ + + con -> pid = getpid(); + con -> mid = con -> pid; /* This will do for now ... */ + con -> uid = 0; /* Until we have done a logon, no uid ... */ + con -> gid = getgid(); + + /* Now connect to the remote end, but first upper case the name of the + service we are going to call, sine some servers want it in uppercase */ + + for (i=0; i < strlen(server); i++) + called[i] = toupper(server[i]); + + called[strlen(server)] = 0; /* Make it a string */ + + for (i=0; i < strlen(con -> myname); i++) + calling[i] = toupper(con -> myname[i]); + + calling[strlen(con -> myname)] = 0; /* Make it a string */ + + if (strcmp(con -> address, "") == 0) + address = con -> desthost; + else + address = con -> address; + + con -> Trans_Connect = RFCNB_Call(called, + calling, + address, /* Protocol specific */ + con -> port); + + /* Did we get one? */ + + if (con -> Trans_Connect == NULL) { + + if (Con_Handle == NULL) { + Con_Handle = NULL; + free(con); + } + SMBlib_errno = -SMBlibE_CallFailed; + return NULL; + + } + + return(con); + +} + +/* SMB_Connect: Connect to the indicated server */ +/* If Con_Handle == NULL then create a handle and connect, otherwise */ +/* use the handle passed */ + +char *SMB_Prots_Restrict[] = {"PC NETWORK PROGRAM 1.0", + NULL}; + + +SMB_Handle_Type SMB_Connect(SMB_Handle_Type Con_Handle, + SMB_Tree_Handle *tree, + char *service, + char *username, + char *password) + +{ SMB_Handle_Type con; + char *host, *address; + char temp[80], called[80], calling[80]; + int i; + + /* Get a connection structure if one does not exist */ + + con = Con_Handle; + + if (Con_Handle == NULL) { + + if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return NULL; + } + + } + + /* Init some things ... */ + + strcpy(con -> service, service); + strcpy(con -> username, username); + strcpy(con -> password, password); + strcpy(con -> sock_options, ""); + strcpy(con -> address, ""); + strcpy(con -> PDomain, SMBLIB_DEFAULT_DOMAIN); + strcpy(con -> OSName, SMBLIB_DEFAULT_OSNAME); + strcpy(con -> LMType, SMBLIB_DEFAULT_LMTYPE); + con -> first_tree = con -> last_tree = NULL; + + SMB_Get_My_Name(con -> myname, sizeof(con -> myname)); + + con -> port = 0; /* No port selected */ + + /* Get some things we need for the SMB Header */ + + con -> pid = getpid(); + con -> mid = con -> pid; /* This will do for now ... */ + con -> uid = 0; /* Until we have done a logon, no uid */ + con -> gid = getgid(); + + /* Now figure out the host portion of the service */ + + strcpy(temp, service); + host = strtok(temp, "/\\"); /* Separate host name portion */ + strcpy(con -> desthost, host); + + /* Now connect to the remote end, but first upper case the name of the + service we are going to call, sine some servers want it in uppercase */ + + for (i=0; i < strlen(host); i++) + called[i] = toupper(host[i]); + + called[strlen(host)] = 0; /* Make it a string */ + + for (i=0; i < strlen(con -> myname); i++) + calling[i] = toupper(con -> myname[i]); + + calling[strlen(con -> myname)] = 0; /* Make it a string */ + + if (strcmp(con -> address, "") == 0) + address = con -> desthost; + else + address = con -> address; + + con -> Trans_Connect = RFCNB_Call(called, + calling, + address, /* Protocol specific */ + con -> port); + + /* Did we get one? */ + + if (con -> Trans_Connect == NULL) { + + if (Con_Handle == NULL) { + free(con); + Con_Handle = NULL; + } + SMBlib_errno = -SMBlibE_CallFailed; + return NULL; + + } + + /* Now, negotiate the protocol */ + + if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) { + + /* Hmmm what should we do here ... We have a connection, but could not + negotiate ... */ + + return NULL; + + } + + /* Now connect to the service ... */ + + if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) { + + return NULL; + + } + + return(con); + +} + +/* Logon to the server. That is, do a session setup if we can. We do not do */ +/* Unicode yet! */ + +int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName, + char *PassWord) + +{ struct RFCNB_Pkt *pkt; + int param_len, i, pkt_len; + char *p; + + /* First we need a packet etc ... but we need to know what protocol has */ + /* been negotiated to figure out if we can do it and what SMB format to */ + /* use ... */ + + if (Con_Handle -> protocol < SMB_P_LanMan1) { + + SMBlib_errno = SMBlibE_ProtLow; + return(SMBlibE_BAD); + + } + + /* Now build the correct structure */ + + if (Con_Handle -> protocol < SMB_P_NT1) { + + /* We don't handle encrypted passwords ... */ + + param_len = strlen(UserName) + 1 + strlen(PassWord) + 1 + + strlen(Con_Handle -> PDomain) + 1 + + strlen(Con_Handle -> OSName) + 1; + + pkt_len = SMB_ssetpLM_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return(SMBlibE_BAD); /* Should handle the error */ + + } + + bzero(SMB_Hdr(pkt), SMB_ssetpLM_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX; + 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) = 10; + *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */ + SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0); + + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle -> pid); + SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, strlen(PassWord) + 1); + SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len); + + /* Now copy the param strings in with the right stuff */ + + p = (char *)(SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset); + + /* Copy in password, then the rest. Password has a null at end */ + + strcpy(p, PassWord); + + p = p + strlen(PassWord) + 1; + + strcpy(p, UserName); + p = p + strlen(UserName); + *p = 0; + + p = p + 1; + + strcpy(p, Con_Handle -> PDomain); + p = p + strlen(Con_Handle -> PDomain); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle -> OSName); + p = p + strlen(Con_Handle -> OSName); + *p = 0; + + } + else { + + /* We don't admit to UNICODE support ... */ + + param_len = strlen(UserName) + 1 + strlen(PassWord) + + strlen(Con_Handle -> PDomain) + 1 + + strlen(Con_Handle -> OSName) + 1 + + strlen(Con_Handle -> LMType) + 1; + + pkt_len = SMB_ssetpNTLM_len + param_len; + + pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len); + + if (pkt == NULL) { + + SMBlib_errno = SMBlibE_NoSpace; + return(-1); /* Should handle the error */ + + } + + bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len); + SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */ + *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX; + 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) = 13; + *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */ + SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0); + + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, strlen(PassWord)); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0); + SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0); + SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len); + + /* Now copy the param strings in with the right stuff */ + + p = (char *)(SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset); + + /* Copy in password, then the rest. Password has no null at end */ + + strcpy(p, PassWord); + + p = p + strlen(PassWord); + + strcpy(p, UserName); + p = p + strlen(UserName); + *p = 0; + + p = p + 1; + + strcpy(p, Con_Handle -> PDomain); + p = p + strlen(Con_Handle -> PDomain); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle -> OSName); + p = p + strlen(Con_Handle -> OSName); + *p = 0; + p = p + 1; + + strcpy(p, Con_Handle -> LMType); + p = p + strlen(Con_Handle -> LMType); + *p = 0; + + } + + /* Now send it and get a response */ + + if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){ + +#ifdef DEBUG + fprintf(stderr, "Error sending SessSetupX request\n"); +#endif + + RFCNB_Free_Pkt(pkt); + SMBlib_errno = SMBlibE_SendFailed; + return(SMBlibE_BAD); + + } + + /* Now get the response ... */ + + if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) { + +#ifdef DEBUG + fprintf(stderr, "Error receiving response to SessSetupAndX\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_SessSetupAndX 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); + + } + +#ifdef DEBUG + fprintf(stderr, "SessSetupAndX response. Action = %i\n", + SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset)); +#endif + + /* Now pick up the UID for future reference ... */ + + Con_Handle -> uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset); + RFCNB_Free_Pkt(pkt); + + return(0); + +} + + +/* Disconnect from the server, and disconnect all tree connects */ + +int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle) + +{ + + /* We just disconnect the connection for now ... */ + + RFCNB_Hangup(Con_Handle -> Trans_Connect); + + if (!KeepHandle) + free(Con_Handle); + + return(0); + +} diff --git a/daemon/smblib/smblib.h b/daemon/smblib/smblib.h new file mode 100644 index 0000000..c485ef5 --- /dev/null +++ b/daemon/smblib/smblib.h @@ -0,0 +1,95 @@ +/* UNIX SMBlib NetBIOS implementation + + Version 1.0 + SMBlib Defines + + 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 "std-defines.h" +#include "smblib-common.h" + +/* Just define all the entry points */ + +/* Create a handle to allow us to set/override some parameters ... */ + +void *SMB_Create_Con_Handle(); + +/* Connect to a server, but do not do a tree con etc ... */ + +void *SMB_Connect_Server(void *Con, char *server); + +/* Connect to a server and give us back a handle. If Con == NULL, create */ +/* The handle and populate it with defaults */ + +void *SMB_Connect(void *Con, void **tree, + char *name, char *User, char *Password); + +/* Negotiate a protocol */ + +int SMB_Negotiate(void *Con_Handle, char *Prots[]); + +/* Connect to a tree ... */ + +void *SMB_TreeConnect(void *con_handle, void *tree_handle, + char *path, char *password, char *dev); + +/* Disconnect a tree ... */ + +int SMB_TreeDisconect(void *tree_handle); + +/* Open a file */ + +void *SMB_Open(void *tree_handle, + void *file_handle, + char *file_name, + unsigned short mode, + unsigned short search); + +/* Close a file */ + +int SMB_Close(void *file_handle); + +/* Disconnect from server. Has flag to specify whether or not we keep the */ +/* handle. */ + +int SMB_Discon(void *Con, BOOL KeepHandle); + +void *SMB_Create(void *Tree_Handle, + void *File_Handle, + char *file_name, + short search); + +int SMB_Delete(void *tree, char *file_name, short search); + +int SMB_Create_Dir(void *tree, char *dir_name); + +int SMB_Delete_Dir(void *tree, char *dir_name); + +int SMB_Check_Dir(void *tree, char *dir_name); + +int SMB_Get_Last_Error(); + +int SMB_Get_Last_SMB_Err(); + +int SMB_Get_Error_Msg(int msg, char *msgbuf, int len); + +void *SMB_Logon_And_TCon(void *con, void *tree, char *user, char *pass, + char *service, char *st); diff --git a/daemon/smblib/std-defines.h b/daemon/smblib/std-defines.h new file mode 100644 index 0000000..c58329d --- /dev/null +++ b/daemon/smblib/std-defines.h @@ -0,0 +1,45 @@ +/* RFCNB Standard includes ... */ +/* + + SMBlib Standard Includes + + Copyright (C) 1996, Richard Sharpe + +/* One day we will conditionalize these on OS types ... */ + +/* + 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. +*/ + +#ifndef __STD_DEFINES_H__ +#define __STD_DEFINES_H__ + +#define BOOL int +typedef short int16; + +#include <netdb.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <signal.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <strings.h> + +#define TRUE 1 +#define FALSE 0 + +#endif |