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 ****************************************************************************/
42 #include <processor.h>
43 #include <lwp_threads.h>
44 #include <lwp_objmgr.h>
51 #define SMB_OFFSET_PROTO 0
52 #define SMB_OFFSET_CMD 4
53 #define SMB_OFFSET_NTSTATUS 5
54 #define SMB_OFFSET_ECLASS 5
55 #define SMB_OFFSET_ECODE 7
56 #define SMB_OFFSET_FLAGS 9
57 #define SMB_OFFSET_FLAGS2 10
58 #define SMB_OFFSET_EXTRA 12
59 #define SMB_OFFSET_TID 24
60 #define SMB_OFFSET_PID 26
61 #define SMB_OFFSET_UID 28
62 #define SMB_OFFSET_MID 30
63 #define SMB_HEADER_SIZE 32 /*** SMB Headers are always 32 bytes long ***/
68 #define NBT_SESSISON_MSG 0x00
70 #define SMB_NEG_PROTOCOL 0x72
71 #define SMB_SETUP_ANDX 0x73
72 #define SMB_TREEC_ANDX 0x75
77 #define SMB_TRANS2 0x32
80 #define SMB_FIND_FIRST2 1
81 #define SMB_FIND_NEXT2 2
82 #define SMB_QUERY_FS_INFO 3
83 #define SMB_QUERY_PATH_INFO 5
84 #define SMB_SET_PATH_INFO 6
85 #define SMB_QUERY_FILE_INFO 7
86 #define SMB_SET_FILE_INFO 8
87 #define SMB_CREATE_DIR 13
88 #define SMB_FIND_CLOSE2 0x34
93 #define SMB_OPEN_ANDX 0x2d
94 #define SMB_WRITE_ANDX 0x2f
95 #define SMB_READ_ANDX 0x2e
96 #define SMB_CLOSE 0x04
102 #define T2_WORD_CNT (SMB_HEADER_SIZE)
103 #define T2_PRM_CNT (T2_WORD_CNT+1)
104 #define T2_DATA_CNT (T2_PRM_CNT+2)
105 #define T2_MAXPRM_CNT (T2_DATA_CNT+2)
106 #define T2_MAXBUFFER (T2_MAXPRM_CNT+2)
107 #define T2_SETUP_CNT (T2_MAXBUFFER+2)
108 #define T2_SPRM_CNT (T2_SETUP_CNT+10)
109 #define T2_SPRM_OFS (T2_SPRM_CNT+2)
110 #define T2_SDATA_CNT (T2_SPRM_OFS+2)
111 #define T2_SDATA_OFS (T2_SDATA_CNT+2)
112 #define T2_SSETUP_CNT (T2_SDATA_OFS+2)
113 #define T2_SUB_CMD (T2_SSETUP_CNT+2)
114 #define T2_BYTE_CNT (T2_SUB_CMD+2)
117 #define SMB_PROTO 0x424d53ff
118 #define SMB_HANDLE_NULL 0xffffffff
119 #define SMB_MAX_BUFFERSIZE (62*1024) // cannot be larger than u16 (65536)
120 #define SMB_MAX_TRANSMIT_SIZE 7236
121 #define SMB_DEF_READOFFSET 59
123 #define SMB_CONNHANDLES_MAX 8
124 #define SMB_FILEHANDLES_MAX (32*SMB_CONNHANDLES_MAX)
126 #define SMB_OBJTYPE_HANDLE 7
127 #define SMB_CHECK_HANDLE(hndl) \
129 if(((hndl)==SMB_HANDLE_NULL) || (LWP_OBJTYPE(hndl)!=SMB_OBJTYPE_HANDLE)) \
143 typedef struct _nbtsmb
145 u8 msg
; /*** NBT Message ***/
146 u8 flags
; /*** Not much here really ***/
147 u16 length
; /*** Length, excluding NBT ***/
148 u8 smb
[SMB_MAX_TRANSMIT_SIZE
]; /*** Wii Actual is 7240 bytes ***/
152 * Session Information
154 typedef struct _smbsession
171 typedef struct _smbhandle
179 struct sockaddr_in server_addr
;
185 static u32 smb_dialectcnt
= 1;
186 static BOOL smb_inited
= FALSE
;
187 static lwp_objinfo smb_handle_objects
;
188 static lwp_queue smb_filehandle_queue
;
189 static struct _smbfile smb_filehandles
[SMB_FILEHANDLES_MAX
];
190 static const char *smb_dialects
[] = {"NT LM 0.12",NULL
};
192 extern void ntlm_smb_nt_encrypt(const char *passwd
, const u8
* challenge
, u8
* answer
);
195 * SMB Endian aware supporting functions
197 * SMB always uses Intel Little-Endian values, so htons etc are
198 * of little or no use :) ... Thanks M$
201 /*** get unsigned char ***/
202 static __inline__ u8
getUChar(u8
*buffer
,u32 offset
)
204 return (u8
)buffer
[offset
];
207 /*** set unsigned char ***/
208 static __inline__
void setUChar(u8
*buffer
,u32 offset
,u8 value
)
210 buffer
[offset
] = value
;
213 /*** get unsigned short ***/
214 static __inline__ u16
getUShort(u8
*buffer
,u32 offset
)
216 return (u16
)((buffer
[offset
+1]<<8)|(buffer
[offset
]));
219 /*** set unsigned short ***/
220 static __inline__
void setUShort(u8
*buffer
,u32 offset
,u16 value
)
222 buffer
[offset
] = (value
&0xff);
223 buffer
[offset
+1] = ((value
&0xff00)>>8);
226 /*** get unsigned int ***/
227 static __inline__ u32
getUInt(u8
*buffer
,u32 offset
)
229 return (u32
)((buffer
[offset
+3]<<24)|(buffer
[offset
+2]<<16)|(buffer
[offset
+1]<<8)|buffer
[offset
]);
232 /*** set unsigned int ***/
233 static __inline__
void setUInt(u8
*buffer
,u32 offset
,u32 value
)
235 buffer
[offset
] = (value
&0xff);
236 buffer
[offset
+1] = ((value
&0xff00)>>8);
237 buffer
[offset
+2] = ((value
&0xff0000)>>16);
238 buffer
[offset
+3] = ((value
&0xff000000)>>24);
241 static __inline__ SMBHANDLE
* __smb_handle_open(SMBCONN smbhndl
)
246 SMB_CHECK_HANDLE(smbhndl
);
248 _CPU_ISR_Disable(level
);
249 handle
= (SMBHANDLE
*)__lwp_objmgr_getnoprotection(&smb_handle_objects
,LWP_OBJMASKID(smbhndl
));
250 _CPU_ISR_Restore(level
);
255 static __inline__
void __smb_handle_free(SMBHANDLE
*handle
)
259 _CPU_ISR_Disable(level
);
260 __lwp_objmgr_close(&smb_handle_objects
,&handle
->object
);
261 __lwp_objmgr_free(&smb_handle_objects
,&handle
->object
);
262 _CPU_ISR_Restore(level
);
265 static void __smb_init()
268 __lwp_objmgr_initinfo(&smb_handle_objects
,SMB_CONNHANDLES_MAX
,sizeof(SMBHANDLE
));
269 __lwp_queue_initialize(&smb_filehandle_queue
,smb_filehandles
,SMB_FILEHANDLES_MAX
,sizeof(struct _smbfile
));
272 static SMBHANDLE
* __smb_allocate_handle()
277 _CPU_ISR_Disable(level
);
278 handle
= (SMBHANDLE
*)__lwp_objmgr_allocate(&smb_handle_objects
);
282 handle
->server_name
= NULL
;
283 handle
->share_name
= NULL
;
284 handle
->sck_server
= INVALID_SOCKET
;
285 handle
->conn_valid
= FALSE
;
286 __lwp_objmgr_open(&smb_handle_objects
,&handle
->object
);
288 _CPU_ISR_Restore(level
);
292 static void __smb_free_handle(SMBHANDLE
*handle
)
294 if(handle
->user
) free(handle
->user
);
295 if(handle
->pwd
) free(handle
->pwd
);
296 if(handle
->server_name
) free(handle
->server_name
);
297 if(handle
->share_name
) free(handle
->share_name
);
301 handle
->server_name
= NULL
;
302 handle
->share_name
= NULL
;
303 handle
->sck_server
= INVALID_SOCKET
;
305 __smb_handle_free(handle
);
308 static void MakeSMBHeader(u8 command
,u8 flags
,u16 flags2
,SMBHANDLE
*handle
)
310 u8
*ptr
= handle
->message
.smb
;
311 NBTSMB
*nbt
= &handle
->message
;
312 SMBSESSION
*sess
= &handle
->session
;
314 memset(nbt
,0,sizeof(NBTSMB
));
316 setUInt(ptr
,SMB_OFFSET_PROTO
,SMB_PROTO
);
317 setUChar(ptr
,SMB_OFFSET_CMD
,command
);
318 setUChar(ptr
,SMB_OFFSET_FLAGS
,flags
);
319 setUShort(ptr
,SMB_OFFSET_FLAGS2
,flags2
);
320 setUShort(ptr
,SMB_OFFSET_TID
,sess
->TID
);
321 setUShort(ptr
,SMB_OFFSET_PID
,sess
->PID
);
322 setUShort(ptr
,SMB_OFFSET_UID
,sess
->UID
);
323 setUShort(ptr
,SMB_OFFSET_MID
,sess
->MID
);
325 ptr
[SMB_HEADER_SIZE
] = 0;
331 static void MakeTRANS2Header(u8 subcommand
,SMBHANDLE
*handle
)
333 u8
*ptr
= handle
->message
.smb
;
334 SMBSESSION
*sess
= &handle
->session
;
336 setUChar(ptr
, T2_WORD_CNT
, 15);
337 setUShort(ptr
, T2_MAXPRM_CNT
, 10);
338 setUShort(ptr
, T2_MAXBUFFER
, sess
->MaxBuffer
);
339 setUChar(ptr
, T2_SSETUP_CNT
, 1);
340 setUShort(ptr
, T2_SUB_CMD
, subcommand
);
347 * Do very basic checking on the return SMB
349 static s32
SMBCheck(u8 command
, s32 readlen
,SMBHANDLE
*handle
)
352 u8
*ptr
= handle
->message
.smb
;
353 NBTSMB
*nbt
= &handle
->message
;
355 memset(nbt
,0,sizeof(NBTSMB
));
356 recvd
= net_recv(handle
->sck_server
,nbt
,readlen
,0);
357 if(recvd
<12) return SMB_BAD_DATALEN
;
359 /*** Do basic SMB Header checks ***/
360 ret
= getUInt(ptr
,SMB_OFFSET_PROTO
);
361 if(ret
!=SMB_PROTO
) return SMB_BAD_PROTOCOL
;
363 ret
= getUChar(ptr
, SMB_OFFSET_CMD
);
364 if(ret
!=command
) return SMB_BAD_COMMAND
;
366 ret
= getUInt(ptr
,SMB_OFFSET_NTSTATUS
);
367 if(ret
) return SMB_ERROR
;
375 * Setup the SMB session, including authentication with the
376 * magic 'NTLM Response'
378 static s32
SMB_SetupAndX(SMBHANDLE
*handle
)
383 u8
*ptr
= handle
->message
.smb
;
384 SMBSESSION
*sess
= &handle
->session
;
385 char pwd
[200], ntRespData
[24];
387 MakeSMBHeader(SMB_SETUP_ANDX
,0x08,0x01,handle
);
388 pos
= SMB_HEADER_SIZE
;
390 setUChar(ptr
,pos
,13);
391 pos
++; /*** Word Count ***/
392 setUChar(ptr
,pos
,0xff);
393 pos
++; /*** Next AndX ***/
394 pos
++; /*** Reserved ***/
395 pos
+= 2; /*** Next AndX Offset ***/
396 setUShort(ptr
,pos
,sess
->MaxBuffer
);
398 setUShort(ptr
,pos
,sess
->MaxMpx
);
400 setUShort(ptr
,pos
,sess
->MaxVCS
);
402 setUInt(ptr
,pos
,sess
->sKey
);
404 setUShort(ptr
,pos
,0); /*** Password length (case-insensitive) ***/
406 setUShort(ptr
,pos
,24); /*** Password length (case-sensitive) ***/
408 pos
+= 4; /*** Reserved ***/
409 pos
+= 4; /*** Capabilities ***/
411 pos
+= 2; /*** Byte count ***/
413 /*** The magic 'NTLM Response' ***/
414 strcpy(pwd
, handle
->pwd
);
415 ntlm_smb_nt_encrypt((const char *) pwd
, (const u8
*) sess
->challenge
, (u8
*) ntRespData
);
417 /*** Build information ***/
418 memcpy(&ptr
[pos
],ntRespData
,24);
422 strcpy(pwd
, handle
->user
);
423 for(i
=0;i
<strlen(pwd
);i
++) pwd
[i
] = toupper(pwd
[i
]);
424 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
425 pos
+= strlen(pwd
)+1;
427 /*** Primary Domain ***/
428 if(handle
->user
[0]=='\0') sess
->p_domain
[0] = '\0';
429 memcpy(&ptr
[pos
],sess
->p_domain
,strlen((const char*)sess
->p_domain
));
430 pos
+= strlen((const char*)sess
->p_domain
)+1;
433 strcpy(pwd
,"Unix (libOGC)");
434 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
435 pos
+= strlen(pwd
)+1;
437 /*** Native LAN Manager ***/
438 strcpy(pwd
,"Nintendo Wii");
439 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
440 pos
+= strlen (pwd
)+1;
442 /*** Update byte count ***/
443 setUShort(ptr
,bcpos
,((pos
-bcpos
)-2));
445 handle
->message
.msg
= NBT_SESSISON_MSG
;
446 handle
->message
.length
= htons (pos
);
449 ret
= net_send(handle
->sck_server
,(char*)&handle
->message
,pos
,0);
451 if((ret
=SMBCheck(SMB_SETUP_ANDX
,sizeof(NBTSMB
),handle
))==SMB_SUCCESS
) {
452 /*** Collect UID ***/
453 sess
->UID
= getUShort(handle
->message
.smb
,SMB_OFFSET_UID
);
462 * Finally, net_connect to the remote share
464 static s32
SMB_TreeAndX(SMBHANDLE
*handle
)
468 u8
*ptr
= handle
->message
.smb
;
469 SMBSESSION
*sess
= &handle
->session
;
471 MakeSMBHeader(SMB_TREEC_ANDX
,0x08,0x01,handle
);
472 pos
= SMB_HEADER_SIZE
;
475 pos
++; /*** Word Count ***/
476 setUChar(ptr
,pos
,0xff);
477 pos
++; /*** Next AndX ***/
478 pos
++; /*** Reserved ***/
479 pos
+= 2; /*** Next AndX Offset ***/
480 pos
+= 2; /*** Flags ***/
481 setUShort(ptr
,pos
,1);
482 pos
+= 2; /*** Password Length ***/
485 pos
++; /*** NULL Password ***/
487 /*** Build server share path ***/
488 strcpy ((char*)path
, "\\\\");
489 strcat ((char*)path
, handle
->server_name
);
490 strcat ((char*)path
, "\\");
491 strcat ((char*)path
, handle
->share_name
);
492 for(ret
=0;ret
<strlen((const char*)path
);ret
++) path
[ret
] = toupper(path
[ret
]);
494 memcpy(&ptr
[pos
],path
,strlen((const char*)path
));
495 pos
+= strlen((const char*)path
)+1;
498 strcpy((char*)path
,"?????");
499 memcpy(&ptr
[pos
],path
,strlen((const char*)path
));
500 pos
+= strlen((const char*)path
)+1;
502 /*** Update byte count ***/
503 setUShort(ptr
,bcpos
,(pos
-bcpos
)-2);
505 handle
->message
.msg
= NBT_SESSISON_MSG
;
506 handle
->message
.length
= htons (pos
);
509 ret
= net_send(handle
->sck_server
,(char *)&handle
->message
,pos
,0);
511 if((ret
=SMBCheck(SMB_TREEC_ANDX
,sizeof(NBTSMB
),handle
))==SMB_SUCCESS
) {
512 /*** Collect Tree ID ***/
513 sess
->TID
= getUShort(handle
->message
.smb
,SMB_OFFSET_TID
);
520 * SMB_NegotiateProtocol
522 * The only protocol we admit to is 'NT LM 0.12'
524 static s32
SMB_NegotiateProtocol(const char *dialects
[],int dialectc
,SMBHANDLE
*handle
)
534 if(!handle
|| !dialects
|| dialectc
<=0)
537 /*** Clear session variables ***/
538 sess
= &handle
->session
;
539 memset(sess
,0,sizeof(SMBSESSION
));
543 MakeSMBHeader(SMB_NEG_PROTOCOL
,0x08,0x01,handle
);
545 pos
= SMB_HEADER_SIZE
+3;
546 ptr
= handle
->message
.smb
;
547 for(i
=0,bcnt
=0;i
<dialectc
;i
++) {
548 len
= strlen(dialects
[i
])+1;
550 memcpy(&ptr
[pos
],dialects
[i
],len
);
554 /*** Update byte count ***/
555 setUShort(ptr
,(SMB_HEADER_SIZE
+1),bcnt
);
557 /*** Set NBT information ***/
558 handle
->message
.msg
= NBT_SESSISON_MSG
;
559 handle
->message
.length
= htons(pos
);
562 ret
= net_send(handle
->sck_server
,(char*)&handle
->message
,pos
,0);
563 if(ret
<=0) return SMB_ERROR
;
565 /*** Check response ***/
566 if((ret
=SMBCheck(SMB_NEG_PROTOCOL
,sizeof(NBTSMB
),handle
))==SMB_SUCCESS
) {
567 pos
= SMB_HEADER_SIZE
;
568 ptr
= handle
->message
.smb
;
570 /*** Collect information ***/
571 if(getUChar(ptr
,pos
)!=17) return SMB_PROTO_FAIL
; // UCHAR WordCount; Count of parameter words = 17
574 if(getUShort(ptr
,pos
)) return SMB_PROTO_FAIL
; // USHORT DialectIndex; Index of selected dialect - should always be 0 since we only supplied 1!
577 if(getUChar(ptr
,pos
)!=3) return SMB_NOT_USER
; //UCHAR SecurityMode; Security mode:
580 sess
->MaxMpx
= getUShort(ptr
, pos
); //USHORT MaxMpxCount; Max pending outstanding requests
583 sess
->MaxVCS
= getUShort(ptr
, pos
); //USHORT MaxNumberVcs; Max VCs between client and server
586 serverMaxBuffer
= getUInt(ptr
, pos
); //ULONG MaxBufferSize; Max transmit buffer size
587 if(serverMaxBuffer
>SMB_MAX_TRANSMIT_SIZE
)
588 sess
->MaxBuffer
= SMB_MAX_TRANSMIT_SIZE
;
590 sess
->MaxBuffer
= serverMaxBuffer
;
593 pos
+= 4; //ULONG MaxRawSize; Maximum raw buffer size
594 sess
->sKey
= getUInt(ptr
,pos
);
596 pos
+= 4; //ULONG Capabilities; Server capabilities
597 pos
+= 4; //ULONG SystemTimeLow; System (UTC) time of the server (low).
598 pos
+= 4; //ULONG SystemTimeHigh; System (UTC) time of the server (high).
599 pos
+= 2; //USHORT ServerTimeZone; Time zone of server (minutes from UTC)
600 if(getUChar(ptr
,pos
)!=8) return SMB_BAD_KEYLEN
; //UCHAR EncryptionKeyLength - 0 or 8
603 bytecount
= getUShort(ptr
,pos
);
605 /*** Copy challenge key ***/
607 memcpy(&sess
->challenge
,&ptr
[pos
],8);
609 /*** Primary domain ***/
612 while(ptr
[pos
+j
]!=0) {
613 sess
->p_domain
[i
] = ptr
[pos
+j
];
617 sess
->p_domain
[i
] = '\0';
625 static s32
do_netconnect(SMBHANDLE
*handle
)
631 /*** Create the global net_socket ***/
632 sock
= net_socket(AF_INET
, SOCK_STREAM
, IPPROTO_IP
);
633 if(sock
==INVALID_SOCKET
) return -1;
635 /*** Switch off Nagle, ON TCP_NODELAY ***/
637 ret
= net_setsockopt(sock
,IPPROTO_TCP
,TCP_NODELAY
,&nodelay
,sizeof(nodelay
));
639 ret
= net_connect(sock
,(struct sockaddr
*)&handle
->server_addr
,sizeof(handle
->server_addr
));
645 handle
->sck_server
= sock
;
649 static s32
do_smbconnect(SMBHANDLE
*handle
)
653 ret
= SMB_NegotiateProtocol(smb_dialects
,smb_dialectcnt
,handle
);
654 if(ret
!=SMB_SUCCESS
) {
655 net_close(handle
->sck_server
);
659 ret
= SMB_SetupAndX(handle
);
660 if(ret
!=SMB_SUCCESS
) {
661 net_close(handle
->sck_server
);
665 ret
= SMB_TreeAndX(handle
);
666 if(ret
!=SMB_SUCCESS
) {
667 net_close(handle
->sck_server
);
671 handle
->conn_valid
= TRUE
;
675 /****************************************************************************
676 * Primary setup, logon and connection all in one :)
677 ****************************************************************************/
678 s32
SMB_Connect(SMBCONN
*smbhndl
, const char *user
, const char *password
, const char *share
, const char *IP
)
683 *smbhndl
= SMB_HANDLE_NULL
;
685 if(smb_inited
==FALSE
) {
687 _CPU_ISR_Disable(level
);
688 if(smb_inited
==FALSE
) __smb_init();
689 _CPU_ISR_Restore(level
);
692 handle
= __smb_allocate_handle();
693 if(!handle
) return SMB_ERROR
;
695 handle
->user
= strdup(user
);
696 handle
->pwd
= strdup(password
);
697 handle
->server_name
= strdup(IP
);
698 handle
->share_name
= strdup(share
);
700 handle
->server_addr
.sin_family
= AF_INET
;
701 handle
->server_addr
.sin_port
= htons(445);
702 handle
->server_addr
.sin_addr
.s_addr
= inet_addr(IP
);
704 ret
= do_netconnect(handle
);
705 if(ret
==0) ret
= do_smbconnect(handle
);
707 __smb_free_handle(handle
);
710 *smbhndl
=(SMBCONN
)(LWP_OBJMASKTYPE(SMB_OBJTYPE_HANDLE
)|LWP_OBJMASKID(handle
->object
.id
));
715 /****************************************************************************
718 * Probably NEVER called on GameCube, but here for completeness
719 ****************************************************************************/
720 void SMB_Close(SMBCONN smbhndl
)
724 handle
= __smb_handle_open(smbhndl
);
727 if(handle
->sck_server
!=INVALID_SOCKET
) net_close(handle
->sck_server
);
728 __smb_free_handle(handle
);
731 s32
SMB_Reconnect(SMBCONN smbhndl
, BOOL test_conn
)
733 s32 ret
= SMB_SUCCESS
;
734 SMBHANDLE
*handle
= __smb_handle_open(smbhndl
);
736 return SMB_ERROR
; // we have no handle, so we can't reconnect
738 if(handle
->conn_valid
&& test_conn
)
741 SMB_PathInfo("\\", &dentry
, smbhndl
);
744 if(!handle
->conn_valid
)
746 // save connection details
747 const char * user
= strdup(handle
->user
);
748 const char * pwd
= strdup(handle
->pwd
);
749 const char * ip
= strdup(handle
->server_name
);
750 const char * share
= strdup(handle
->share_name
);
752 // shut down connection, and reopen
754 ret
= SMB_Connect(&smbhndl
, user
, pwd
, share
, ip
);
759 SMBFILE
SMB_OpenFile(const char *filename
, u16 access
, u16 creation
,SMBCONN smbhndl
)
764 struct _smbfile
*fid
= NULL
;
768 if(SMB_Reconnect(smbhndl
,TRUE
)!=SMB_SUCCESS
) return NULL
;
770 handle
= __smb_handle_open(smbhndl
);
771 if(!handle
) return NULL
;
773 MakeSMBHeader(SMB_OPEN_ANDX
,0x08,0x01,handle
);
775 pos
= SMB_HEADER_SIZE
;
776 ptr
= handle
->message
.smb
;
777 setUChar(ptr
, pos
, 15);
778 pos
++; /*** Word Count ***/
779 setUChar(ptr
, pos
, 0xff);
780 pos
++; /*** Next AndX ***/
781 pos
+= 3; /*** Next AndX Offset ***/
783 pos
+= 2; /*** Flags ***/
784 setUShort(ptr
, pos
, access
);
785 pos
+= 2; /*** Access mode ***/
786 setUShort(ptr
, pos
, 0x6);
787 pos
+= 2; /*** Type of file ***/
788 pos
+= 2; /*** Attributes ***/
789 pos
+= 4; /*** File time - don't care - let server decide ***/
790 setUShort(ptr
, pos
, creation
);
791 pos
+= 2; /*** Creation flags ***/
792 pos
+= 4; /*** Allocation size ***/
793 pos
+= 8; /*** Reserved ***/
794 pos
+= 2; /*** Byte Count ***/
797 if (filename
[0] != '\\') {
798 strcpy(realfile
, "\\");
799 strcat(realfile
,filename
);
801 strcpy(realfile
,filename
);
803 memcpy(&ptr
[pos
],realfile
,strlen(realfile
));
804 pos
+= strlen(realfile
)+1;
806 setUShort(ptr
,(bpos
-2),(pos
-bpos
));
808 handle
->message
.msg
= NBT_SESSISON_MSG
;
809 handle
->message
.length
= htons(pos
);
812 ret
= net_send(handle
->sck_server
,(char*)&handle
->message
,pos
,0);
813 if(ret
<0) goto failed
;
815 if(SMBCheck(SMB_OPEN_ANDX
,sizeof(NBTSMB
),handle
)==SMB_SUCCESS
) {
816 /*** Check file handle ***/
817 fid
= (struct _smbfile
*)__lwp_queue_get(&smb_filehandle_queue
);
820 fid
->sfid
= getUShort(handle
->message
.smb
,(SMB_HEADER_SIZE
+5));
826 handle
->conn_valid
= FALSE
;
833 void SMB_CloseFile(SMBFILE sfid
)
838 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
842 handle
= __smb_handle_open(fid
->conn
);
845 MakeSMBHeader(SMB_CLOSE
,0x08,0x01,handle
);
847 pos
= SMB_HEADER_SIZE
;
848 ptr
= handle
->message
.smb
;
849 setUChar(ptr
, pos
, 3);
850 pos
++; /** Word Count **/
851 setUShort(ptr
, pos
, fid
->sfid
);
853 setUInt(ptr
, pos
, 0xffffffff);
854 pos
+= 4; /*** Last Write ***/
855 pos
+= 2; /*** Byte Count ***/
857 handle
->message
.msg
= NBT_SESSISON_MSG
;
858 handle
->message
.length
= htons(pos
);
861 ret
= net_send(handle
->sck_server
,(char*)&handle
->message
,pos
,0);
862 if(ret
<0) handle
->conn_valid
= FALSE
;
864 SMBCheck(SMB_CLOSE
,sizeof(NBTSMB
),handle
);
865 __lwp_queue_append(&smb_filehandle_queue
,&fid
->node
);
871 s32
SMB_ReadFile(char *buffer
, int size
, int offset
, SMBFILE sfid
)
877 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
881 /*** Don't let the size exceed! ***/
882 if(size
>SMB_MAX_BUFFERSIZE
) return 0;
884 handle
= __smb_handle_open(fid
->conn
);
885 if(!handle
) return 0;
887 MakeSMBHeader(SMB_READ_ANDX
,0x08,0x01,handle
);
889 pos
= SMB_HEADER_SIZE
;
890 ptr
= handle
->message
.smb
;
891 setUChar(ptr
, pos
, 10);
892 pos
++; /*** Word count ***/
893 setUChar(ptr
, pos
, 0xff);
895 pos
+= 3; /*** Reserved, Next AndX Offset ***/
896 setUShort(ptr
, pos
, fid
->sfid
);
897 pos
+= 2; /*** FID ***/
898 setUInt(ptr
, pos
, offset
);
899 pos
+= 4; /*** Offset ***/
901 setUShort(ptr
, pos
, size
& 0xffff);
903 setUShort(ptr
, pos
, size
& 0xffff);
905 setUInt(ptr
, pos
, 0);
907 pos
+= 2; /*** Remaining ***/
908 pos
+= 2; /*** Byte count ***/
910 handle
->message
.msg
= NBT_SESSISON_MSG
;
911 handle
->message
.length
= htons(pos
);
914 ret
= net_send(handle
->sck_server
,(char*)&handle
->message
, pos
, 0);
915 if(ret
<0) goto failed
;
917 /*** SMBCheck should now only read up to the end of a standard header ***/
918 if((ret
=SMBCheck(SMB_READ_ANDX
,(SMB_HEADER_SIZE
+27+4),handle
))==SMB_SUCCESS
) {
919 ptr
= handle
->message
.smb
;
920 /*** Retrieve data length for this packet ***/
921 length
= getUShort(ptr
,(SMB_HEADER_SIZE
+11));
922 /*** Retrieve offset to data ***/
923 ofs
= getUShort(ptr
,(SMB_HEADER_SIZE
+13));
925 /*** Default offset, with no padding is 59, so grab any outstanding padding ***/
926 if(ofs
>SMB_DEF_READOFFSET
) {
928 ret
= net_recv(handle
->sck_server
,pad
,(ofs
-SMB_DEF_READOFFSET
), 0);
929 if(ret
<0) return ret
;
932 /*** Finally, go grab the data ***/
936 while ((ret
=net_recv(handle
->sck_server
,&dest
[ofs
],length
, 0))!=0) {
937 if(ret
<0) return ret
;
940 if (ofs
>=length
) break;
948 handle
->conn_valid
= FALSE
;
955 s32
SMB_WriteFile(const char *buffer
, int size
, int offset
, SMBFILE sfid
)
962 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
966 handle
= __smb_handle_open(fid
->conn
);
967 if(!handle
) return SMB_ERROR
;
969 MakeSMBHeader(SMB_WRITE_ANDX
,0x08,0x01,handle
);
971 pos
= SMB_HEADER_SIZE
;
972 ptr
= handle
->message
.smb
;
973 setUChar(ptr
, pos
, 12);
974 pos
++; /*** Word Count ***/
975 setUChar(ptr
, pos
, 0xff);
976 pos
+= 2; /*** Next AndX ***/
977 pos
+= 2; /*** Next AndX Offset ***/
979 setUShort(ptr
, pos
, fid
->sfid
);
981 setUInt(ptr
, pos
, offset
);
983 pos
+= 4; /*** Reserved ***/
984 pos
+= 2; /*** Write Mode ***/
985 pos
+= 2; /*** Remaining ***/
987 blocks64
= size
>> 16;
989 setUShort(ptr
, pos
, blocks64
);
990 pos
+= 2; /*** Length High ***/
991 setUShort(ptr
, pos
, size
& 0xffff);
992 pos
+= 2; /*** Length Low ***/
993 setUShort(ptr
, pos
, 59);
994 pos
+= 2; /*** Data Offset ***/
995 setUShort(ptr
, pos
, size
& 0xffff);
996 pos
+= 2; /*** Data Byte Count ***/
998 handle
->message
.msg
= NBT_SESSISON_MSG
;
999 handle
->message
.length
= htons(pos
+size
);
1003 if((copy_len
+pos
)>SMB_MAX_TRANSMIT_SIZE
) copy_len
= (SMB_MAX_TRANSMIT_SIZE
-pos
);
1005 memcpy(&ptr
[pos
],src
,copy_len
);
1012 /*** Send Header Information ***/
1013 ret
= net_send(handle
->sck_server
,(char*)&handle
->message
,pos
,0);
1014 if(ret
<0) goto failed
;
1017 /*** Send the data ***/
1018 ret
= net_send(handle
->sck_server
,src
,size
,0);
1019 if(ret
<0) goto failed
;
1023 if(SMBCheck(SMB_WRITE_ANDX
,sizeof(NBTSMB
),handle
)==SMB_SUCCESS
) {
1024 ptr
= handle
->message
.smb
;
1025 ret
= getUShort(ptr
,(SMB_HEADER_SIZE
+5));
1031 handle
->conn_valid
= FALSE
;
1038 s32
SMB_PathInfo(const char *filename
, SMBDIRENTRY
*sdir
, SMBCONN smbhndl
)
1047 handle
= __smb_handle_open(smbhndl
);
1048 if (!handle
) return SMB_ERROR
;
1050 MakeSMBHeader(SMB_TRANS2
, 0x08, 0x01, handle
);
1051 MakeTRANS2Header(SMB_QUERY_PATH_INFO
, handle
);
1053 bpos
= pos
= (T2_BYTE_CNT
+ 2);
1054 pos
+= 3; /*** Padding ***/
1055 ptr
= handle
->message
.smb
;
1056 setUShort(ptr
, pos
, 0x107); //SMB_QUERY_FILE_ALL_INFO
1059 setUInt(ptr
, pos
, 0);
1060 pos
+= 4; /*** reserved ***/
1062 if (filename
[0] != '\\') {
1063 strcpy(realfile
, "\\");
1064 strcat(realfile
, filename
);
1066 strcpy(realfile
, filename
);
1068 memcpy(&ptr
[pos
], realfile
, strlen(realfile
));
1069 pos
+= strlen(realfile
) + 1; /*** Include padding ***/
1071 /*** Update counts ***/
1072 setUShort(ptr
, T2_PRM_CNT
, (7 + strlen(realfile
)));
1073 setUShort(ptr
, T2_SPRM_CNT
, (7 + strlen(realfile
)));
1074 setUShort(ptr
, T2_SPRM_OFS
, 68);
1075 setUShort(ptr
, T2_SDATA_OFS
, (75 + strlen(realfile
)));
1076 setUShort(ptr
, T2_BYTE_CNT
, (pos
- bpos
));
1078 handle
->message
.msg
= NBT_SESSISON_MSG
;
1079 handle
->message
.length
= htons(pos
);
1082 ret
= net_send(handle
->sck_server
, (char*) &handle
->message
, pos
, 0);
1083 if(ret
<0) goto failed
;
1086 if (SMBCheck(SMB_TRANS2
, sizeof(NBTSMB
), handle
) == SMB_SUCCESS
) {
1088 ptr
= handle
->message
.smb
;
1089 /*** Get parameter offset ***/
1090 pos
= getUShort(ptr
, (SMB_HEADER_SIZE
+ 9));
1091 sdir
->attributes
= getUShort(ptr
,pos
+36);
1094 sdir
->size_low
= getUInt(ptr
, pos
);
1096 sdir
->size_high
= getUInt(ptr
, pos
);
1098 strcpy(sdir
->name
,realfile
);
1105 handle
->conn_valid
= FALSE
;
1112 * Uses TRANS2 to support long filenames
1114 s32
SMB_FindFirst(const char *filename
, unsigned short flags
, SMBDIRENTRY
*sdir
, SMBCONN smbhndl
)
1123 if(SMB_Reconnect(smbhndl
,TRUE
)!=SMB_SUCCESS
) return SMB_ERROR
;
1125 handle
= __smb_handle_open(smbhndl
);
1126 if(!handle
) return SMB_ERROR
;
1128 sess
= &handle
->session
;
1129 MakeSMBHeader(SMB_TRANS2
,0x08,0x01,handle
);
1130 MakeTRANS2Header(SMB_FIND_FIRST2
,handle
);
1132 bpos
= pos
= (T2_BYTE_CNT
+2);
1133 pos
+= 3; /*** Padding ***/
1134 ptr
= handle
->message
.smb
;
1135 setUShort(ptr
, pos
, flags
);
1136 pos
+= 2; /*** Flags ***/
1137 setUShort(ptr
, pos
, 1);
1138 pos
+= 2; /*** Count ***/
1139 setUShort(ptr
, pos
, 6);
1140 pos
+= 2; /*** Internal Flags ***/
1141 setUShort(ptr
, pos
, 260);
1142 pos
+= 2; /*** Level of Interest ***/
1143 pos
+= 4; /*** Storage Type == 0 ***/
1144 memcpy(&ptr
[pos
], filename
, strlen(filename
));
1145 pos
+= strlen(filename
)+1; /*** Include padding ***/
1147 /*** Update counts ***/
1148 setUShort(ptr
, T2_PRM_CNT
, (13+strlen(filename
)));
1149 setUShort(ptr
, T2_SPRM_CNT
, (13+strlen(filename
)));
1150 setUShort(ptr
, T2_SPRM_OFS
, 68);
1151 setUShort(ptr
, T2_SDATA_OFS
,(81+strlen(filename
)));
1152 setUShort(ptr
, T2_BYTE_CNT
,(pos
-bpos
));
1154 handle
->message
.msg
= NBT_SESSISON_MSG
;
1155 handle
->message
.length
= htons(pos
);
1158 ret
= net_send(handle
->sck_server
,(char*)&handle
->message
,pos
,0);
1159 if(ret
<0) goto failed
;
1165 if(SMBCheck(SMB_TRANS2
,sizeof(NBTSMB
),handle
)==SMB_SUCCESS
) {
1166 ptr
= handle
->message
.smb
;
1167 /*** Get parameter offset ***/
1168 pos
= getUShort(ptr
,(SMB_HEADER_SIZE
+9));
1169 sess
->sid
= getUShort(ptr
, pos
);
1171 sess
->count
= getUShort(ptr
, pos
);
1173 sess
->eos
= getUShort(ptr
, pos
);
1178 sdir
->size_low
= getUInt(ptr
, pos
);
1180 sdir
->size_high
= getUInt(ptr
, pos
);
1183 sdir
->attributes
= getUInt(ptr
, pos
);
1185 strcpy(sdir
->name
, (const char*)&ptr
[pos
]);
1193 handle
->conn_valid
= FALSE
;
1200 s32
SMB_FindNext(SMBDIRENTRY
*sdir
,SMBCONN smbhndl
)
1209 if(SMB_Reconnect(smbhndl
,TRUE
)!=SMB_SUCCESS
) return SMB_ERROR
;
1211 handle
= __smb_handle_open(smbhndl
);
1212 if(!handle
) return SMB_ERROR
;
1214 sess
= &handle
->session
;
1215 if(sess
->eos
|| sess
->sid
==0) return SMB_ERROR
;
1217 MakeSMBHeader(SMB_TRANS2
,0x08,0x01,handle
);
1218 MakeTRANS2Header(SMB_FIND_NEXT2
,handle
);
1220 bpos
= pos
= (T2_BYTE_CNT
+2);
1221 pos
+= 3; /*** Padding ***/
1222 ptr
= handle
->message
.smb
;
1223 setUShort(ptr
, pos
, sess
->sid
);
1224 pos
+= 2; /*** Search ID ***/
1225 setUShort(ptr
, pos
, 1);
1226 pos
+= 2; /*** Count ***/
1227 setUShort(ptr
, pos
, 260);
1228 pos
+= 2; /*** Level of Interest ***/
1229 pos
+= 4; /*** Storage Type == 0 ***/
1230 setUShort(ptr
, pos
, 12);
1231 pos
+=2; /*** Search flags ***/
1234 /*** Update counts ***/
1235 setUShort(ptr
, T2_PRM_CNT
, 13);
1236 setUShort(ptr
, T2_SPRM_CNT
, 13);
1237 setUShort(ptr
, T2_SPRM_OFS
, 68);
1238 setUShort(ptr
, T2_SDATA_OFS
, 81);
1239 setUShort(ptr
, T2_BYTE_CNT
, (pos
-bpos
));
1241 handle
->message
.msg
= NBT_SESSISON_MSG
;
1242 handle
->message
.length
= htons(pos
);
1245 ret
= net_send(handle
->sck_server
,(char*)&handle
->message
,pos
,0);
1246 if(ret
<0) goto failed
;
1249 if (SMBCheck(SMB_TRANS2
,sizeof(NBTSMB
),handle
)==SMB_SUCCESS
) {
1250 ptr
= handle
->message
.smb
;
1251 /*** Get parameter offset ***/
1252 pos
= getUShort(ptr
,(SMB_HEADER_SIZE
+9));
1253 sess
->count
= getUShort(ptr
, pos
);
1255 sess
->eos
= getUShort(ptr
, pos
);
1260 sdir
->size_low
= getUInt(ptr
, pos
);
1262 sdir
->size_high
= getUInt(ptr
, pos
);
1265 sdir
->attributes
= getUInt(ptr
, pos
);
1267 strcpy (sdir
->name
, (const char*)&ptr
[pos
]);
1275 handle
->conn_valid
= FALSE
;
1282 s32
SMB_FindClose(SMBCONN smbhndl
)
1290 if(SMB_Reconnect(smbhndl
,TRUE
)!=SMB_SUCCESS
) return SMB_ERROR
;
1292 handle
= __smb_handle_open(smbhndl
);
1293 if(!handle
) return SMB_ERROR
;
1295 sess
= &handle
->session
;
1296 if(sess
->sid
==0) return SMB_ERROR
;
1298 MakeSMBHeader(SMB_FIND_CLOSE2
,0x08,0x01,handle
);
1300 pos
= SMB_HEADER_SIZE
;
1301 ptr
= handle
->message
.smb
;
1302 setUChar(ptr
, pos
, 1);
1303 pos
++; /*** Word Count ***/
1304 setUShort(ptr
, pos
, sess
->sid
);
1306 pos
+= 2; /*** Byte Count ***/
1308 handle
->message
.msg
= NBT_SESSISON_MSG
;
1309 handle
->message
.length
= htons(pos
);
1312 ret
= net_send(handle
->sck_server
,(char*)&handle
->message
,pos
,0);
1313 if(ret
<0) goto failed
;
1315 ret
= SMBCheck(SMB_FIND_CLOSE2
,sizeof(NBTSMB
),handle
);
1319 handle
->conn_valid
= FALSE
;