/* 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
#define uchar unsigned char
#include "smblib-priv.h"
#include "rfcnb.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, char *NTdomain)
{ 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, NTdomain);
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 */
static const 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, pass_len,a;
char *p, pword[256];
/* 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);
}
strcpy(pword, PassWord);
if (Con_Handle -> encrypt_passwords)
{
pass_len=24;
SMBencrypt((uchar *) PassWord, (uchar *)Con_Handle -> Encrypt_Key,(uchar *)pword);
}
else
pass_len=strlen(pword);
/* Now build the correct structure */
if (Con_Handle -> protocol < SMB_P_NT1) {
param_len = strlen(UserName) + 1 + pass_len + 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, pass_len + 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 */
memcpy(p, pword, pass_len);
p = p + pass_len + 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 + pass_len +
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, pass_len);
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 */
memcpy(p, pword, pass_len);
p = p + pass_len;
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);
}
/** @@@ mdz: check for guest login { **/
if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1)
{
/* do we allow guest login? NO! */
return(SMBlibE_BAD);
}
/** @@@ mdz: } **/
#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);
}
syntax highlighted by Code2HTML, v. 0.9.1