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>
52 #define IOS_O_NONBLOCK 0x04
53 #define RECV_TIMEOUT 3000 // in ms
58 #define SMB_OFFSET_PROTO 0
59 #define SMB_OFFSET_CMD 4
60 #define SMB_OFFSET_NTSTATUS 5
61 #define SMB_OFFSET_ECLASS 5
62 #define SMB_OFFSET_ECODE 7
63 #define SMB_OFFSET_FLAGS 9
64 #define SMB_OFFSET_FLAGS2 10
65 #define SMB_OFFSET_EXTRA 12
66 #define SMB_OFFSET_TID 24
67 #define SMB_OFFSET_PID 26
68 #define SMB_OFFSET_UID 28
69 #define SMB_OFFSET_MID 30
70 #define SMB_HEADER_SIZE 32 /*** SMB Headers are always 32 bytes long ***/
75 #define NBT_SESSISON_MSG 0x00
77 #define SMB_NEG_PROTOCOL 0x72
78 #define SMB_SETUP_ANDX 0x73
79 #define SMB_TREEC_ANDX 0x75
82 #define NBT_KEEPALIVE_MSG 0x85
83 #define KEEPALIVE_SIZE 4
88 #define SMB_TRANS2 0x32
91 #define SMB_FIND_FIRST2 1
92 #define SMB_FIND_NEXT2 2
93 #define SMB_QUERY_FS_INFO 3
94 #define SMB_QUERY_PATH_INFO 5
95 #define SMB_SET_PATH_INFO 6
96 #define SMB_QUERY_FILE_INFO 7
97 #define SMB_SET_FILE_INFO 8
98 #define SMB_CREATE_DIR 13
99 #define SMB_FIND_CLOSE2 0x34
100 #define SMB_QUERY_FILE_ALL_INFO 0x107
105 #define SMB_OPEN_ANDX 0x2d
106 #define SMB_WRITE_ANDX 0x2f
107 #define SMB_READ_ANDX 0x2e
108 #define SMB_CLOSE 0x04
114 #define T2_WORD_CNT (SMB_HEADER_SIZE)
115 #define T2_PRM_CNT (T2_WORD_CNT+1)
116 #define T2_DATA_CNT (T2_PRM_CNT+2)
117 #define T2_MAXPRM_CNT (T2_DATA_CNT+2)
118 #define T2_MAXBUFFER (T2_MAXPRM_CNT+2)
119 #define T2_SETUP_CNT (T2_MAXBUFFER+2)
120 #define T2_SPRM_CNT (T2_SETUP_CNT+10)
121 #define T2_SPRM_OFS (T2_SPRM_CNT+2)
122 #define T2_SDATA_CNT (T2_SPRM_OFS+2)
123 #define T2_SDATA_OFS (T2_SDATA_CNT+2)
124 #define T2_SSETUP_CNT (T2_SDATA_OFS+2)
125 #define T2_SUB_CMD (T2_SSETUP_CNT+2)
126 #define T2_BYTE_CNT (T2_SUB_CMD+2)
129 #define SMB_PROTO 0x424d53ff
130 #define SMB_HANDLE_NULL 0xffffffff
131 #define SMB_MAX_BUFFERSIZE ((1024*64)-64) // cannot be larger than u16 (65536) - samba header (64)
132 #define SMB_MAX_NET_READ_SIZE 7300 // see smb_recv
133 #define SMB_MAX_NET_WRITE_SIZE 4096 // see smb_sendv
134 #define SMB_MAX_TRANSMIT_SIZE 16384
135 #define SMB_DEF_READOFFSET 63
137 #define SMB_CONNHANDLES_MAX 8
138 #define SMB_FILEHANDLES_MAX (32*SMB_CONNHANDLES_MAX)
140 #define SMB_OBJTYPE_HANDLE 7
141 #define SMB_CHECK_HANDLE(hndl) \
143 if(((hndl)==SMB_HANDLE_NULL) || (LWP_OBJTYPE(hndl)!=SMB_OBJTYPE_HANDLE)) \
147 /* NBT Session Service Packet Type Codes
150 #define SESS_MSG 0x00
151 #define SESS_REQ 0x81
152 #define SESS_POS_RESP 0x82
153 #define SESS_NEG_RESP 0x83
154 #define SESS_RETARGET 0x84
155 #define SESS_KEEPALIVE 0x85
167 typedef struct _nbtsmb
169 u8 msg
; /*** NBT Message ***/
170 u8 flags
; /*** Not much here really ***/
171 u16 length
; /*** Length, excluding NBT ***/
172 u8 smb
[SMB_MAX_TRANSMIT_SIZE
];
176 * Session Information
178 typedef struct _smbsession
197 typedef struct _smbhandle
205 struct sockaddr_in server_addr
;
211 static u32 smb_dialectcnt
= 1;
212 static BOOL smb_inited
= FALSE
;
213 static lwp_objinfo smb_handle_objects
;
214 static lwp_queue smb_filehandle_queue
;
215 static struct _smbfile smb_filehandles
[SMB_FILEHANDLES_MAX
];
216 static const char *smb_dialects
[] = {"NT LM 0.12",NULL
};
218 extern void ntlm_smb_nt_encrypt(const char *passwd
, const u8
* challenge
, u8
* answer
);
221 * SMB Endian aware supporting functions
223 * SMB always uses Intel Little-Endian values, so htons etc are
224 * of little or no use :) ... Thanks M$
227 /*** get unsigned char ***/
228 static __inline__ u8
getUChar(u8
*buffer
,u32 offset
)
230 return (u8
)buffer
[offset
];
233 /*** set unsigned char ***/
234 static __inline__
void setUChar(u8
*buffer
,u32 offset
,u8 value
)
236 buffer
[offset
] = value
;
239 /*** get signed short ***/
240 static __inline__ s16
getShort(u8
*buffer
,u32 offset
)
242 return (s16
)((buffer
[offset
+1]<<8)|(buffer
[offset
]));
245 /*** get unsigned short ***/
246 static __inline__ u16
getUShort(u8
*buffer
,u32 offset
)
248 return (u16
)((buffer
[offset
+1]<<8)|(buffer
[offset
]));
251 /*** set unsigned short ***/
252 static __inline__
void setUShort(u8
*buffer
,u32 offset
,u16 value
)
254 buffer
[offset
] = (value
&0xff);
255 buffer
[offset
+1] = ((value
&0xff00)>>8);
258 /*** get unsigned int ***/
259 static __inline__ u32
getUInt(u8
*buffer
,u32 offset
)
261 return (u32
)((buffer
[offset
+3]<<24)|(buffer
[offset
+2]<<16)|(buffer
[offset
+1]<<8)|buffer
[offset
]);
264 /*** set unsigned int ***/
265 static __inline__
void setUInt(u8
*buffer
,u32 offset
,u32 value
)
267 buffer
[offset
] = (value
&0xff);
268 buffer
[offset
+1] = ((value
&0xff00)>>8);
269 buffer
[offset
+2] = ((value
&0xff0000)>>16);
270 buffer
[offset
+3] = ((value
&0xff000000)>>24);
273 /*** get unsigned long long ***/
274 static __inline__ u64
getULongLong(u8
*buffer
,u32 offset
)
276 return (u64
)(getUInt(buffer
, offset
) | (u64
)getUInt(buffer
, offset
+4) << 32);
279 static __inline__ SMBHANDLE
* __smb_handle_open(SMBCONN smbhndl
)
284 SMB_CHECK_HANDLE(smbhndl
);
286 _CPU_ISR_Disable(level
);
287 handle
= (SMBHANDLE
*)__lwp_objmgr_getnoprotection(&smb_handle_objects
,LWP_OBJMASKID(smbhndl
));
288 _CPU_ISR_Restore(level
);
293 static __inline__
void __smb_handle_free(SMBHANDLE
*handle
)
297 _CPU_ISR_Disable(level
);
298 __lwp_objmgr_close(&smb_handle_objects
,&handle
->object
);
299 __lwp_objmgr_free(&smb_handle_objects
,&handle
->object
);
300 _CPU_ISR_Restore(level
);
303 static void __smb_init()
306 __lwp_objmgr_initinfo(&smb_handle_objects
,SMB_CONNHANDLES_MAX
,sizeof(SMBHANDLE
));
307 __lwp_queue_initialize(&smb_filehandle_queue
,smb_filehandles
,SMB_FILEHANDLES_MAX
,sizeof(struct _smbfile
));
310 static SMBHANDLE
* __smb_allocate_handle()
315 _CPU_ISR_Disable(level
);
316 handle
= (SMBHANDLE
*)__lwp_objmgr_allocate(&smb_handle_objects
);
320 handle
->server_name
= NULL
;
321 handle
->share_name
= NULL
;
322 handle
->sck_server
= INVALID_SOCKET
;
323 handle
->conn_valid
= FALSE
;
324 __lwp_objmgr_open(&smb_handle_objects
,&handle
->object
);
326 _CPU_ISR_Restore(level
);
330 static void __smb_free_handle(SMBHANDLE
*handle
)
332 if(handle
->user
) free(handle
->user
);
333 if(handle
->pwd
) free(handle
->pwd
);
334 if(handle
->server_name
) free(handle
->server_name
);
335 if(handle
->share_name
) free(handle
->share_name
);
339 handle
->server_name
= NULL
;
340 handle
->share_name
= NULL
;
341 handle
->sck_server
= INVALID_SOCKET
;
343 __smb_handle_free(handle
);
346 static void MakeSMBHeader(u8 command
,u8 flags
,u16 flags2
,SMBHANDLE
*handle
)
348 u8
*ptr
= handle
->message
.smb
;
349 NBTSMB
*nbt
= &handle
->message
;
350 SMBSESSION
*sess
= &handle
->session
;
352 memset(nbt
,0,sizeof(NBTSMB
));
354 setUInt(ptr
,SMB_OFFSET_PROTO
,SMB_PROTO
);
355 setUChar(ptr
,SMB_OFFSET_CMD
,command
);
356 setUChar(ptr
,SMB_OFFSET_FLAGS
,flags
);
357 setUShort(ptr
,SMB_OFFSET_FLAGS2
,flags2
);
358 setUShort(ptr
,SMB_OFFSET_TID
,sess
->TID
);
359 setUShort(ptr
,SMB_OFFSET_PID
,sess
->PID
);
360 setUShort(ptr
,SMB_OFFSET_UID
,sess
->UID
);
361 setUShort(ptr
,SMB_OFFSET_MID
,sess
->MID
);
363 ptr
[SMB_HEADER_SIZE
] = 0;
369 static void MakeTRANS2Header(u8 subcommand
,SMBHANDLE
*handle
)
371 u8
*ptr
= handle
->message
.smb
;
372 SMBSESSION
*sess
= &handle
->session
;
374 setUChar(ptr
, T2_WORD_CNT
, 15);
375 setUShort(ptr
, T2_MAXPRM_CNT
, 10);
376 setUShort(ptr
, T2_MAXBUFFER
, sess
->MaxBuffer
);
377 setUChar(ptr
, T2_SSETUP_CNT
, 1);
378 setUShort(ptr
, T2_SUB_CMD
, subcommand
);
384 * blocking call with timeout
385 * will return when ALL data has been sent. Number of bytes sent is returned.
386 * OR timeout. Timeout will return -1
387 * OR network error. -ve value will be returned
389 static inline s32
smb_send(s32 s
,const void *data
,s32 size
)
392 s32 ret
, len
= size
, nextsend
;
394 t1
=ticks_to_millisecs(gettime());
399 if(nextsend
>SMB_MAX_NET_WRITE_SIZE
)
400 nextsend
=SMB_MAX_NET_WRITE_SIZE
; //optimized value
402 ret
=net_send(s
,data
,nextsend
,0);
405 t2
=ticks_to_millisecs(gettime());
406 if( (t2
- t1
) > RECV_TIMEOUT
)
408 return -1; // timeout
410 usleep(100); // allow system to perform work. Stabilizes system
415 return ret
; // an error occurred
421 if(len
==0) return size
;
422 t1
=ticks_to_millisecs(gettime());
431 * blocking call with timeout
432 * will return when ANY data has been read from socket. Number of bytes read is returned.
433 * OR timeout. Timeout will return -1
434 * OR network error. -ve value will be returned
436 static s32
smb_recv(s32 s
,void *mem
,s32 len
)
438 s32 ret
,read
,readtotal
=0;
441 t1
=ticks_to_millisecs(gettime());
445 if(read
>SMB_MAX_NET_READ_SIZE
)
446 read
=SMB_MAX_NET_READ_SIZE
; // optimized value
448 ret
=net_recv(s
,mem
+readtotal
,read
,0);
453 if(len
==0) return readtotal
;
457 if(ret
!=-EAGAIN
) return ret
;
458 t2
=ticks_to_millisecs(gettime());
459 if( (t2
- t1
) > RECV_TIMEOUT
) return -1;
460 usleep(100); // allow system to perform work. Stabilizes system
469 * Do very basic checking on the return SMB
470 * Read <readlen> bytes
471 * if <readlen>==0 then read a single SMB packet
472 * discard any NBT_KEEPALIVE_MSG packets along the way.
474 static s32
SMBCheck(u8 command
, s32 readlen
,SMBHANDLE
*handle
)
477 u8
*ptr
= handle
->message
.smb
;
478 NBTSMB
*nbt
= &handle
->message
;
480 u8 tempLength
= (readlen
==0);
482 if(handle
->sck_server
== INVALID_SOCKET
) return SMB_ERROR
;
484 /* if length is not specified,*/
487 /* read entire header if available. if not, just get whatever available.*/
488 readlen
= SMB_HEADER_SIZE
+4;
491 memset(nbt
,0,sizeof(NBTSMB
));
494 /*keep going till we get all the data we wanted*/
497 ret
=smb_recv(handle
->sck_server
, ptr2
+recvd
, readlen
-recvd
);
503 /* discard any and all keepalive packets */
504 while( (nbt
->msg
==NBT_KEEPALIVE_MSG
) && (recvd
>=KEEPALIVE_SIZE
) )
506 recvd
-=KEEPALIVE_SIZE
;
507 memmove(ptr2
, ptr2
+KEEPALIVE_SIZE
, recvd
);
509 /* obtain required length from NBT header if readlen==0*/
510 if(tempLength
&& recvd
>=KEEPALIVE_SIZE
)
512 /* get the length header */
513 if(nbt
->flags
!=0 || nbt
->length
>SMB_MAX_TRANSMIT_SIZE
)
515 /*length too big to be supported*/
516 return SMB_BAD_DATALEN
;
520 readlen
= nbt
->length
+KEEPALIVE_SIZE
;
526 /*** Do basic SMB Header checks ***/
527 ret
= getUInt(ptr
,SMB_OFFSET_PROTO
);
528 if(ret
!=SMB_PROTO
) return SMB_BAD_PROTOCOL
;
530 ret
= getUChar(ptr
, SMB_OFFSET_CMD
);
531 if(ret
!=command
) return SMB_BAD_COMMAND
;
533 ret
= getUInt(ptr
,SMB_OFFSET_NTSTATUS
);
534 if(ret
) return SMB_ERROR
;
542 * Setup the SMB session, including authentication with the
543 * magic 'NTLM Response'
545 static s32
SMB_SetupAndX(SMBHANDLE
*handle
)
550 u8
*ptr
= handle
->message
.smb
;
551 SMBSESSION
*sess
= &handle
->session
;
552 char pwd
[15], ntRespData
[24];
554 if(handle
->sck_server
== INVALID_SOCKET
) return SMB_ERROR
;
556 MakeSMBHeader(SMB_SETUP_ANDX
,0x08,0x01,handle
);
557 pos
= SMB_HEADER_SIZE
;
559 setUChar(ptr
,pos
,13);
560 pos
++; /*** Word Count ***/
561 setUChar(ptr
,pos
,0xff);
562 pos
++; /*** Next AndX ***/
563 pos
++; /*** Reserved ***/
564 pos
+= 2; /*** Next AndX Offset ***/
565 setUShort(ptr
,pos
,sess
->MaxBuffer
);
567 setUShort(ptr
,pos
,sess
->MaxMpx
);
569 setUShort(ptr
,pos
,sess
->MaxVCS
);
571 setUInt(ptr
,pos
,sess
->sKey
);
573 setUShort(ptr
,pos
,0); /*** Password length (case-insensitive) ***/
575 setUShort(ptr
,pos
,24); /*** Password length (case-sensitive) ***/
577 pos
+= 4; /*** Reserved ***/
578 pos
+= 4; /*** Capabilities ***/
580 pos
+= 2; /*** Byte count ***/
582 /*** The magic 'NTLM Response' ***/
583 strcpy(pwd
, handle
->pwd
);
584 if (sess
->challengeUsed
)
585 ntlm_smb_nt_encrypt((const char *) pwd
, (const u8
*) sess
->challenge
, (u8
*) ntRespData
);
587 /*** Build information ***/
588 memcpy(&ptr
[pos
],ntRespData
,24);
592 strcpy(pwd
, handle
->user
);
593 for(i
=0;i
<strlen(pwd
);i
++) pwd
[i
] = toupper((int)pwd
[i
]);
594 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
595 pos
+= strlen(pwd
)+1;
597 /*** Primary Domain ***/
598 if(handle
->user
[0]=='\0') sess
->p_domain
[0] = '\0';
599 memcpy(&ptr
[pos
],sess
->p_domain
,strlen((const char*)sess
->p_domain
));
600 pos
+= strlen((const char*)sess
->p_domain
)+1;
603 strcpy(pwd
,"Unix (libOGC)");
604 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
605 pos
+= strlen(pwd
)+1;
607 /*** Native LAN Manager ***/
608 strcpy(pwd
,"Nintendo Wii");
609 memcpy(&ptr
[pos
],pwd
,strlen(pwd
));
610 pos
+= strlen (pwd
)+1;
612 /*** Update byte count ***/
613 setUShort(ptr
,bcpos
,((pos
-bcpos
)-2));
615 handle
->message
.msg
= NBT_SESSISON_MSG
;
616 handle
->message
.length
= htons (pos
);
619 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
620 if(ret
<=0) return SMB_ERROR
;
622 if((ret
=SMBCheck(SMB_SETUP_ANDX
,0,handle
))==SMB_SUCCESS
) {
623 /*** Collect UID ***/
624 sess
->UID
= getUShort(handle
->message
.smb
,SMB_OFFSET_UID
);
633 * Finally, net_connect to the remote share
635 static s32
SMB_TreeAndX(SMBHANDLE
*handle
)
639 u8
*ptr
= handle
->message
.smb
;
640 SMBSESSION
*sess
= &handle
->session
;
642 if(handle
->sck_server
== INVALID_SOCKET
) return SMB_ERROR
;
644 MakeSMBHeader(SMB_TREEC_ANDX
,0x08,0x01,handle
);
645 pos
= SMB_HEADER_SIZE
;
648 pos
++; /*** Word Count ***/
649 setUChar(ptr
,pos
,0xff);
650 pos
++; /*** Next AndX ***/
651 pos
++; /*** Reserved ***/
652 pos
+= 2; /*** Next AndX Offset ***/
653 pos
+= 2; /*** Flags ***/
654 setUShort(ptr
,pos
,1);
655 pos
+= 2; /*** Password Length ***/
658 pos
++; /*** NULL Password ***/
660 /*** Build server share path ***/
661 strcpy ((char*)path
, "\\\\");
662 strcat ((char*)path
, handle
->server_name
);
663 strcat ((char*)path
, "\\");
664 strcat ((char*)path
, handle
->share_name
);
665 for(ret
=0;ret
<strlen((const char*)path
);ret
++) path
[ret
] = toupper(path
[ret
]);
667 memcpy(&ptr
[pos
],path
,strlen((const char*)path
));
668 pos
+= strlen((const char*)path
)+1;
671 strcpy((char*)path
,"?????");
672 memcpy(&ptr
[pos
],path
,strlen((const char*)path
));
673 pos
+= strlen((const char*)path
)+1;
675 /*** Update byte count ***/
676 setUShort(ptr
,bcpos
,(pos
-bcpos
)-2);
678 handle
->message
.msg
= NBT_SESSISON_MSG
;
679 handle
->message
.length
= htons (pos
);
682 ret
= smb_send(handle
->sck_server
,(char *)&handle
->message
,pos
);
683 if(ret
<=0) return SMB_ERROR
;
685 if((ret
=SMBCheck(SMB_TREEC_ANDX
,0,handle
))==SMB_SUCCESS
) {
686 /*** Collect Tree ID ***/
687 sess
->TID
= getUShort(handle
->message
.smb
,SMB_OFFSET_TID
);
694 * SMB_NegotiateProtocol
696 * The only protocol we admit to is 'NT LM 0.12'
698 static s32
SMB_NegotiateProtocol(const char *dialects
[],int dialectc
,SMBHANDLE
*handle
)
708 if(!handle
|| !dialects
|| dialectc
<=0)
711 if(handle
->sck_server
== INVALID_SOCKET
) return SMB_ERROR
;
713 /*** Clear session variables ***/
714 sess
= &handle
->session
;
715 memset(sess
,0,sizeof(SMBSESSION
));
719 MakeSMBHeader(SMB_NEG_PROTOCOL
,0x08,0x01,handle
);
721 pos
= SMB_HEADER_SIZE
+3;
722 ptr
= handle
->message
.smb
;
723 for(i
=0,bcnt
=0;i
<dialectc
;i
++) {
724 len
= strlen(dialects
[i
])+1;
726 memcpy(&ptr
[pos
],dialects
[i
],len
);
730 /*** Update byte count ***/
731 setUShort(ptr
,(SMB_HEADER_SIZE
+1),bcnt
);
733 /*** Set NBT information ***/
734 handle
->message
.msg
= NBT_SESSISON_MSG
;
735 handle
->message
.length
= htons(pos
);
738 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
739 if(ret
<=0) return SMB_ERROR
;
741 /*** Check response ***/
742 if((ret
=SMBCheck(SMB_NEG_PROTOCOL
,0,handle
))==SMB_SUCCESS
)
744 pos
= SMB_HEADER_SIZE
;
745 ptr
= handle
->message
.smb
;
747 /*** Collect information ***/
748 if(getUChar(ptr
,pos
)!=17) return SMB_PROTO_FAIL
; // UCHAR WordCount; Count of parameter words = 17
751 if(getUShort(ptr
,pos
)!=0) return SMB_PROTO_FAIL
; // USHORT DialectIndex; Index of selected dialect - should always be 0 since we only supplied 1!
754 if(getUChar(ptr
,pos
)!=3)
756 // user level security
760 // share level security
764 sess
->MaxMpx
= getUShort(ptr
, pos
); //USHORT MaxMpxCount; Max pending outstanding requests
767 sess
->MaxVCS
= getUShort(ptr
, pos
); //USHORT MaxNumberVcs; Max VCs between client and server
770 serverMaxBuffer
= getUInt(ptr
, pos
); //ULONG MaxBufferSize; Max transmit buffer size
772 if(serverMaxBuffer
>SMB_MAX_TRANSMIT_SIZE
)
773 sess
->MaxBuffer
= SMB_MAX_TRANSMIT_SIZE
;
775 sess
->MaxBuffer
= serverMaxBuffer
;
778 pos
+= 4; //ULONG MaxRawSize; Maximum raw buffer size
779 sess
->sKey
= getUInt(ptr
,pos
); pos
+= 4;
780 pos
+= 4; //ULONG Capabilities; Server capabilities
781 pos
+= 4; //ULONG SystemTimeLow; System (UTC) time of the server (low).
782 pos
+= 4; //ULONG SystemTimeHigh; System (UTC) time of the server (high).
783 sess
->timeOffset
= getShort(ptr
,pos
) * 600000000LL; pos
+= 2; //SHORT ServerTimeZone; Time zone of server (minutes from UTC)
785 //UCHAR EncryptionKeyLength - 0 or 8
786 if(getUChar(ptr
,pos
)!=8)
788 if (getUChar(ptr
,pos
)!=0)
790 return SMB_BAD_KEYLEN
;
794 // Challenge key not used
795 sess
->challengeUsed
= false;
800 sess
->challengeUsed
= true;
804 bytecount
= getUShort(ptr
,pos
);
806 if (sess
->challengeUsed
)
808 /*** Copy challenge key ***/
810 memcpy(&sess
->challenge
,&ptr
[pos
],8);
813 /*** Primary domain ***/
816 while(ptr
[pos
+j
]!=0) {
817 sess
->p_domain
[i
] = ptr
[pos
+j
];
821 sess
->p_domain
[i
] = '\0';
829 static s32
do_netconnect(SMBHANDLE
*handle
)
837 handle
->sck_server
= INVALID_SOCKET
;
838 /*** Create the global net_socket ***/
839 sock
= net_socket(AF_INET
, SOCK_STREAM
, IPPROTO_IP
);
840 if(sock
==INVALID_SOCKET
) return -1;
842 /*** Switch off Nagle, ON TCP_NODELAY ***/
844 ret
= net_setsockopt(sock
,IPPROTO_TCP
,TCP_NODELAY
,&nodelay
,sizeof(nodelay
));
846 //create non blocking socket
847 flags
= net_fcntl(sock
, F_GETFL
, 0);
848 flags
|= IOS_O_NONBLOCK
;
849 ret
=net_fcntl(sock
, F_SETFL
, flags
);
851 t1
=ticks_to_millisecs(gettime());
854 ret
= net_connect(sock
,(struct sockaddr
*)&handle
->server_addr
,sizeof(handle
->server_addr
));
856 t2
=ticks_to_millisecs(gettime());
858 if(t2
-t1
> 3000) break; // 3 secs to try to connect to handle->server_addr
867 handle
->sck_server
= sock
;
871 static s32
do_smbconnect(SMBHANDLE
*handle
)
875 if(handle
->sck_server
== INVALID_SOCKET
) return -1;
877 ret
= SMB_NegotiateProtocol(smb_dialects
,smb_dialectcnt
,handle
);
880 net_close(handle
->sck_server
);
881 handle
->sck_server
= INVALID_SOCKET
;
885 ret
= SMB_SetupAndX(handle
);
888 net_close(handle
->sck_server
);
889 handle
->sck_server
= INVALID_SOCKET
;
893 ret
= SMB_TreeAndX(handle
);
896 net_close(handle
->sck_server
);
897 handle
->sck_server
= INVALID_SOCKET
;
901 handle
->conn_valid
= TRUE
;
905 /****************************************************************************
906 * Create an NBT SESSION REQUEST message.
907 ****************************************************************************/
908 static int MakeSessReq(unsigned char *bufr
, unsigned char *Called
, unsigned char *Calling
)
914 bufr
[3] = 68; // 2x34 bytes in length.
916 // Copy the Called and Calling names into the buffer.
917 (void) memcpy(&bufr
[4], Called
, 34);
918 (void) memcpy(&bufr
[38], Calling
, 34);
920 // Return the total message length.
924 static unsigned char *L1_Encode(unsigned char *dst
, const unsigned char *name
,
925 const unsigned char pad
, const unsigned char sfx
)
931 while (('\0' != name
[i
]) && (i
< 15))
933 k
= toupper(name
[i
++]);
934 dst
[j
++] = 'A' + ((k
& 0xF0) >> 4);
935 dst
[j
++] = 'A' + (k
& 0x0F);
938 i
= 'A' + ((pad
& 0xF0) >> 4);
939 k
= 'A' + (pad
& 0x0F);
946 dst
[30] = 'A' + ((sfx
& 0xF0) >> 4);
947 dst
[31] = 'A' + (sfx
& 0x0F);
953 static int L2_Encode(unsigned char *dst
, const unsigned char *name
,
954 const unsigned char pad
, const unsigned char sfx
,
955 const unsigned char *scope
)
961 if (NULL
== L1_Encode(&dst
[1], name
, pad
, sfx
))
971 for (i
= 0, j
= (lenpos
+ 1); ('.' != scope
[i
]) && ('\0'
972 != scope
[i
]); i
++, j
++)
973 dst
[j
] = toupper(scope
[i
]);
975 dst
[lenpos
] = (unsigned char) i
;
978 } while ('.' == *(scope
++));
986 /****************************************************************************
987 * Send an NBT SESSION REQUEST over the TCP connection, then wait for a reply.
988 ****************************************************************************/
989 static s32
SMB_RequestNBTSession(SMBHANDLE
*handle
)
991 unsigned char Called
[34];
992 unsigned char Calling
[34];
993 unsigned char bufr
[128];
996 if(handle
->sck_server
== INVALID_SOCKET
) return -1;
998 L2_Encode(Called
, (const unsigned char*) "*SMBSERVER", 0x20, 0x20,
999 (const unsigned char*) "");
1000 L2_Encode(Calling
, (const unsigned char*) "SMBCLIENT", 0x20, 0x00,
1001 (const unsigned char*) "");
1003 // Create the NBT Session Request message.
1004 result
= MakeSessReq(bufr
, Called
, Calling
);
1006 //Send the NBT Session Request message.
1007 result
= smb_send(handle
->sck_server
, bufr
, result
);
1010 // Error sending Session Request message
1014 // Now wait for and handle the reply (2 seconds).
1015 result
= smb_recv(handle
->sck_server
, bufr
, 128);
1018 // Timeout waiting for NBT Session Response
1025 // Positive Session Response
1029 // Negative Session Response
1033 // Retarget Session Response
1037 // Unexpected Session Response
1042 /****************************************************************************
1043 * Primary setup, logon and connection all in one :)
1044 ****************************************************************************/
1045 s32
SMB_Connect(SMBCONN
*smbhndl
, const char *user
, const char *password
, const char *share
, const char *server
)
1052 *smbhndl
= SMB_HANDLE_NULL
;
1054 if(!user
|| !password
|| !share
|| !server
||
1055 strlen(user
) > 20 || strlen(password
) > 14 ||
1056 strlen(share
) > 80 || strlen(server
) > 80)
1058 return SMB_BAD_LOGINDATA
;
1061 if(smb_inited
==FALSE
)
1064 _CPU_ISR_Disable(level
);
1066 _CPU_ISR_Restore(level
);
1069 handle
= __smb_allocate_handle();
1070 if(!handle
) return SMB_ERROR
;
1072 handle
->user
= strdup(user
);
1073 handle
->pwd
= strdup(password
);
1074 handle
->server_name
= strdup(server
);
1075 handle
->share_name
= strdup(share
);
1076 handle
->server_addr
.sin_family
= AF_INET
;
1077 handle
->server_addr
.sin_port
= htons(445);
1079 if(strlen(server
) < 16 && inet_aton(server
, &val
))
1081 handle
->server_addr
.sin_addr
.s_addr
= val
.s_addr
;
1083 else // might be a hostname
1085 hp
= net_gethostbyname(server
);
1086 if (!hp
|| !(hp
->h_addrtype
== PF_INET
))
1087 ret
= SMB_BAD_LOGINDATA
;
1089 memcpy((char *)&handle
->server_addr
.sin_addr
.s_addr
, hp
->h_addr_list
[0], hp
->h_length
);
1092 *smbhndl
=(SMBCONN
)(LWP_OBJMASKTYPE(SMB_OBJTYPE_HANDLE
)|LWP_OBJMASKID(handle
->object
.id
));
1096 ret
= do_netconnect(handle
);
1097 if(ret
==0) ret
= do_smbconnect(handle
);
1102 handle
->server_addr
.sin_port
= htons(139);
1103 ret
= do_netconnect(handle
);
1104 if(ret
==0) ret
= SMB_RequestNBTSession(handle
);
1105 if(ret
==0) ret
= do_smbconnect(handle
);
1110 handle
->server_addr
.sin_port
= 0;
1117 /****************************************************************************
1120 * Probably NEVER called on GameCube, but here for completeness
1121 ****************************************************************************/
1122 void SMB_Close(SMBCONN smbhndl
)
1126 handle
= __smb_handle_open(smbhndl
);
1129 if(handle
->sck_server
!=INVALID_SOCKET
) net_close(handle
->sck_server
);
1130 __smb_free_handle(handle
);
1133 s32
SMB_Reconnect(SMBCONN
*_smbhndl
, BOOL test_conn
)
1135 s32 ret
= SMB_SUCCESS
;
1136 SMBCONN smbhndl
= *_smbhndl
;
1137 SMBHANDLE
*handle
= __smb_handle_open(smbhndl
);
1139 return SMB_ERROR
; // we have no handle, so we can't reconnect
1141 if(handle
->conn_valid
&& test_conn
)
1144 if(SMB_PathInfo("\\", &dentry
, smbhndl
)==SMB_SUCCESS
) return SMB_SUCCESS
; // no need to reconnect
1145 handle
->conn_valid
= FALSE
; // else connection is invalid
1147 if(!handle
->conn_valid
)
1149 // shut down connection
1150 if(handle
->sck_server
!=INVALID_SOCKET
)
1152 net_close(handle
->sck_server
);
1153 handle
->sck_server
= INVALID_SOCKET
;
1157 if(handle
->server_addr
.sin_port
> 0)
1159 ret
= do_netconnect(handle
);
1160 if(ret
==0 && handle
->server_addr
.sin_port
== htons(139))
1161 ret
= SMB_RequestNBTSession(handle
);
1163 ret
= do_smbconnect(handle
);
1165 else // initial connection
1167 handle
->server_addr
.sin_port
= htons(445);
1168 ret
= do_netconnect(handle
);
1169 if(ret
==0) ret
= do_smbconnect(handle
);
1174 handle
->server_addr
.sin_port
= htons(139);
1175 ret
= do_netconnect(handle
);
1176 if(ret
==0) ret
= SMB_RequestNBTSession(handle
);
1177 if(ret
==0) ret
= do_smbconnect(handle
);
1181 handle
->server_addr
.sin_port
= 0;
1187 SMBFILE
SMB_OpenFile(const char *filename
, u16 access
, u16 creation
,SMBCONN smbhndl
)
1192 struct _smbfile
*fid
= NULL
;
1196 if(filename
== NULL
)
1199 if(SMB_Reconnect(&smbhndl
,TRUE
)!=SMB_SUCCESS
) return NULL
;
1201 handle
= __smb_handle_open(smbhndl
);
1202 if(!handle
) return NULL
;
1204 MakeSMBHeader(SMB_OPEN_ANDX
,0x08,0x01,handle
);
1206 pos
= SMB_HEADER_SIZE
;
1207 ptr
= handle
->message
.smb
;
1208 setUChar(ptr
, pos
, 15);
1209 pos
++; /*** Word Count ***/
1210 setUChar(ptr
, pos
, 0xff);
1211 pos
++; /*** Next AndX ***/
1212 pos
+= 3; /*** Next AndX Offset ***/
1214 pos
+= 2; /*** Flags ***/
1215 setUShort(ptr
, pos
, access
);
1216 pos
+= 2; /*** Access mode ***/
1217 setUShort(ptr
, pos
, 0x6);
1218 pos
+= 2; /*** Type of file ***/
1219 pos
+= 2; /*** Attributes ***/
1220 pos
+= 4; /*** File time - don't care - let server decide ***/
1221 setUShort(ptr
, pos
, creation
);
1222 pos
+= 2; /*** Creation flags ***/
1223 pos
+= 4; /*** Allocation size ***/
1224 pos
+= 8; /*** Reserved ***/
1225 pos
+= 2; /*** Byte Count ***/
1228 if (filename
[0] != '\\') {
1229 strcpy(realfile
, "\\");
1230 strcat(realfile
,filename
);
1232 strcpy(realfile
,filename
);
1234 memcpy(&ptr
[pos
],realfile
,strlen(realfile
));
1235 pos
+= strlen(realfile
)+1;
1237 setUShort(ptr
,(bpos
-2),(pos
-bpos
));
1239 handle
->message
.msg
= NBT_SESSISON_MSG
;
1240 handle
->message
.length
= htons(pos
);
1243 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1244 if(ret
<0) goto failed
;
1246 if(SMBCheck(SMB_OPEN_ANDX
,0,handle
)==SMB_SUCCESS
) {
1247 /*** Check file handle ***/
1248 fid
= (struct _smbfile
*)__lwp_queue_get(&smb_filehandle_queue
);
1250 fid
->conn
= smbhndl
;
1251 fid
->sfid
= getUShort(handle
->message
.smb
,(SMB_HEADER_SIZE
+5));
1254 return (SMBFILE
)fid
;
1257 handle
->conn_valid
= FALSE
;
1264 void SMB_CloseFile(SMBFILE sfid
)
1269 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
1273 handle
= __smb_handle_open(fid
->conn
);
1276 MakeSMBHeader(SMB_CLOSE
,0x08,0x01,handle
);
1278 pos
= SMB_HEADER_SIZE
;
1279 ptr
= handle
->message
.smb
;
1280 setUChar(ptr
, pos
, 3);
1281 pos
++; /** Word Count **/
1282 setUShort(ptr
, pos
, fid
->sfid
);
1284 setUInt(ptr
, pos
, 0xffffffff);
1285 pos
+= 4; /*** Last Write ***/
1286 pos
+= 2; /*** Byte Count ***/
1288 handle
->message
.msg
= NBT_SESSISON_MSG
;
1289 handle
->message
.length
= htons(pos
);
1292 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1293 if(ret
<0) handle
->conn_valid
= FALSE
;
1294 else SMBCheck(SMB_CLOSE
,0,handle
);
1295 __lwp_queue_append(&smb_filehandle_queue
,&fid
->node
);
1301 s32
SMB_ReadFile(char *buffer
, size_t size
, off_t offset
, SMBFILE sfid
)
1307 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
1311 // Check for invalid size
1312 if(size
== 0 || size
> SMB_MAX_BUFFERSIZE
) return -1;
1314 handle
= __smb_handle_open(fid
->conn
);
1315 if(!handle
) return -1;
1317 MakeSMBHeader(SMB_READ_ANDX
,0x08,0x01,handle
);
1319 pos
= SMB_HEADER_SIZE
;
1320 ptr
= handle
->message
.smb
;
1321 setUChar(ptr
, pos
, 12);
1322 pos
++; /*** Word count ***/
1323 setUChar(ptr
, pos
, 0xff);
1325 pos
+= 3; /*** Reserved, Next AndX Offset ***/
1326 setUShort(ptr
, pos
, fid
->sfid
);
1327 pos
+= 2; /*** FID ***/
1328 setUInt(ptr
, pos
, offset
& 0xffffffff);
1329 pos
+= 4; /*** Offset ***/
1331 setUShort(ptr
, pos
, size
& 0xffff);
1333 setUShort(ptr
, pos
, size
& 0xffff);
1335 setUInt(ptr
, pos
, 0);
1337 pos
+= 2; /*** Remaining ***/
1338 setUInt(ptr
, pos
, offset
>> 32); // offset high
1340 pos
+= 2; /*** Byte count ***/
1342 handle
->message
.msg
= NBT_SESSISON_MSG
;
1343 handle
->message
.length
= htons(pos
);
1347 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
, pos
);
1348 if(ret
<0) goto failed
;
1350 /*** SMBCheck should now only read up to the end of a standard header ***/
1351 if((ret
=SMBCheck(SMB_READ_ANDX
,(SMB_HEADER_SIZE
+27+4),handle
))==SMB_SUCCESS
) {
1352 ptr
= handle
->message
.smb
;
1353 /*** Retrieve data length for this packet ***/
1354 length
= getUShort(ptr
,(SMB_HEADER_SIZE
+11));
1355 /*** Retrieve offset to data ***/
1356 ofs
= getUShort(ptr
,(SMB_HEADER_SIZE
+13));
1358 /*** Default offset, with no padding is 63, so grab any outstanding padding ***/
1359 while(ofs
>SMB_DEF_READOFFSET
) {
1361 ret
= smb_recv(handle
->sck_server
,pad
,(ofs
-SMB_DEF_READOFFSET
));
1362 if(ret
<0) goto failed
;
1366 /*** Finally, go grab the data ***/
1372 ret
=smb_recv(handle
->sck_server
,&dest
[ofs
],length
-ofs
);
1373 if(ret
<0) goto failed
;
1375 if (ofs
>=length
) break;
1383 handle
->conn_valid
= FALSE
;
1390 s32
SMB_WriteFile(const char *buffer
, size_t size
, off_t offset
, SMBFILE sfid
)
1397 struct _smbfile
*fid
= (struct _smbfile
*)sfid
;
1401 handle
= __smb_handle_open(fid
->conn
);
1402 if(!handle
) return -1;
1404 MakeSMBHeader(SMB_WRITE_ANDX
,0x08,0x01,handle
);
1406 pos
= SMB_HEADER_SIZE
;
1407 ptr
= handle
->message
.smb
;
1408 setUChar(ptr
, pos
, 14);
1409 pos
++; /*** Word Count ***/
1410 setUChar(ptr
, pos
, 0xff);
1411 pos
+= 2; /*** Next AndX ***/
1412 pos
+= 2; /*** Next AndX Offset ***/
1414 setUShort(ptr
, pos
, fid
->sfid
);
1416 setUInt(ptr
, pos
, offset
& 0xffffffff);
1418 setUInt(ptr
, pos
, 0); /*** Reserved, must be 0 ***/
1420 setUShort(ptr
, pos
, 0); /*** Write Mode ***/
1422 pos
+= 2; /*** Remaining ***/
1424 blocks64
= size
>> 16;
1426 setUShort(ptr
, pos
, blocks64
);
1427 pos
+= 2; /*** Length High ***/
1428 setUShort(ptr
, pos
, size
& 0xffff);
1429 pos
+= 2; /*** Length Low ***/
1430 setUShort(ptr
, pos
, 63);
1431 pos
+= 2; /*** Data Offset ***/
1432 setUInt(ptr
, pos
, offset
>> 32); /*** OffsetHigh ***/
1434 setUShort(ptr
, pos
, size
& 0xffff);
1435 pos
+= 2; /*** Data Byte Count ***/
1437 handle
->message
.msg
= NBT_SESSISON_MSG
;
1438 handle
->message
.length
= htons(pos
+size
);
1442 if((copy_len
+pos
)>SMB_MAX_TRANSMIT_SIZE
) copy_len
= (SMB_MAX_TRANSMIT_SIZE
-pos
);
1444 memcpy(&ptr
[pos
],src
,copy_len
);
1451 /*** Send Header Information ***/
1452 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1453 if(ret
<0) goto failed
;
1456 /*** Send the data ***/
1457 ret
= smb_send(handle
->sck_server
,src
,size
);
1458 if(ret
<0) goto failed
;
1462 if(SMBCheck(SMB_WRITE_ANDX
,0,handle
)==SMB_SUCCESS
) {
1463 ptr
= handle
->message
.smb
;
1464 ret
= getUShort(ptr
,(SMB_HEADER_SIZE
+5));
1470 handle
->conn_valid
= FALSE
;
1477 s32
SMB_PathInfo(const char *filename
, SMBDIRENTRY
*sdir
, SMBCONN smbhndl
)
1486 if(filename
== NULL
)
1489 handle
= __smb_handle_open(smbhndl
);
1490 if (!handle
) return SMB_ERROR
;
1492 MakeSMBHeader(SMB_TRANS2
, 0x08, 0x01, handle
);
1493 MakeTRANS2Header(SMB_QUERY_PATH_INFO
, handle
);
1495 bpos
= pos
= (T2_BYTE_CNT
+ 2);
1496 pos
+= 3; /*** Padding ***/
1497 ptr
= handle
->message
.smb
;
1498 setUShort(ptr
, pos
, SMB_QUERY_FILE_ALL_INFO
);
1501 setUInt(ptr
, pos
, 0);
1502 pos
+= 4; /*** reserved ***/
1504 if (filename
[0] != '\\') {
1505 strcpy(realfile
, "\\");
1506 strcat(realfile
, filename
);
1508 strcpy(realfile
, filename
);
1510 memcpy(&ptr
[pos
], realfile
, strlen(realfile
));
1511 pos
+= strlen(realfile
) + 1; /*** Include padding ***/
1513 /*** Update counts ***/
1514 setUShort(ptr
, T2_PRM_CNT
, (7 + strlen(realfile
)));
1515 setUShort(ptr
, T2_SPRM_CNT
, (7 + strlen(realfile
)));
1516 setUShort(ptr
, T2_SPRM_OFS
, 68);
1517 setUShort(ptr
, T2_SDATA_OFS
, (75 + strlen(realfile
)));
1518 setUShort(ptr
, T2_BYTE_CNT
, (pos
- bpos
));
1520 handle
->message
.msg
= NBT_SESSISON_MSG
;
1521 handle
->message
.length
= htons(pos
);
1524 ret
= smb_send(handle
->sck_server
, (char*) &handle
->message
, pos
);
1525 if(ret
<0) goto failed
;
1528 if (SMBCheck(SMB_TRANS2
, 0, handle
) == SMB_SUCCESS
) {
1530 ptr
= handle
->message
.smb
;
1531 /*** Get parameter offset ***/
1532 pos
= getUShort(ptr
, (SMB_HEADER_SIZE
+ 9));
1533 pos
+= 4; // padding
1534 sdir
->ctime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - creation time
1535 sdir
->atime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - access time
1536 sdir
->mtime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - write time
1537 pos
+= 8; // ULONGLONG - change time
1538 sdir
->attributes
= getUInt(ptr
,pos
); pos
+= 4; // ULONG - file attributes
1539 pos
+= 4; // padding
1540 pos
+= 8; // ULONGLONG - allocated file size
1541 sdir
->size
= getULongLong(ptr
, pos
); pos
+= 8; // ULONGLONG - file size
1542 pos
+= 4; // ULONG NumberOfLinks;
1543 pos
+= 2; // UCHAR DeletePending;
1544 pos
+= 2; // UCHAR Directory;
1545 pos
+= 2; // USHORT Pad2; // for alignment only
1546 pos
+= 4; // ULONG EaSize;
1547 pos
+= 4; // ULONG FileNameLength;
1549 strcpy(sdir
->name
,realfile
);
1556 handle
->conn_valid
= FALSE
;
1563 * Uses TRANS2 to support long filenames
1565 s32
SMB_FindFirst(const char *filename
, unsigned short flags
, SMBDIRENTRY
*sdir
, SMBCONN smbhndl
)
1574 if(filename
== NULL
)
1577 if(SMB_Reconnect(&smbhndl
,TRUE
)!=SMB_SUCCESS
) return SMB_ERROR
;
1579 handle
= __smb_handle_open(smbhndl
);
1580 if(!handle
) return SMB_ERROR
;
1582 sess
= &handle
->session
;
1583 MakeSMBHeader(SMB_TRANS2
,0x08,0x01,handle
);
1584 MakeTRANS2Header(SMB_FIND_FIRST2
,handle
);
1586 bpos
= pos
= (T2_BYTE_CNT
+2);
1587 pos
+= 3; /*** Padding ***/
1588 ptr
= handle
->message
.smb
;
1589 setUShort(ptr
, pos
, flags
);
1590 pos
+= 2; /*** Flags ***/
1591 setUShort(ptr
, pos
, 1);
1592 pos
+= 2; /*** Count ***/
1593 setUShort(ptr
, pos
, 6);
1594 pos
+= 2; /*** Internal Flags ***/
1595 setUShort(ptr
, pos
, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
1596 pos
+= 2; /*** Level of Interest ***/
1597 pos
+= 4; /*** Storage Type == 0 ***/
1598 memcpy(&ptr
[pos
], filename
, strlen(filename
));
1599 pos
+= strlen(filename
)+1; /*** Include padding ***/
1601 /*** Update counts ***/
1602 setUShort(ptr
, T2_PRM_CNT
, (13+strlen(filename
)));
1603 setUShort(ptr
, T2_SPRM_CNT
, (13+strlen(filename
)));
1604 setUShort(ptr
, T2_SPRM_OFS
, 68);
1605 setUShort(ptr
, T2_SDATA_OFS
,(81+strlen(filename
)));
1606 setUShort(ptr
, T2_BYTE_CNT
,(pos
-bpos
));
1608 handle
->message
.msg
= NBT_SESSISON_MSG
;
1609 handle
->message
.length
= htons(pos
);
1612 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1613 if(ret
<0) goto failed
;
1619 if(SMBCheck(SMB_TRANS2
,0,handle
)==SMB_SUCCESS
) {
1620 ptr
= handle
->message
.smb
;
1621 /*** Get parameter offset ***/
1622 pos
= getUShort(ptr
,(SMB_HEADER_SIZE
+9));
1623 sess
->sid
= getUShort(ptr
, pos
); pos
+= 2;
1624 sess
->count
= getUShort(ptr
, pos
); pos
+= 2;
1625 sess
->eos
= getUShort(ptr
, pos
); pos
+= 2;
1626 pos
+= 2; // USHORT EaErrorOffset;
1627 pos
+= 2; // USHORT LastNameOffset;
1628 pos
+= 2; // padding?
1632 pos
+= 4; // ULONG NextEntryOffset;
1633 pos
+= 4; // ULONG FileIndex;
1634 sdir
->ctime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - creation time
1635 sdir
->atime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - access time
1636 sdir
->mtime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - write time
1637 pos
+= 8; // ULONGLONG - change time low
1638 sdir
->size
= getULongLong(ptr
, pos
); pos
+= 8;
1640 sdir
->attributes
= getUInt(ptr
, pos
); pos
+= 4;
1642 strcpy(sdir
->name
, (const char*)&ptr
[pos
]);
1650 handle
->conn_valid
= FALSE
;
1657 s32
SMB_FindNext(SMBDIRENTRY
*sdir
,SMBCONN smbhndl
)
1666 handle
= __smb_handle_open(smbhndl
);
1667 if(!handle
) return SMB_ERROR
;
1669 sess
= &handle
->session
;
1670 if(sess
->eos
|| sess
->sid
==0) return SMB_ERROR
;
1672 MakeSMBHeader(SMB_TRANS2
,0x08,0x01,handle
);
1673 MakeTRANS2Header(SMB_FIND_NEXT2
,handle
);
1675 bpos
= pos
= (T2_BYTE_CNT
+2);
1676 pos
+= 3; /*** Padding ***/
1677 ptr
= handle
->message
.smb
;
1678 setUShort(ptr
, pos
, sess
->sid
);
1679 pos
+= 2; /*** Search ID ***/
1680 setUShort(ptr
, pos
, 1);
1681 pos
+= 2; /*** Count ***/
1682 setUShort(ptr
, pos
, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
1683 pos
+= 2; /*** Level of Interest ***/
1684 pos
+= 4; /*** Storage Type == 0 ***/
1685 setUShort(ptr
, pos
, 12);
1686 pos
+=2; /*** Search flags ***/
1689 /*** Update counts ***/
1690 setUShort(ptr
, T2_PRM_CNT
, 13);
1691 setUShort(ptr
, T2_SPRM_CNT
, 13);
1692 setUShort(ptr
, T2_SPRM_OFS
, 68);
1693 setUShort(ptr
, T2_SDATA_OFS
, 81);
1694 setUShort(ptr
, T2_BYTE_CNT
, (pos
-bpos
));
1696 handle
->message
.msg
= NBT_SESSISON_MSG
;
1697 handle
->message
.length
= htons(pos
);
1700 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1701 if(ret
<0) goto failed
;
1704 if (SMBCheck(SMB_TRANS2
,0,handle
)==SMB_SUCCESS
) {
1705 ptr
= handle
->message
.smb
;
1706 /*** Get parameter offset ***/
1707 pos
= getUShort(ptr
,(SMB_HEADER_SIZE
+9));
1708 sess
->count
= getUShort(ptr
, pos
); pos
+= 2;
1709 sess
->eos
= getUShort(ptr
, pos
); pos
+= 2;
1710 pos
+= 2; // USHORT EaErrorOffset;
1711 pos
+= 2; // USHORT LastNameOffset;
1715 pos
+= 4; // ULONG NextEntryOffset;
1716 pos
+= 4; // ULONG FileIndex;
1717 sdir
->ctime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - creation time
1718 sdir
->atime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - access time
1719 sdir
->mtime
= getULongLong(ptr
, pos
) - handle
->session
.timeOffset
; pos
+= 8; // ULONGLONG - write time
1720 pos
+= 8; // ULONGLONG - change time low
1721 sdir
->size
= getULongLong(ptr
, pos
); pos
+= 8;
1723 sdir
->attributes
= getUInt(ptr
, pos
); pos
+= 4;
1725 strcpy (sdir
->name
, (const char*)&ptr
[pos
]);
1733 handle
->conn_valid
= FALSE
;
1740 s32
SMB_FindClose(SMBCONN smbhndl
)
1748 handle
= __smb_handle_open(smbhndl
);
1749 if(!handle
) return SMB_ERROR
;
1751 sess
= &handle
->session
;
1752 if(sess
->sid
==0) return SMB_ERROR
;
1754 MakeSMBHeader(SMB_FIND_CLOSE2
,0x08,0x01,handle
);
1756 pos
= SMB_HEADER_SIZE
;
1757 ptr
= handle
->message
.smb
;
1758 setUChar(ptr
, pos
, 1);
1759 pos
++; /*** Word Count ***/
1760 setUShort(ptr
, pos
, sess
->sid
);
1762 pos
+= 2; /*** Byte Count ***/
1764 handle
->message
.msg
= NBT_SESSISON_MSG
;
1765 handle
->message
.length
= htons(pos
);
1768 ret
= smb_send(handle
->sck_server
,(char*)&handle
->message
,pos
);
1769 if(ret
<0) goto failed
;
1771 ret
= SMBCheck(SMB_FIND_CLOSE2
,0,handle
);
1775 handle
->conn_valid
= FALSE
;