1 /****************************************************************************
3 * Nintendo Wii/GameCube SMB implementation
6 * Modified by Tantric to utilize NTLM authentication
7 * PathInfo added by rodries
8 * SMB devoptab by scip, rodries
10 * You will find WireShark (http://www.wireshark.org/)
11 * invaluable for debugging SAMBA implementations.
14 * Implementing CIFS - Christopher R Hertel
15 * http://www.ubiqx.org/cifs/SMB.html
19 * This library is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU Lesser General Public
21 * License as published by the Free Software Foundation; either
22 * version 2.1 of the License, or (at your option) any later version.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 ****************************************************************************/
44 #include <processor.h>
45 #include <lwp_threads.h>
46 #include <lwp_objmgr.h>
47 #include <ogc/lwp_watchdog.h>
48 #include <sys/statvfs.h>
53 #define IOS_O_NONBLOCK 0x04
54 #define RECV_TIMEOUT 3000 // in ms
55 #define CONN_TIMEOUT 6000
60 #define SMB_OFFSET_PROTO 0
61 #define SMB_OFFSET_CMD 4
62 #define SMB_OFFSET_NTSTATUS 5
63 #define SMB_OFFSET_ECLASS 5
64 #define SMB_OFFSET_ECODE 7
65 #define SMB_OFFSET_FLAGS 9
66 #define SMB_OFFSET_FLAGS2 10
67 #define SMB_OFFSET_EXTRA 12
68 #define SMB_OFFSET_TID 24
69 #define SMB_OFFSET_PID 26
70 #define SMB_OFFSET_UID 28
71 #define SMB_OFFSET_MID 30
72 #define SMB_HEADER_SIZE 32 /*** SMB Headers are always 32 bytes long ***/
77 #define NBT_SESSISON_MSG 0x00
79 #define SMB_NEG_PROTOCOL 0x72
80 #define SMB_SETUP_ANDX 0x73
81 #define SMB_TREEC_ANDX 0x75
84 #define NBT_KEEPALIVE_MSG 0x85
85 #define KEEPALIVE_SIZE 4
90 #define SMB_TRANS2 0x32
93 #define SMB_FIND_FIRST2 1
94 #define SMB_FIND_NEXT2 2
95 #define SMB_QUERY_FS_INFO 3
96 #define SMB_QUERY_PATH_INFO 5
97 #define SMB_SET_PATH_INFO 6
98 #define SMB_QUERY_FILE_INFO 7
99 #define SMB_SET_FILE_INFO 8
100 #define SMB_CREATE_DIR 13
101 #define SMB_FIND_CLOSE2 0x34
102 #define SMB_QUERY_FILE_ALL_INFO 0x107
107 #define SMB_OPEN_ANDX 0x2d
108 #define SMB_WRITE_ANDX 0x2f
109 #define SMB_READ_ANDX 0x2e
110 #define SMB_CLOSE 0x04
115 #define SMB_COM_CREATE_DIRECTORY 0x00
116 #define SMB_COM_DELETE_DIRECTORY 0x01
117 #define SMB_COM_DELETE 0x06
118 #define SMB_COM_RENAME 0x07
119 #define SMB_COM_QUERY_INFORMATION_DISK 0x80
124 #define T2_WORD_CNT (SMB_HEADER_SIZE)
125 #define T2_PRM_CNT (T2_WORD_CNT+1)
126 #define T2_DATA_CNT (T2_PRM_CNT+2)
127 #define T2_MAXPRM_CNT (T2_DATA_CNT+2)
128 #define T2_MAXBUFFER (T2_MAXPRM_CNT+2)
129 #define T2_SETUP_CNT (T2_MAXBUFFER+2)
130 #define T2_SPRM_CNT (T2_SETUP_CNT+10)
131 #define T2_SPRM_OFS (T2_SPRM_CNT+2)
132 #define T2_SDATA_CNT (T2_SPRM_OFS+2)
133 #define T2_SDATA_OFS (T2_SDATA_CNT+2)
134 #define T2_SSETUP_CNT (T2_SDATA_OFS+2)
135 #define T2_SUB_CMD (T2_SSETUP_CNT+2)
136 #define T2_BYTE_CNT (T2_SUB_CMD+2)
139 #define SMB_PROTO 0x424d53ff
140 #define SMB_HANDLE_NULL 0xffffffff
141 #define SMB_MAX_NET_READ_SIZE (16*1024) // see smb_recv
142 #define SMB_MAX_NET_WRITE_SIZE 4096 // see smb_sendv
143 #define SMB_MAX_TRANSMIT_SIZE 65472
145 #define CAP_LARGE_FILES 0x00000008 // 64-bit file sizes and offsets supported
146 #define CAP_UNICODE 0x00000004 // Unicode supported
147 #define CIFS_FLAGS1 0x08 // Paths are caseless
148 #define CIFS_FLAGS2_UNICODE 0x8001 // Server may return long components in paths in the response - use 0x8001 for Unicode support
149 #define CIFS_FLAGS2 0x0001 // Server may return long components in paths in the response - use 0x0001 for ASCII support
151 #define SMB_CONNHANDLES_MAX 8
152 #define SMB_FILEHANDLES_MAX (32*SMB_CONNHANDLES_MAX)
154 #define SMB_OBJTYPE_HANDLE 7
155 #define SMB_CHECK_HANDLE(hndl) \
157 if(((hndl)==SMB_HANDLE_NULL) || (LWP_OBJTYPE(hndl)!=SMB_OBJTYPE_HANDLE)) \
161 /* NBT Session Service Packet Type Codes
164 #define SESS_MSG 0x00
165 #define SESS_REQ 0x81
166 #define SESS_POS_RESP 0x82
167 #define SESS_NEG_RESP 0x83
168 #define SESS_RETARGET 0x84
169 #define SESS_KEEPALIVE 0x85
181 typedef struct _nbtsmb
183 u8 msg
; /*** NBT Message ***/
185 u16 length
; /*** Length, excluding NBT ***/
186 u8 smb
[SMB_MAX_TRANSMIT_SIZE
+128];
190 * Session Information
192 typedef struct _smbsession
212 typedef struct _smbhandle
220 struct sockaddr_in server_addr
;
227 static u32 smb_dialectcnt
= 1;
228 static bool smb_inited
= false;
229 static lwp_objinfo smb_handle_objects
;
230 static lwp_queue smb_filehandle_queue
;
231 static struct _smbfile smb_filehandles
[SMB_FILEHANDLES_MAX
];
232 static const char *smb_dialects
[] = {"NT LM 0.12",NULL
};
234 extern void ntlm_smb_nt_encrypt(const char *passwd
, const u8
* challenge
, u8
* answer
);
236 // UTF conversion functions
237 size_t utf16_to_utf8(char* dst
, char* src
, size_t len
)
242 char buff
[MB_CUR_MAX
];
245 memset(&ps
, 0, sizeof(mbstate_t));
247 while (count
< len
&& *src
!= '\0')
249 c
= *(src
+ 1) << 8 | *src
; // little endian
252 bytes
= wcrtomb(buff
, c
, &ps
);
260 for (i
= 0; i
< bytes
; i
++)
276 size_t utf8_to_utf16(char* dst
, char* src
, size_t len
)
283 tempChar
= (char*) &tempWChar
;
284 memset(&ps
, 0, sizeof(mbstate_t));
286 while (count
< len
- 1 && src
!= '\0')
288 bytes
= mbrtowc(&tempWChar
, src
, MB_CUR_MAX
, &ps
);
317 * SMB Endian aware supporting functions
319 * SMB always uses Intel Little-Endian values, so htons etc are
320 * of little or no use :) ... Thanks M$
323 /*** get unsigned char ***/
324 static __inline__ u8
getUChar(u8
*buffer
,u32 offset
)
326 return (u8
)buffer
[offset
];
329 /*** set unsigned char ***/
330 static __inline__
void setUChar(u8
*buffer
,u32 offset
,u8 value
)
332 buffer
[offset
] = value
;
335 /*** get signed short ***/
336 static __inline__ s16
getShort(u8
*buffer
,u32 offset
)
338 return (s16
)((buffer
[offset
+1]<<8)|(buffer
[offset
]));
341 /*** get unsigned short ***/
342 static __inline__ u16
getUShort(u8
*buffer
,u32 offset
)
344 return (u16
)((buffer
[offset
+1]<<8)|(buffer
[offset
]));
347 /*** set unsigned short ***/
348 static __inline__
void setUShort(u8
*buffer
,u32 offset
,u16 value
)
350 buffer
[offset
] = (value
&0xff);
351 buffer
[offset
+1] = ((value
&0xff00)>>8);
354 /*** get unsigned int ***/
355 static __inline__ u32
getUInt(u8
*buffer
,u32 offset
)
357 return (u32
)((buffer
[offset
+3]<<24)|(buffer
[offset
+2]<<16)|(buffer
[offset
+1]<<8)|buffer
[offset
]);
360 /*** set unsigned int ***/
361 static __inline__
void setUInt(u8
*buffer
,u32 offset
,u32 value
)
363 buffer
[offset
] = (value
&0xff);
364 buffer
[offset
+1] = ((value
&0xff00)>>8);
365 buffer
[offset
+2] = ((value
&0xff0000)>>16);
366 buffer
[offset
+3] = ((value
&0xff000000)>>24);
369 /*** get unsigned long long ***/
370 static __inline__ u64
getULongLong(u8
*buffer
,u32 offset
)
372 return (u64
)(getUInt(buffer
, offset
) | (u64
)getUInt(buffer
, offset
+4) << 32);
375 static __inline__ SMBHANDLE
* __smb_handle_open(SMBCONN smbhndl
)
380 SMB_CHECK_HANDLE(smbhndl
);
382 _CPU_ISR_Disable(level
);
383 handle
= (SMBHANDLE
*)__lwp_objmgr_getnoprotection(&smb_handle_objects
,LWP_OBJMASKID(smbhndl
));
384 _CPU_ISR_Restore(level
);
389 static __inline__
void __smb_handle_free(SMBHANDLE
*handle
)
393 _CPU_ISR_Disable(level
);
394 __lwp_objmgr_close(&smb_handle_objects
,&handle
->object
);
395 __lwp_objmgr_free(&smb_handle_objects
,&handle
->object
);
396 _CPU_ISR_Restore(level
);
399 static void __smb_init()
402 __lwp_objmgr_initinfo(&smb_handle_objects
,SMB_CONNHANDLES_MAX
,sizeof(SMBHANDLE
));
403 __lwp_queue_initialize(&smb_filehandle_queue
,smb_filehandles
,SMB_FILEHANDLES_MAX
,sizeof(struct _smbfile
));
406 static SMBHANDLE
* __smb_allocate_handle()
411 _CPU_ISR_Disable(level
);
412 handle
= (SMBHANDLE
*)__lwp_objmgr_allocate(&smb_handle_objects
);
416 handle
->server_name
= NULL
;
417 handle
->share_name
= NULL
;
418 handle
->sck_server
= INVALID_SOCKET
;
419 handle
->conn_valid
= false;
420 __lwp_objmgr_open(&smb_handle_objects
,&handle
->object
);
422 _CPU_ISR_Restore(level
);
426 static void __smb_free_handle(SMBHANDLE
*handle
)
428 if(handle
->user
) free(handle
->user
);
429 if(handle
->pwd
) free(handle
->pwd
);
430 if(handle
->server_name
) free(handle
->server_name
);
431 if(handle
->share_name
) free(handle
->share_name
);
435 handle
->server_name
= NULL
;
436 handle
->share_name
= NULL
;
437 handle
->sck_server
= INVALID_SOCKET
;
439 __smb_handle_free(handle
);
442 static void MakeSMBHeader(u8 command
,u8 flags
,u16 flags2
,SMBHANDLE
*handle
)
444 u8
*ptr
= handle
->message
.smb
;
445 NBTSMB
*nbt
= &handle
->message
;
446 SMBSESSION
*sess
= &handle
->session
;
448 memset(nbt
,0,sizeof(NBTSMB
));
450 setUInt(ptr
,SMB_OFFSET_PROTO
,SMB_PROTO
);
451 setUChar(ptr
,SMB_OFFSET_CMD
,command
);
452 setUChar(ptr
,SMB_OFFSET_FLAGS
,flags
);
453 setUShort(ptr
,SMB_OFFSET_FLAGS2
,flags2
);
454 setUShort(ptr
,SMB_OFFSET_TID
,sess
->TID
);
455 setUShort(ptr
,SMB_OFFSET_PID
,sess
->PID
);
456 setUShort(ptr
,SMB_OFFSET_UID
,sess
->UID
);
457 setUShort(ptr
,SMB_OFFSET_MID
,sess
->MID
);
459 ptr
[SMB_HEADER_SIZE
] = 0;
465 static void MakeTRANS2Header(u8 subcommand
,SMBHANDLE
*handle
)
467 u8
*ptr
= handle
->message
.smb
;
469 setUChar(ptr
, T2_WORD_CNT
, 15);
470 setUShort(ptr
, T2_MAXPRM_CNT
, 10);
471 setUShort(ptr
, T2_MAXBUFFER
, 16384);
472 setUChar(ptr
, T2_SSETUP_CNT
, 1);
473 setUShort(ptr
, T2_SUB_CMD
, subcommand
);
479 * blocking call with timeout
480 * will return when ALL data has been sent. Number of bytes sent is returned.
481 * OR timeout. Timeout will return -1
482 * OR network error. -ve value will be returned
484 static inline s32
smb_send(s32 s
,const void *data
,s32 size
)
487 s32 ret
, len
= size
, nextsend
;
489 t1
=ticks_to_millisecs(gettime());
494 if(nextsend
>SMB_MAX_NET_WRITE_SIZE
)
495 nextsend
=SMB_MAX_NET_WRITE_SIZE
; //optimized value
497 ret
=net_send(s
,data
,nextsend
,0);
500 t2
=ticks_to_millisecs(gettime());
501 if( (t2
- t1
) > RECV_TIMEOUT
)
503 return -1; // timeout
505 usleep(100); // allow system to perform work. Stabilizes system
510 return ret
; // an error occurred
516 if(len
==0) return size
;
517 t1
=ticks_to_millisecs(gettime());
527 * blocking call with timeout
528 * will return when ANY data has been read from socket. Number of bytes read is returned.
529 * OR timeout. Timeout will return -1
530 * OR network error. -ve value will be returned
532 static s32
smb_recv(s32 s
,void *mem
,s32 len
)
534 s32 ret
,read
,readtotal
=0;
537 t1
=ticks_to_millisecs(gettime());
541 if(read
>SMB_MAX_NET_READ_SIZE
)
542 read
=SMB_MAX_NET_READ_SIZE
; // optimized value
544 ret
=net_recv(s
,mem
+readtotal
,read
,0);
549 if(len
==0) return readtotal
;
553 if(ret
!=-EAGAIN
) return ret
;
554 t2
=ticks_to_millisecs(gettime());
555 if( (t2
- t1
) > RECV_TIMEOUT
) return -1;
562 static void clear_network(s32 s
,u8
*ptr
)
566 t1
=ticks_to_millisecs(gettime());
569 net_recv(s
,ptr
,SMB_MAX_NET_READ_SIZE
,0);
571 t2
=ticks_to_millisecs(gettime());
572 if( (t2
- t1
) > 600) return;
580 * Do very basic checking on the return SMB
581 * Read <readlen> bytes
582 * if <readlen>==0 then read a single SMB packet
583 * discard any non NBT_SESSISON_MSG packets along the way.
585 static s32
SMBCheck(u8 command
,SMBHANDLE
*handle
)
588 u8
*ptr
= handle
->message
.smb
;
589 NBTSMB
*nbt
= &handle
->message
;
593 if(handle
->sck_server
== INVALID_SOCKET
) return SMB_ERROR
;
595 memset(nbt
,0xFF,sizeof(NBTSMB
)); //NBT_SESSISON_MSG is 0x00 so fill mem with 0xFF
597 t1
=ticks_to_millisecs(gettime());
599 /*keep going till we get a NBT session message*/
601 ret
=smb_recv(handle
->sck_server
, (u8
*)nbt
, 4);
602 if(ret
!=4) goto failed
;
604 if(nbt
->msg
!=NBT_SESSISON_MSG
)
606 readlen
=(u32
)((nbt
->length_high
<<16)|nbt
->length
);
609 t1
=ticks_to_millisecs(gettime());
610 smb_recv(handle
->sck_server
, ptr
, readlen
); //clear unexpected NBT message
613 t2
=ticks_to_millisecs(gettime());
614 if( (t2
- t1
) > RECV_TIMEOUT
* 2) goto failed
;
616 } while(nbt
->msg
!=NBT_SESSISON_MSG
);
618 /* obtain required length from NBT header if readlen==0*/
619 readlen
=(u32
)((nbt
->length_high
<<16)|nbt
->length
);
621 // Get server message block
622 ret
=smb_recv(handle
->sck_server
, ptr
, readlen
);
623 if(readlen
!=ret
) goto failed
;
625 /*** Do basic SMB Header checks ***/
626 ret
= getUInt(ptr
,SMB_OFFSET_PROTO
);
627 if(ret
!=SMB_PROTO
) goto failed
;
629 ret
= getUChar(ptr
, SMB_OFFSET_CMD
);
630 if(ret
!=command
) goto failed
;
632 ret
= getUInt(ptr
,SMB_OFFSET_NTSTATUS
);
637 clear_network(handle
->sck_server
,ptr
);
644 * Setup the SMB session, including authentication with the
645 * magic 'NTLM Response'
647 static s32
SMB_SetupAndX(SMBHANDLE
*handle
)
652 u8
*ptr
= handle
->message
.smb
;
653 SMBSESSION
*sess
= &handle
->session
;
654 char pwd
[30], ntRespData
[24];
656 if(handle
->sck_server
== INVALID_SOCKET
) return SMB_ERROR
;
658 MakeSMBHeader(SMB_SETUP_ANDX
,CIFS_FLAGS1
,handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
659 pos
= SMB_HEADER_SIZE
;
661 setUChar(ptr
,pos
,13);
662 pos
++; /*** Word Count ***/
663 setUChar(ptr
,pos
,0xff);
664 pos
++; /*** Next AndX ***/
666 pos
++; /*** Reserved ***/
667 pos
+= 2; /*** Next AndX Offset ***/
668 setUShort(ptr
,pos
,sess
->MaxBuffer
);
670 setUShort(ptr
,pos
,sess
->MaxMpx
);
672 setUShort(ptr
,pos
,sess
->MaxVCS
);
674 setUInt(ptr
,pos
,sess
->sKey
);
676 setUShort(ptr
,pos
,24); /*** Password length (case-insensitive) ***/
678 setUShort(ptr
,pos
,24); /*** Password length (case-sensitive) ***/
681 pos
+= 4; /*** Reserved ***/
682 setUInt(ptr
,pos
,sess
->capabilities
);
683 pos
+= 4; /*** Capabilities ***/
685 pos
+= 2; /*** Byte count ***/
687 /*** The magic 'NTLM Response' ***/
688 strcpy(pwd
, handle
->pwd
);
689 if (sess
->challengeUsed
)
690 ntlm_smb_nt_encrypt((const char *) pwd
, (const u8
*) sess
->challenge
, (u8
*) ntRespData
);
692 /*** Build information ***/
693 memset(&ptr
[pos
],0,24);
695 memcpy(&ptr
[pos
],ntRespData
,24);
699 strcpy(pwd
, handle
->user
);
700 for(i
=0;i
<strlen(pwd
);i
++)
701 pwd
[i
] = toupper((int)pwd
[i
]);
704 pos
+= utf8_to_utf16((char*)&ptr
[pos
],pwd
,SMB_MAXPATH
-2);
709 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
710 pos
+= strlen(pwd
)+1;
713 /*** Primary Domain ***/
714 if(handle
->user
[0]=='\0') sess
->p_domain
[0] = '\0';
717 pos
+= utf8_to_utf16((char*)&ptr
[pos
],(char*)sess
->p_domain
,SMB_MAXPATH
-2);
722 memcpy(&ptr
[pos
],sess
->p_domain
,strlen((const char*)sess
->p_domain
));
723 pos
+= strlen((const char*)sess
->p_domain
)+1;
727 strcpy(pwd
,"Unix (libOGC)");
730 pos
+= utf8_to_utf16((char*)&ptr
[pos
],pwd
,SMB_MAXPATH
-2);
735 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
736 pos
+= strlen(pwd
)+1;
739 /*** Native LAN Manager ***/
740 strcpy(pwd
,"Nintendo Wii");
743 pos
+= utf8_to_utf16((char*)&ptr
[pos
],pwd
,SMB_MAXPATH
-2);
748 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
749 pos
+= strlen (pwd
)+1;
752 /*** Update byte count ***/
753 setUShort(ptr
,bcpos
,((pos
-bcpos
)-2));
755 handle
->message
.msg
= NBT_SESSISON_MSG
;
756 handle
->message
.length
= htons (pos
);
759 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
760 if(ret
<=0) return SMB_ERROR
;
762 if((ret
=SMBCheck(SMB_SETUP_ANDX
,handle
))==SMB_SUCCESS
) {
763 /*** Collect UID ***/
764 sess
->UID
= getUShort(handle
->message
.smb
,SMB_OFFSET_UID
);
773 * Finally, net_connect to the remote share
775 static s32
SMB_TreeAndX(SMBHANDLE
*handle
)
779 u8
*ptr
= handle
->message
.smb
;
780 SMBSESSION
*sess
= &handle
->session
;
782 if(handle
->sck_server
== INVALID_SOCKET
) return SMB_ERROR
;
784 MakeSMBHeader(SMB_TREEC_ANDX
,CIFS_FLAGS1
,handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
785 pos
= SMB_HEADER_SIZE
;
788 pos
++; /*** Word Count ***/
789 setUChar(ptr
,pos
,0xff);
790 pos
++; /*** Next AndX ***/
791 pos
++; /*** Reserved ***/
792 pos
+= 2; /*** Next AndX Offset ***/
793 pos
+= 2; /*** Flags ***/
794 setUShort(ptr
,pos
,1);
795 pos
+= 2; /*** Password Length ***/
798 pos
++; /*** NULL Password ***/
800 /*** Build server share path ***/
801 strcpy ((char*)path
, "\\\\");
802 strcat ((char*)path
, handle
->server_name
);
803 strcat ((char*)path
, "\\");
804 strcat ((char*)path
, handle
->share_name
);
806 for(ret
=0;ret
<strlen((const char*)path
);ret
++)
807 path
[ret
] = (char)toupper((int)path
[ret
]);
811 pos
+= utf8_to_utf16((char*)&ptr
[pos
],path
,SMB_MAXPATH
-2);
816 memcpy(&ptr
[pos
],path
,strlen((const char*)path
));
817 pos
+= strlen((const char*)path
)+1;
821 strcpy((char*)path
,"?????");
822 memcpy(&ptr
[pos
],path
,strlen((const char*)path
));
823 pos
+= strlen((const char*)path
)+1;
826 /*** Update byte count ***/
827 setUShort(ptr
,bcpos
,(pos
-bcpos
)-2);
829 handle
->message
.msg
= NBT_SESSISON_MSG
;
830 handle
->message
.length
= htons (pos
);
833 ret
= smb_send(handle
->sck_server
,(char *)&handle
->message
,pos
);
834 if(ret
<=0) return SMB_ERROR
;
836 if((ret
=SMBCheck(SMB_TREEC_ANDX
,handle
))==SMB_SUCCESS
) {
837 /*** Collect Tree ID ***/
838 sess
->TID
= getUShort(handle
->message
.smb
,SMB_OFFSET_TID
);
845 * SMB_NegotiateProtocol
847 * The only protocol we admit to is 'NT LM 0.12'
849 static s32
SMB_NegotiateProtocol(const char *dialects
[],int dialectc
,SMBHANDLE
*handle
)
859 if(!handle
|| !dialects
|| dialectc
<=0)
862 if(handle
->sck_server
== INVALID_SOCKET
) return SMB_ERROR
;
864 /*** Clear session variables ***/
865 sess
= &handle
->session
;
866 memset(sess
,0,sizeof(SMBSESSION
));
869 sess
->capabilities
= 0;
871 MakeSMBHeader(SMB_NEG_PROTOCOL
,CIFS_FLAGS1
,handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
873 pos
= SMB_HEADER_SIZE
+3;
874 ptr
= handle
->message
.smb
;
875 for(i
=0,bcnt
=0;i
<dialectc
;i
++) {
876 len
= strlen(dialects
[i
])+1;
878 memcpy(&ptr
[pos
],dialects
[i
],len
);
882 /*** Update byte count ***/
883 setUShort(ptr
,(SMB_HEADER_SIZE
+1),bcnt
);
885 /*** Set NBT information ***/
886 handle
->message
.msg
= NBT_SESSISON_MSG
;
887 handle
->message
.length
= htons(pos
);
890 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
891 if(ret
<=0) return SMB_ERROR
;
893 /*** Check response ***/
894 if((ret
=SMBCheck(SMB_NEG_PROTOCOL
,handle
))==SMB_SUCCESS
)
896 pos
= SMB_HEADER_SIZE
;
897 ptr
= handle
->message
.smb
;
899 /*** Collect information ***/
900 if(getUChar(ptr
,pos
)!=17) return SMB_PROTO_FAIL
; // UCHAR WordCount; Count of parameter words = 17
903 if(getUShort(ptr
,pos
)!=0) return SMB_PROTO_FAIL
; // USHORT DialectIndex; Index of selected dialect - should always be 0 since we only supplied 1!
906 if(getUChar(ptr
,pos
) & 1)
908 // user level security
909 sess
->securityLevel
= 1;
913 // share level security - can we skip SetupAndX? If so, we would need to specify the password in TreeAndX
914 sess
->securityLevel
= 0;
918 sess
->MaxMpx
= getUShort(ptr
, pos
); //USHORT MaxMpxCount; Max pending outstanding requests
921 sess
->MaxVCS
= getUShort(ptr
, pos
); //USHORT MaxNumberVcs; Max VCs between client and server
924 serverMaxBuffer
= getUInt(ptr
, pos
); //ULONG MaxBufferSize; Max transmit buffer size
927 if(serverMaxBuffer
>SMB_MAX_TRANSMIT_SIZE
)
928 sess
->MaxBuffer
= SMB_MAX_TRANSMIT_SIZE
;
930 sess
->MaxBuffer
= serverMaxBuffer
;
932 pos
+= 4; //ULONG MaxRawSize; Maximum raw buffer size
933 sess
->sKey
= getUInt(ptr
,pos
); pos
+= 4;
934 u32 servcap
= getUInt(ptr
,pos
); pos
+= 4; //ULONG Capabilities; Server capabilities
935 pos
+= 4; //ULONG SystemTimeLow; System (UTC) time of the server (low).
936 pos
+= 4; //ULONG SystemTimeHigh; System (UTC) time of the server (high).
937 sess
->timeOffset
= getShort(ptr
,pos
) * 600000000LL; pos
+= 2; //SHORT ServerTimeZone; Time zone of server (minutes from UTC)
939 //UCHAR EncryptionKeyLength - 0 or 8
940 if(getUChar(ptr
,pos
)!=8)
942 if (getUChar(ptr
,pos
)!=0)
944 return SMB_BAD_KEYLEN
;
948 // Challenge key not used
949 sess
->challengeUsed
= false;
954 sess
->challengeUsed
= true;
958 bytecount
= getUShort(ptr
,pos
);
960 if (sess
->challengeUsed
)
962 /*** Copy challenge key ***/
964 memcpy(&sess
->challenge
,&ptr
[pos
],8);
967 /*** Primary domain ***/
970 while(ptr
[pos
+j
]!=0) {
971 sess
->p_domain
[i
] = ptr
[pos
+j
];
975 sess
->p_domain
[i
] = '\0';
977 // setup capabilities
978 //if(servcap & CAP_LARGE_FILES)
979 // sess->capabilities |= CAP_LARGE_FILES;
981 if(servcap
& CAP_UNICODE
)
983 sess
->capabilities
|= CAP_UNICODE
;
984 handle
->unicode
= true;
992 static s32
do_netconnect(SMBHANDLE
*handle
)
999 handle
->sck_server
= INVALID_SOCKET
;
1000 /*** Create the global net_socket ***/
1001 sock
= net_socket(AF_INET
, SOCK_STREAM
, IPPROTO_IP
);
1002 if(sock
==INVALID_SOCKET
) return -1;
1004 // Switch off Nagle with TCP_NODELAY
1006 net_setsockopt(sock
,IPPROTO_TCP
,TCP_NODELAY
,&nodelay
,sizeof(nodelay
));
1008 // create non blocking socket
1009 ret
= net_fcntl(sock
, F_GETFL
, 0);
1016 ret
= net_fcntl(sock
, F_SETFL
, ret
| IOS_O_NONBLOCK
);
1023 t1
=ticks_to_millisecs(gettime());
1026 ret
= net_connect(sock
,(struct sockaddr
*)&handle
->server_addr
,sizeof(handle
->server_addr
));
1027 if(ret
==-EISCONN
) break;
1028 t2
=ticks_to_millisecs(gettime());
1030 if((t2
-t1
) > CONN_TIMEOUT
) break; // usually not more than 90ms
1039 handle
->sck_server
= sock
;
1043 static s32
do_smbconnect(SMBHANDLE
*handle
)
1047 if(handle
->sck_server
== INVALID_SOCKET
) return -1;
1049 ret
= SMB_NegotiateProtocol(smb_dialects
,smb_dialectcnt
,handle
);
1050 if(ret
!=SMB_SUCCESS
)
1052 net_close(handle
->sck_server
);
1053 handle
->sck_server
= INVALID_SOCKET
;
1057 ret
= SMB_SetupAndX(handle
);
1058 if(ret
!=SMB_SUCCESS
)
1060 net_close(handle
->sck_server
);
1061 handle
->sck_server
= INVALID_SOCKET
;
1065 ret
= SMB_TreeAndX(handle
);
1066 if(ret
!=SMB_SUCCESS
)
1068 net_close(handle
->sck_server
);
1069 handle
->sck_server
= INVALID_SOCKET
;
1073 handle
->conn_valid
= true;
1077 /****************************************************************************
1078 * Create an NBT SESSION REQUEST message.
1079 ****************************************************************************/
1080 static int MakeSessReq(unsigned char *bufr
, unsigned char *Called
, unsigned char *Calling
)
1082 // Write the header.
1086 bufr
[3] = 68; // 2x34 bytes in length.
1088 // Copy the Called and Calling names into the buffer.
1089 (void) memcpy(&bufr
[4], Called
, 34);
1090 (void) memcpy(&bufr
[38], Calling
, 34);
1092 // Return the total message length.
1096 static unsigned char *L1_Encode(unsigned char *dst
, const unsigned char *name
,
1097 const unsigned char pad
, const unsigned char sfx
)
1103 while (('\0' != name
[i
]) && (i
< 15))
1105 k
= toupper(name
[i
++]);
1106 dst
[j
++] = 'A' + ((k
& 0xF0) >> 4);
1107 dst
[j
++] = 'A' + (k
& 0x0F);
1110 i
= 'A' + ((pad
& 0xF0) >> 4);
1111 k
= 'A' + (pad
& 0x0F);
1118 dst
[30] = 'A' + ((sfx
& 0xF0) >> 4);
1119 dst
[31] = 'A' + (sfx
& 0x0F);
1125 static int L2_Encode(unsigned char *dst
, const unsigned char *name
,
1126 const unsigned char pad
, const unsigned char sfx
,
1127 const unsigned char *scope
)
1133 if (NULL
== L1_Encode(&dst
[1], name
, pad
, sfx
))
1143 for (i
= 0, j
= (lenpos
+ 1); ('.' != scope
[i
]) && ('\0'
1144 != scope
[i
]); i
++, j
++)
1145 dst
[j
] = toupper(scope
[i
]);
1147 dst
[lenpos
] = (unsigned char) i
;
1150 } while ('.' == *(scope
++));
1155 return (lenpos
+ 1);
1158 /****************************************************************************
1159 * Send an NBT SESSION REQUEST over the TCP connection, then wait for a reply.
1160 ****************************************************************************/
1161 static s32
SMB_RequestNBTSession(SMBHANDLE
*handle
)
1163 unsigned char Called
[34];
1164 unsigned char Calling
[34];
1165 unsigned char bufr
[128];
1168 if(handle
->sck_server
== INVALID_SOCKET
) return -1;
1170 L2_Encode(Called
, (const unsigned char*) "*SMBSERVER", 0x20, 0x20,
1171 (const unsigned char*) "");
1172 L2_Encode(Calling
, (const unsigned char*) "SMBCLIENT", 0x20, 0x00,
1173 (const unsigned char*) "");
1175 // Create the NBT Session Request message.
1176 result
= MakeSessReq(bufr
, Called
, Calling
);
1178 //Send the NBT Session Request message.
1179 result
= smb_send(handle
->sck_server
, bufr
, result
);
1182 // Error sending Session Request message
1186 // Now wait for and handle the reply (2 seconds).
1187 result
= smb_recv(handle
->sck_server
, bufr
, 128);
1190 // Timeout waiting for NBT Session Response
1197 // Positive Session Response
1201 // Negative Session Response
1205 // Retarget Session Response
1209 // Unexpected Session Response
1214 /****************************************************************************
1215 * Primary setup, logon and connection all in one :)
1216 ****************************************************************************/
1217 s32
SMB_Connect(SMBCONN
*smbhndl
, const char *user
, const char *password
, const char *share
, const char *server
)
1223 *smbhndl
= SMB_HANDLE_NULL
;
1225 if(!user
|| !password
|| !share
|| !server
||
1226 strlen(user
) > 20 || strlen(password
) > 14 ||
1227 strlen(share
) > 80 || strlen(server
) > 80)
1229 return SMB_BAD_LOGINDATA
;
1235 _CPU_ISR_Disable(level
);
1237 _CPU_ISR_Restore(level
);
1240 handle
= __smb_allocate_handle();
1241 if(!handle
) return SMB_ERROR
;
1243 handle
->user
= strdup(user
);
1244 handle
->pwd
= strdup(password
);
1245 handle
->server_name
= strdup(server
);
1246 handle
->share_name
= strdup(share
);
1247 handle
->server_addr
.sin_family
= AF_INET
;
1248 handle
->server_addr
.sin_port
= htons(445);
1249 handle
->unicode
= false;
1251 if(strlen(server
) < 16 && inet_aton(server
, &val
))
1253 handle
->server_addr
.sin_addr
.s_addr
= val
.s_addr
;
1255 else // might be a hostname
1258 struct hostent
*hp
= net_gethostbyname(server
);
1259 if (!hp
|| !(hp
->h_addrtype
== PF_INET
))
1260 ret
= SMB_BAD_LOGINDATA
;
1262 memcpy((char *)&handle
->server_addr
.sin_addr
.s_addr
, hp
->h_addr_list
[0], hp
->h_length
);
1264 __smb_free_handle(handle
);
1269 *smbhndl
=(SMBCONN
)(LWP_OBJMASKTYPE(SMB_OBJTYPE_HANDLE
)|LWP_OBJMASKID(handle
->object
.id
));
1273 ret
= do_netconnect(handle
);
1274 if(ret
==0) ret
= do_smbconnect(handle
);
1279 handle
->server_addr
.sin_port
= htons(139);
1280 ret
= do_netconnect(handle
);
1281 if(ret
==0) ret
= SMB_RequestNBTSession(handle
);
1282 if(ret
==0) ret
= do_smbconnect(handle
);
1287 __smb_free_handle(handle
);
1294 /****************************************************************************
1296 ****************************************************************************/
1297 void SMB_Close(SMBCONN smbhndl
)
1299 SMBHANDLE
*handle
= __smb_handle_open(smbhndl
);
1302 if(handle
->sck_server
!=INVALID_SOCKET
)
1303 net_close(handle
->sck_server
);
1305 __smb_free_handle(handle
);
1308 s32
SMB_Reconnect(SMBCONN
*_smbhndl
, bool test_conn
)
1310 s32 ret
= SMB_SUCCESS
;
1311 SMBCONN smbhndl
= *_smbhndl
;
1312 SMBHANDLE
*handle
= __smb_handle_open(smbhndl
);
1314 return SMB_ERROR
; // we have no handle, so we can't reconnect
1316 if(handle
->conn_valid
&& test_conn
)
1319 if(SMB_PathInfo("\\", &dentry
, smbhndl
)==SMB_SUCCESS
) return SMB_SUCCESS
; // no need to reconnect
1320 handle
->conn_valid
= false; // else connection is invalid
1322 if(!handle
->conn_valid
)
1324 // shut down connection
1325 if(handle
->sck_server
!=INVALID_SOCKET
)
1327 net_close(handle
->sck_server
);
1328 handle
->sck_server
= INVALID_SOCKET
;
1332 if(handle
->server_addr
.sin_port
> 0)
1334 ret
= do_netconnect(handle
);
1335 if(ret
==0 && handle
->server_addr
.sin_port
== htons(139))
1336 ret
= SMB_RequestNBTSession(handle
);
1338 ret
= do_smbconnect(handle
);
1340 else // initial connection
1342 handle
->server_addr
.sin_port
= htons(445);
1343 ret
= do_netconnect(handle
);
1344 if(ret
==0) ret
= do_smbconnect(handle
);
1349 handle
->server_addr
.sin_port
= htons(139);
1350 ret
= do_netconnect(handle
);
1351 if(ret
==0) ret
= SMB_RequestNBTSession(handle
);
1352 if(ret
==0) ret
= do_smbconnect(handle
);
1356 handle
->server_addr
.sin_port
= 0;
1362 SMBFILE
SMB_OpenFile(const char *filename
, u16 access
, u16 creation
,SMBCONN smbhndl
)
1367 struct _smbfile
*fid
= NULL
;
1371 if(filename
== NULL
)
1374 if(SMB_Reconnect(&smbhndl
,true)!=SMB_SUCCESS
) return NULL
;
1376 handle
= __smb_handle_open(smbhndl
);
1377 if(!handle
) return NULL
;
1379 MakeSMBHeader(SMB_OPEN_ANDX
,CIFS_FLAGS1
,handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
1381 pos
= SMB_HEADER_SIZE
;
1382 ptr
= handle
->message
.smb
;
1383 setUChar(ptr
, pos
, 15);
1384 pos
++; /*** Word Count ***/
1385 setUChar(ptr
, pos
, 0xff);
1386 pos
++; /*** AndXCommand 0xFF = None ***/
1387 setUChar(ptr
, pos
, 0);
1388 pos
++; /*** AndX Reserved must be 0 ***/
1389 pos
+= 2; /*** Next AndX Offset to next Command ***/
1390 pos
+= 2; /*** Flags ***/
1391 setUShort(ptr
, pos
, access
);
1392 pos
+= 2; /*** Access mode ***/
1393 setUShort(ptr
, pos
, 0x6);
1394 pos
+= 2; /*** Type of file ***/
1395 pos
+= 2; /*** File Attributes ***/
1396 pos
+= 4; /*** File time - don't care - let server decide ***/
1397 setUShort(ptr
, pos
, creation
);
1398 pos
+= 2; /*** Creation flags ***/
1399 pos
+= 4; /*** Allocation size ***/
1400 setUInt(ptr
, pos
, 0);
1401 pos
+= 4; /*** Reserved[0] must be 0 ***/
1402 setUInt(ptr
, pos
, 0);
1403 pos
+= 4; /*** Reserved[1] must be 0 ***/
1404 pos
+= 2; /*** Byte Count ***/
1406 setUChar(ptr
, pos
, 0x04); /** Bufferformat **/
1410 if (filename
[0] != '\\')
1411 strcpy(realfile
,"\\");
1412 strcat(realfile
,filename
);
1416 pos
+= utf8_to_utf16((char*)&ptr
[pos
],realfile
,SMB_MAXPATH
-2);
1421 memcpy(&ptr
[pos
],realfile
,strlen(realfile
));
1422 pos
+= strlen(realfile
)+1;
1425 setUShort(ptr
,(bpos
-2),(pos
-bpos
));
1427 handle
->message
.msg
= NBT_SESSISON_MSG
;
1428 handle
->message
.length
= htons(pos
);
1431 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1432 if(ret
<0) goto failed
;
1434 if(SMBCheck(SMB_OPEN_ANDX
,handle
)==SMB_SUCCESS
) {
1435 /*** Check file handle ***/
1436 fid
= (struct _smbfile
*)__lwp_queue_get(&smb_filehandle_queue
);
1438 fid
->conn
= smbhndl
;
1439 fid
->sfid
= getUShort(handle
->message
.smb
,(SMB_HEADER_SIZE
+5));
1442 return (SMBFILE
)fid
;
1445 handle
->conn_valid
= false;
1452 void SMB_CloseFile(SMBFILE sfid
)
1457 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
1461 handle
= __smb_handle_open(fid
->conn
);
1464 MakeSMBHeader(SMB_CLOSE
,CIFS_FLAGS1
,handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
1466 pos
= SMB_HEADER_SIZE
;
1467 ptr
= handle
->message
.smb
;
1468 setUChar(ptr
, pos
, 3);
1469 pos
++; /** Word Count **/
1470 setUShort(ptr
, pos
, fid
->sfid
);
1472 setUInt(ptr
, pos
, 0xffffffff);
1473 pos
+= 4; /*** Last Write ***/
1474 pos
+= 2; /*** Byte Count ***/
1476 handle
->message
.msg
= NBT_SESSISON_MSG
;
1477 handle
->message
.length
= htons(pos
);
1480 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1481 if(ret
<0) handle
->conn_valid
= false;
1482 else SMBCheck(SMB_CLOSE
,handle
);
1483 __lwp_queue_append(&smb_filehandle_queue
,&fid
->node
);
1487 * SMB_CreateDirectory
1489 s32
SMB_CreateDirectory(const char *dirname
, SMBCONN smbhndl
)
1500 if(SMB_Reconnect(&smbhndl
,true)!=SMB_SUCCESS
) return -1;
1502 handle
= __smb_handle_open(smbhndl
);
1503 if(!handle
) return -1;
1505 MakeSMBHeader(SMB_COM_CREATE_DIRECTORY
,CIFS_FLAGS1
, handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
1507 pos
= SMB_HEADER_SIZE
;
1508 ptr
= handle
->message
.smb
;
1509 setUChar(ptr
, pos
, 0);
1510 pos
++; /*** Word Count ***/
1511 pos
+= 2; /*** Byte Count ***/
1513 setUChar(ptr
, pos
, 0x04); /*** Buffer format ***/
1517 if (dirname
[0] != '\\')
1518 strcpy(realfile
,"\\");
1519 strcat(realfile
,dirname
);
1523 pos
+= utf8_to_utf16((char*)&ptr
[pos
],realfile
,SMB_MAXPATH
-2);
1528 memcpy(&ptr
[pos
],realfile
,strlen(realfile
));
1529 pos
+= strlen(realfile
)+1;
1532 setUShort(ptr
,(bpos
-2),(pos
-bpos
));
1534 handle
->message
.msg
= NBT_SESSISON_MSG
;
1535 handle
->message
.length
= htons(pos
);
1538 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1539 if(ret
< 0) goto failed
;
1541 ret
= SMBCheck(SMB_COM_CREATE_DIRECTORY
,handle
);
1550 * SMB_DeleteDirectory
1552 s32
SMB_DeleteDirectory(const char *dirname
, SMBCONN smbhndl
)
1563 if(SMB_Reconnect(&smbhndl
,true)!=SMB_SUCCESS
) return -1;
1565 handle
= __smb_handle_open(smbhndl
);
1566 if(!handle
) return -1;
1568 MakeSMBHeader(SMB_COM_DELETE_DIRECTORY
,CIFS_FLAGS1
, handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
1570 pos
= SMB_HEADER_SIZE
;
1571 ptr
= handle
->message
.smb
;
1572 setUChar(ptr
, pos
, 0);
1573 pos
++; /*** Word Count ***/
1574 pos
+= 2; /*** Byte Count ***/
1576 setUChar(ptr
, pos
, 0x04); /** Bufferformat **/
1580 if (dirname
[0] != '\\')
1581 strcpy(realfile
,"\\");
1582 strcat(realfile
,dirname
);
1586 pos
+= utf8_to_utf16((char*)&ptr
[pos
],realfile
,SMB_MAXPATH
-2);
1591 memcpy(&ptr
[pos
],realfile
,strlen(realfile
));
1592 pos
+= strlen(realfile
)+1;
1595 setUShort(ptr
,(bpos
-2),(pos
-bpos
));
1597 handle
->message
.msg
= NBT_SESSISON_MSG
;
1598 handle
->message
.length
= htons(pos
);
1601 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1602 if(ret
< 0) goto failed
;
1604 ret
= SMBCheck(SMB_COM_DELETE_DIRECTORY
,handle
);
1615 s32
SMB_DeleteFile(const char *filename
, SMBCONN smbhndl
)
1623 if(filename
== NULL
)
1626 if(SMB_Reconnect(&smbhndl
,true)!=SMB_SUCCESS
) return -1;
1628 handle
= __smb_handle_open(smbhndl
);
1629 if(!handle
) return -1;
1631 MakeSMBHeader(SMB_COM_DELETE
,CIFS_FLAGS1
, handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
1633 pos
= SMB_HEADER_SIZE
;
1634 ptr
= handle
->message
.smb
;
1635 setUChar(ptr
, pos
, 1);
1636 pos
++; /*** Word Count ***/
1637 setUShort(ptr
, pos
, SMB_SRCH_HIDDEN
);
1638 pos
+= 2; /*** SearchAttributes ***/
1639 pos
+= 2; /*** Byte Count ***/
1641 setUChar(ptr
, pos
, 0x04); /** Bufferformat **/
1645 if (filename
[0] != '\\')
1646 strcpy(realfile
,"\\");
1647 strcat(realfile
,filename
);
1651 pos
+= utf8_to_utf16((char*)&ptr
[pos
],realfile
,SMB_MAXPATH
-2);
1656 memcpy(&ptr
[pos
],realfile
,strlen(realfile
));
1657 pos
+= strlen(realfile
)+1;
1660 setUShort(ptr
,(bpos
-2),(pos
-bpos
));
1662 handle
->message
.msg
= NBT_SESSISON_MSG
;
1663 handle
->message
.length
= htons(pos
);
1666 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1667 if(ret
< 0) goto failed
;
1669 ret
= SMBCheck(SMB_COM_DELETE
,handle
);
1680 s32
SMB_Rename(const char *filename
, const char * newfilename
, SMBCONN smbhndl
)
1687 char newrealfile
[512];
1689 if(filename
== NULL
|| newfilename
== NULL
)
1692 if(SMB_Reconnect(&smbhndl
,true)!=SMB_SUCCESS
)
1695 handle
= __smb_handle_open(smbhndl
);
1696 if(!handle
) return -1;
1698 MakeSMBHeader(SMB_COM_RENAME
,CIFS_FLAGS1
, handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
1700 pos
= SMB_HEADER_SIZE
;
1701 ptr
= handle
->message
.smb
;
1702 setUChar(ptr
, pos
, 1);
1703 pos
++; /*** Word Count ***/
1704 setUShort(ptr
, pos
, SMB_SRCH_HIDDEN
);
1705 pos
+= 2; /*** SearchAttributes ***/
1706 pos
+= 2; /*** Byte Count ***/
1708 setUChar(ptr
, pos
, 0x04); /** Bufferformat **/
1712 if (filename
[0] != '\\')
1713 strcpy(realfile
,"\\");
1714 strcat(realfile
,filename
);
1718 pos
+= utf8_to_utf16((char*)&ptr
[pos
],realfile
,SMB_MAXPATH
-2);
1723 memcpy(&ptr
[pos
],realfile
,strlen(realfile
));
1724 pos
+= strlen(realfile
)+1;
1728 setUChar(ptr
, pos
, 0x04); /** Bufferformat **/
1731 newrealfile
[0]='\0';
1732 if (newfilename
[0] != '\\')
1733 strcpy(newrealfile
,"\\");
1734 strcat(newrealfile
,newfilename
);
1738 pos
+= utf8_to_utf16((char*)&ptr
[pos
],newrealfile
,SMB_MAXPATH
-2);
1743 memcpy(&ptr
[pos
],newrealfile
,strlen(newrealfile
));
1744 pos
+= strlen(newrealfile
)+1;
1747 setUShort(ptr
,(bpos
-2),(pos
-bpos
));
1749 handle
->message
.msg
= NBT_SESSISON_MSG
;
1750 handle
->message
.length
= htons(pos
);
1753 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1754 if(ret
< 0) goto failed
;
1756 ret
= SMBCheck(SMB_COM_RENAME
,handle
);
1765 * SMB_DiskInformation
1767 s32
SMB_DiskInformation(struct statvfs
*buf
, SMBCONN smbhndl
)
1771 u16 TotalUnits
, BlocksPerUnit
, BlockSize
, FreeUnits
;
1775 if(SMB_Reconnect(&smbhndl
,true)!=SMB_SUCCESS
) return -1;
1777 handle
= __smb_handle_open(smbhndl
);
1778 if(!handle
) return -1;
1780 MakeSMBHeader(SMB_COM_QUERY_INFORMATION_DISK
,CIFS_FLAGS1
, handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
1782 pos
= SMB_HEADER_SIZE
;
1783 ptr
= handle
->message
.smb
;
1784 setUChar(ptr
, pos
, 0);
1785 pos
++; /*** Word Count ***/
1786 setUShort(ptr
, pos
, 0);
1787 pos
+= 2; /*** Byte Count ***/
1790 handle
->message
.msg
= NBT_SESSISON_MSG
;
1791 handle
->message
.length
= htons(pos
);
1794 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1795 if(ret
< 0) goto failed
;
1797 if((ret
=SMBCheck(SMB_COM_QUERY_INFORMATION_DISK
, handle
))==SMB_SUCCESS
)
1799 ptr
= handle
->message
.smb
;
1800 /** Read the received data ***/
1804 TotalUnits
= getUShort(ptr
,(SMB_HEADER_SIZE
+recv_pos
));
1806 /** BlocksPerUnit **/
1807 BlocksPerUnit
= getUShort(ptr
,(SMB_HEADER_SIZE
+recv_pos
));
1810 BlockSize
= getUShort(ptr
,(SMB_HEADER_SIZE
+recv_pos
));
1813 FreeUnits
= getUShort(ptr
,(SMB_HEADER_SIZE
+recv_pos
));
1816 buf
->f_bsize
= (unsigned long) BlockSize
; // File system block size.
1817 buf
->f_frsize
= (unsigned long) BlockSize
; // Fundamental file system block size.
1818 buf
->f_blocks
= (fsblkcnt_t
) (TotalUnits
*BlocksPerUnit
); // Total number of blocks on file system in units of f_frsize.
1819 buf
->f_bfree
= (fsblkcnt_t
) (FreeUnits
*BlocksPerUnit
); // Total number of free blocks.
1820 buf
->f_bavail
= 0; // Number of free blocks available to non-privileged process.
1821 buf
->f_files
= 0; // Total number of file serial numbers.
1822 buf
->f_ffree
= 0; // Total number of free file serial numbers.
1823 buf
->f_favail
= 0; // Number of file serial numbers available to non-privileged process.
1824 buf
->f_fsid
= 0; // File system ID. 32bit ioType value
1825 buf
->f_flag
= 0; // Bit mask of f_flag values.
1826 buf
->f_namemax
= SMB_MAXPATH
; // Maximum filename length.
1832 handle
->conn_valid
= false;
1839 s32
SMB_ReadFile(char *buffer
, size_t size
, off_t offset
, SMBFILE sfid
)
1845 size_t totalread
=0,nextread
;
1846 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
1850 // Check for invalid size
1851 if(size
== 0) return -1;
1853 handle
= __smb_handle_open(fid
->conn
);
1854 if(!handle
) return -1;
1856 while(totalread
< size
)
1858 if((size
-totalread
) > SMB_MAX_TRANSMIT_SIZE
)
1859 nextread
=SMB_MAX_TRANSMIT_SIZE
;
1861 nextread
=size
-totalread
;
1863 MakeSMBHeader(SMB_READ_ANDX
,CIFS_FLAGS1
,handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
1865 pos
= SMB_HEADER_SIZE
;
1866 ptr
= handle
->message
.smb
;
1867 setUChar(ptr
, pos
, 12);
1868 pos
++; /*** Word count ***/
1869 setUChar(ptr
, pos
, 0xff);
1871 setUChar(ptr
, pos
, 0);
1872 pos
++; /*** Reserved must be 0 ***/
1873 pos
+= 2; /*** Next AndX Offset ***/
1874 setUShort(ptr
, pos
, fid
->sfid
);
1875 pos
+= 2; /*** FID ***/
1876 setUInt(ptr
, pos
, (offset
+totalread
) & 0xffffffff);
1877 pos
+= 4; /*** Offset ***/
1879 setUShort(ptr
, pos
, nextread
& 0xffff);
1881 setUShort(ptr
, pos
, nextread
& 0xffff);
1883 setUInt(ptr
, pos
, 0);
1884 pos
+= 4; /*** Reserved must be 0 ***/
1885 setUShort(ptr
, pos
, nextread
& 0xffff);
1886 pos
+= 2; /*** Remaining ***/
1887 setUInt(ptr
, pos
, (offset
+totalread
) >> 32); // offset high
1888 pos
+= 4; /*** OffsetHIGH ***/
1889 pos
+= 2; /*** Byte count ***/
1891 handle
->message
.msg
= NBT_SESSISON_MSG
;
1892 handle
->message
.length
= htons(pos
);
1896 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
, pos
);
1897 if(ret
<0) goto failed
;
1900 if(SMBCheck(SMB_READ_ANDX
,handle
)!=SMB_SUCCESS
) goto failed
;
1902 ptr
= handle
->message
.smb
;
1903 // Retrieve data length for this packet
1904 length
= getUShort(ptr
,(SMB_HEADER_SIZE
+11));
1909 // Retrieve offset to data
1910 ofs
= getUShort(ptr
,(SMB_HEADER_SIZE
+13));
1911 memcpy(&buffer
[totalread
],&ptr
[ofs
],length
);
1917 handle
->conn_valid
= false;
1924 s32
SMB_WriteFile(const char *buffer
, size_t size
, off_t offset
, SMBFILE sfid
)
1931 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
1935 handle
= __smb_handle_open(fid
->conn
);
1936 if(!handle
) return -1;
1938 MakeSMBHeader(SMB_WRITE_ANDX
,CIFS_FLAGS1
,handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
1941 pos
= SMB_HEADER_SIZE
;
1942 ptr
= handle
->message
.smb
;
1943 setUChar(ptr
, pos
, 14);
1944 pos
++; /*** Word Count ***/
1945 setUChar(ptr
, pos
, 0xff);
1946 pos
+= 2; /*** Next AndX ***/
1947 pos
+= 2; /*** Next AndX Offset ***/
1949 setUShort(ptr
, pos
, fid
->sfid
);
1951 setUInt(ptr
, pos
, offset
& 0xffffffff);
1953 setUInt(ptr
, pos
, 0); /*** Reserved, must be 0 ***/
1955 setUShort(ptr
, pos
, 0); /*** Write Mode ***/
1957 pos
+= 2; /*** Remaining ***/
1959 blocks64
= size
>> 16;
1961 setUShort(ptr
, pos
, blocks64
);
1962 pos
+= 2; /*** Length High ***/
1963 setUShort(ptr
, pos
, size
& 0xffff);
1964 pos
+= 2; /*** Length Low ***/
1965 setUShort(ptr
, pos
, 63);
1966 pos
+= 2; /*** Data Offset ***/
1967 setUInt(ptr
, pos
, offset
>> 32); /*** OffsetHigh ***/
1969 setUShort(ptr
, pos
, size
& 0xffff);
1970 pos
+= 2; /*** Data Byte Count ***/
1972 handle
->message
.msg
= NBT_SESSISON_MSG
;
1973 handle
->message
.length
= htons(pos
+size
);
1978 if((copy_len
+pos
)>SMB_MAX_TRANSMIT_SIZE
)
1979 copy_len
= (SMB_MAX_TRANSMIT_SIZE
-pos
);
1981 memcpy(&ptr
[pos
],src
,copy_len
);
1988 /*** Send Header Information ***/
1989 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1990 if(ret
<0) goto failed
;
1993 /*** Send the data ***/
1994 ret
= smb_send(handle
->sck_server
,src
,size
);
1995 if(ret
<0) goto failed
;
1999 if(SMBCheck(SMB_WRITE_ANDX
,handle
)==SMB_SUCCESS
) {
2000 ptr
= handle
->message
.smb
;
2001 ret
= getUShort(ptr
,(SMB_HEADER_SIZE
+5));
2007 handle
->conn_valid
= false;
2014 s32
SMB_PathInfo(const char *filename
, SMBDIRENTRY
*sdir
, SMBCONN smbhndl
)
2024 if(filename
== NULL
)
2027 handle
= __smb_handle_open(smbhndl
);
2028 if (!handle
) return SMB_ERROR
;
2030 MakeSMBHeader(SMB_TRANS2
, CIFS_FLAGS1
, handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
, handle
);
2031 MakeTRANS2Header(SMB_QUERY_PATH_INFO
, handle
);
2033 bpos
= pos
= (T2_BYTE_CNT
+ 2);
2034 pos
+= 3; /*** Padding ***/
2035 ptr
= handle
->message
.smb
;
2036 setUShort(ptr
, pos
, SMB_QUERY_FILE_ALL_INFO
);
2037 pos
+= 2; /*** Level of information requested ***/
2038 setUInt(ptr
, pos
, 0);
2039 pos
+= 4; /*** reserved ***/
2042 if (filename
[0] != '\\')
2043 strcpy(realfile
,"\\");
2044 strcat(realfile
,filename
);
2048 len
= utf8_to_utf16((char*)&ptr
[pos
],realfile
,SMB_MAXPATH
-2);
2054 len
= strlen(realfile
);
2055 memcpy(&ptr
[pos
],realfile
,len
);
2059 /*** Update counts ***/
2060 setUShort(ptr
, T2_PRM_CNT
, (7 + len
));
2061 setUShort(ptr
, T2_SPRM_CNT
, (7 + len
));
2062 setUShort(ptr
, T2_SPRM_OFS
, 68);
2063 setUShort(ptr
, T2_BYTE_CNT
, (pos
- bpos
));
2065 handle
->message
.msg
= NBT_SESSISON_MSG
;
2066 handle
->message
.length
= htons(pos
);
2069 ret
= smb_send(handle
->sck_server
, (char*) &handle
->message
, pos
);
2070 if(ret
<0) goto failed
;
2073 if (SMBCheck(SMB_TRANS2
, handle
) == SMB_SUCCESS
) {
2075 ptr
= handle
->message
.smb
;
2076 /*** Get parameter offset ***/
2077 pos
= getUShort(ptr
, (SMB_HEADER_SIZE
+ 9));
2078 pos
+= 4; // padding
2079 sdir
->ctime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - creation time
2080 sdir
->atime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - access time
2081 sdir
->mtime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - write time
2082 pos
+= 8; // ULONGLONG - change time
2083 sdir
->attributes
= getUInt(ptr
,pos
); pos
+= 4; // ULONG - file attributes
2084 pos
+= 4; // padding
2085 pos
+= 8; // ULONGLONG - allocated file size
2086 sdir
->size
= getULongLong(ptr
, pos
); pos
+= 8; // ULONGLONG - file size
2087 pos
+= 4; // ULONG NumberOfLinks;
2088 pos
+= 2; // UCHAR DeletePending;
2089 pos
+= 2; // UCHAR Directory;
2090 pos
+= 2; // USHORT Pad2; // for alignment only
2091 pos
+= 4; // ULONG EaSize;
2092 pos
+= 4; // ULONG FileNameLength;
2094 strcpy(sdir
->name
,realfile
);
2101 handle
->conn_valid
= false;
2108 * Uses TRANS2 to support long filenames
2110 s32
SMB_FindFirst(const char *filename
, unsigned short flags
, SMBDIRENTRY
*sdir
, SMBCONN smbhndl
)
2120 if(filename
== NULL
)
2123 if(SMB_Reconnect(&smbhndl
,true)!=SMB_SUCCESS
) return SMB_ERROR
;
2125 handle
= __smb_handle_open(smbhndl
);
2126 if(!handle
) return SMB_ERROR
;
2128 sess
= &handle
->session
;
2129 MakeSMBHeader(SMB_TRANS2
,CIFS_FLAGS1
,handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
2130 MakeTRANS2Header(SMB_FIND_FIRST2
,handle
);
2132 ptr
= handle
->message
.smb
;
2134 bpos
= pos
= (T2_BYTE_CNT
+2);
2135 pos
+= 3; /*** Padding ***/
2136 setUShort(ptr
, pos
, flags
);
2137 pos
+= 2; /*** Flags ***/
2138 setUShort(ptr
, pos
, 1);
2139 pos
+= 2; /*** Count ***/
2140 setUShort(ptr
, pos
, 6);
2141 pos
+= 2; /*** Internal Flags ***/
2142 setUShort(ptr
, pos
, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
2143 pos
+= 2; /*** Level of Interest ***/
2144 pos
+= 4; /*** Storage Type == 0 ***/
2148 len
= utf8_to_utf16((char*)&ptr
[pos
], (char*)filename
,SMB_MAXPATH
-2);
2154 len
= strlen(filename
);
2155 memcpy(&ptr
[pos
],filename
,len
);
2159 /*** Update counts ***/
2160 setUShort(ptr
, T2_PRM_CNT
, (13+len
));
2161 setUShort(ptr
, T2_SPRM_CNT
, (13+len
));
2162 setUShort(ptr
, T2_SPRM_OFS
, 68);
2163 setUShort(ptr
, T2_BYTE_CNT
,(pos
-bpos
));
2165 handle
->message
.msg
= NBT_SESSISON_MSG
;
2166 handle
->message
.length
= htons(pos
);
2169 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
2170 if(ret
<0) goto failed
;
2175 if(SMBCheck(SMB_TRANS2
,handle
)==SMB_SUCCESS
) {
2176 ptr
= handle
->message
.smb
;
2177 /*** Get parameter offset ***/
2178 pos
= getUShort(ptr
,(SMB_HEADER_SIZE
+9));
2179 sdir
->sid
= getUShort(ptr
, pos
); pos
+= 2;
2180 sess
->count
= getUShort(ptr
, pos
); pos
+= 2;
2181 sess
->eos
= getUShort(ptr
, pos
); pos
+= 2;
2182 pos
+= 2; // USHORT EaErrorOffset;
2183 pos
+= 2; // USHORT LastNameOffset;
2184 pos
+= 2; // padding?
2188 pos
+= 4; // ULONG NextEntryOffset;
2189 pos
+= 4; // ULONG FileIndex;
2190 sdir
->ctime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - creation time
2191 sdir
->atime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - access time
2192 sdir
->mtime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - write time
2193 pos
+= 8; // ULONGLONG - change time low
2194 sdir
->size
= getULongLong(ptr
, pos
); pos
+= 8;
2196 sdir
->attributes
= getUInt(ptr
, pos
); pos
+= 4;
2197 len
=getUInt(ptr
, pos
);
2200 utf16_to_utf8(sdir
->name
,(char*)&ptr
[pos
],len
);
2202 strcpy(sdir
->name
,(const char*)&ptr
[pos
]);
2210 handle
->conn_valid
= false;
2217 s32
SMB_FindNext(SMBDIRENTRY
*sdir
,SMBCONN smbhndl
)
2226 handle
= __smb_handle_open(smbhndl
);
2227 if(!handle
) return SMB_ERROR
;
2229 sess
= &handle
->session
;
2230 if(sess
->eos
|| sdir
->sid
==0) return SMB_ERROR
;
2232 MakeSMBHeader(SMB_TRANS2
,CIFS_FLAGS1
,handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
2233 MakeTRANS2Header(SMB_FIND_NEXT2
,handle
);
2235 bpos
= pos
= (T2_BYTE_CNT
+2);
2236 pos
+= 3; /*** Padding ***/
2237 ptr
= handle
->message
.smb
;
2238 setUShort(ptr
, pos
, sdir
->sid
);
2239 pos
+= 2; /*** Search ID ***/
2240 setUShort(ptr
, pos
, 1);
2241 pos
+= 2; /*** Count ***/
2242 setUShort(ptr
, pos
, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
2243 pos
+= 2; /*** Level of Interest ***/
2244 pos
+= 4; /*** Storage Type == 0 ***/
2245 setUShort(ptr
, pos
, 12);
2246 pos
+=2; /*** Search flags ***/
2250 if(handle
->unicode
)pad
=1;
2253 /*** Update counts ***/
2254 setUShort(ptr
, T2_PRM_CNT
, 13+pad
);
2255 setUShort(ptr
, T2_SPRM_CNT
, 13+pad
);
2256 setUShort(ptr
, T2_SPRM_OFS
, 68);
2257 setUShort(ptr
, T2_BYTE_CNT
, (pos
-bpos
));
2259 handle
->message
.msg
= NBT_SESSISON_MSG
;
2260 handle
->message
.length
= htons(pos
);
2263 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
2264 if(ret
<0) goto failed
;
2267 if (SMBCheck(SMB_TRANS2
,handle
)==SMB_SUCCESS
) {
2268 ptr
= handle
->message
.smb
;
2269 /*** Get parameter offset ***/
2270 pos
= getUShort(ptr
,(SMB_HEADER_SIZE
+9));
2271 sess
->count
= getUShort(ptr
, pos
); pos
+= 2;
2272 sess
->eos
= getUShort(ptr
, pos
); pos
+= 2;
2273 pos
+= 2; // USHORT EaErrorOffset;
2274 pos
+= 2; // USHORT LastNameOffset;
2279 pos
+= 4; // ULONG NextEntryOffset;
2280 pos
+= 4; // ULONG FileIndex;
2281 sdir
->ctime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - creation time
2282 sdir
->atime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - access time
2283 sdir
->mtime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - write time
2284 pos
+= 8; // ULONGLONG - change time low
2285 sdir
->size
= getULongLong(ptr
, pos
); pos
+= 8;
2287 sdir
->attributes
= getUInt(ptr
, pos
); pos
+= 4;
2288 len
=getUInt(ptr
, pos
);
2291 utf16_to_utf8(sdir
->name
, (char*)&ptr
[pos
],len
);
2293 strcpy (sdir
->name
, (const char*)&ptr
[pos
]);
2301 handle
->conn_valid
= false;
2308 s32
SMB_FindClose(SMBDIRENTRY
*sdir
,SMBCONN smbhndl
)
2316 handle
= __smb_handle_open(smbhndl
);
2317 if(!handle
) return SMB_ERROR
;
2319 sess
= &handle
->session
;
2320 if(sdir
->sid
==0) return SMB_ERROR
;
2322 MakeSMBHeader(SMB_FIND_CLOSE2
,CIFS_FLAGS1
,handle
->unicode
?CIFS_FLAGS2_UNICODE
:CIFS_FLAGS2
,handle
);
2324 pos
= SMB_HEADER_SIZE
;
2325 ptr
= handle
->message
.smb
;
2326 setUChar(ptr
, pos
, 1);
2327 pos
++; /*** Word Count ***/
2328 setUShort(ptr
, pos
, sdir
->sid
);
2330 pos
+= 2; /*** Byte Count ***/
2332 handle
->message
.msg
= NBT_SESSISON_MSG
;
2333 handle
->message
.length
= htons(pos
);
2336 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
2337 if(ret
<0) goto failed
;
2339 ret
= SMBCheck(SMB_FIND_CLOSE2
,handle
);
2343 handle
->conn_valid
= false;