#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <string.h>
#include "smblib-priv.h"
#include "rfcnb.h"
void SMB_Print_Pkt(FILE fd, RFCNB_Pkt *pkt, BOOL command, int Offset, int Len)
{
}
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);
}
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);
}
int SMB_Get_Tree_MBS(SMB_Tree_Handle tree)
{
if (tree != NULL) {
return(tree -> mbs);
}
else {
return(SMBlibE_BAD);
}
}
int SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle)
{
if (Con_Handle != NULL) {
return(Con_Handle -> max_xmit);
}
else {
return(SMBlibE_BAD);
}
}
int SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle)
{
if (Con_Handle != NULL) {
return(Con_Handle -> prot_IDX);
}
else {
return(0xFFFF);
}
}
int SMB_Get_Protocol(SMB_Handle_Type Con_Handle)
{
if (Con_Handle != NULL) {
return(Con_Handle -> protocol);
}
else {
return(0xFFFF);
}
}
int SMB_Figure_Protocol(char *dialects[], int prot_index)
{ int i;
if (dialects == SMB_Prots) {
return(SMB_Types[prot_index]);
}
else {
for (i = 0; SMB_Prots[i] != NULL; i++) {
if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) {
return(SMB_Types[i]);
}
}
return(SMB_P_Unknown);
}
}
int SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[])
{
struct RFCNB_Pkt *pkt;
int prots_len, i, pkt_len, prot, alloc_len;
char *p;
prots_len = 0;
for (i = 0; Prots[i] != NULL; i++) {
prots_len = prots_len + strlen(Prots[i]) + 2;
}
pkt_len = SMB_negp_len + prots_len;
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);
}
bzero(SMB_Hdr(pkt), SMB_negp_len);
SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_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);
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;
}
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;
return(SMBlibE_BAD);
}
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;
return(SMBlibE_BAD);
}
if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {
#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);
}
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) {
RFCNB_Free_Pkt(pkt);
SMBlib_errno = SMBlibE_ProtUnknown;
return(SMBlibE_BAD);
}
switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) {
case 0x01:
break;
case 13:
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);
fprintf(stderr, "%s", (char *)(SMB_Hdr(pkt) + SMB_negrLM_buf_offset));
memcpy(Con_Handle->Encrypt_Key, p, 8);
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:
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_negrNTLM_buf_offset );
memcpy(Con_Handle -> Encrypt_Key, p, 8);
p = (SMB_Hdr(pkt) + SMB_negrNTLM_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);
}
void SMB_Get_My_Name(char *name, int len)
{
if (gethostname(name, len) < 0) {
strncpy(name, "unknown", len);
#ifdef DEBUG
fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:");
perror("");
#endif
}
}
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, pkt_len;
char *p;
SMB_Tree_Handle tree;
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);
}
param_len = strlen(path) + 2 + strlen(password) + 2 + strlen(device) + 2;
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);
}
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));
bzero(SMB_Hdr(pkt), SMB_tcon_len);
SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_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);
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);
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);
}
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);
}
if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {
#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
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);
}
bzero(SMB_Hdr(pkt), SMB_tdis_len);
SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_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);
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);
}
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);
}
if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {
#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;
Tree_Handle -> mbs = 0;
#ifdef DEBUG
fprintf(stderr, "Tree disconnect successful ...\n");
#endif
if (discard == TRUE) {
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);
}
int SMB_Get_Last_Error()
{
return(SMBlib_errno);
}
int SMB_Get_Last_SMB_Err()
{
return(SMBlib_SMB_Error);
}
static const 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.",
"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;
}
else {
char prot_msg[1024];
msg = -msg;
strncpy(msgbuf,
SMBlib_Error_Messages[msg>SMBlibE_NoSuchMsg?SMBlibE_NoSuchMsg:msg],
len - 1);
msgbuf[len - 1] = 0;
if (strlen(msgbuf) < len) {
strncat(msgbuf, "\n\t", len - strlen(msgbuf));
RFCNB_Get_Error(prot_msg, sizeof(prot_msg) - 1);
strncat(msgbuf, prot_msg, len - strlen(msgbuf));
}
}
return 0;
}