tinysmb - add error checking on input params, add DNS lookup, fallback to port 139
[libogc.git] / libtinysmb / smb.c
blob40849d97c9c7cbbbffcfd09d413dbbbd937d4157
1 /****************************************************************************
2 * TinySMB
3 * Nintendo Wii/GameCube SMB implementation
5 * Copyright softdev
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.
13 * Recommended Reading
14 * Implementing CIFS - Christopher R Hertel
15 * http://www.ubiqx.org/cifs/SMB.html
17 * License:
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 ****************************************************************************/
34 #include <asm.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <malloc.h>
40 #include <ctype.h>
41 #include <gccore.h>
42 #include <network.h>
43 #include <processor.h>
44 #include <lwp_threads.h>
45 #include <lwp_objmgr.h>
46 #include <ogc/lwp_watchdog.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <smb.h>
51 #define IOS_O_NONBLOCK 0x04
52 #define RECV_TIMEOUT 5000 // in ms
54 /**
55 * Field offsets.
57 #define SMB_OFFSET_PROTO 0
58 #define SMB_OFFSET_CMD 4
59 #define SMB_OFFSET_NTSTATUS 5
60 #define SMB_OFFSET_ECLASS 5
61 #define SMB_OFFSET_ECODE 7
62 #define SMB_OFFSET_FLAGS 9
63 #define SMB_OFFSET_FLAGS2 10
64 #define SMB_OFFSET_EXTRA 12
65 #define SMB_OFFSET_TID 24
66 #define SMB_OFFSET_PID 26
67 #define SMB_OFFSET_UID 28
68 #define SMB_OFFSET_MID 30
69 #define SMB_HEADER_SIZE 32 /*** SMB Headers are always 32 bytes long ***/
71 /**
72 * Message / Commands
74 #define NBT_SESSISON_MSG 0x00
76 #define SMB_NEG_PROTOCOL 0x72
77 #define SMB_SETUP_ANDX 0x73
78 #define SMB_TREEC_ANDX 0x75
81 #define NBT_KEEPALIVE_MSG 0x85
82 #define KEEPALIVE_SIZE 4
84 /**
85 * SMBTrans2
87 #define SMB_TRANS2 0x32
89 #define SMB_OPEN2 0
90 #define SMB_FIND_FIRST2 1
91 #define SMB_FIND_NEXT2 2
92 #define SMB_QUERY_FS_INFO 3
93 #define SMB_QUERY_PATH_INFO 5
94 #define SMB_SET_PATH_INFO 6
95 #define SMB_QUERY_FILE_INFO 7
96 #define SMB_SET_FILE_INFO 8
97 #define SMB_CREATE_DIR 13
98 #define SMB_FIND_CLOSE2 0x34
99 #define SMB_QUERY_FILE_ALL_INFO 0x107
102 * File I/O
104 #define SMB_OPEN_ANDX 0x2d
105 #define SMB_WRITE_ANDX 0x2f
106 #define SMB_READ_ANDX 0x2e
107 #define SMB_CLOSE 0x04
111 * TRANS2 Offsets
113 #define T2_WORD_CNT (SMB_HEADER_SIZE)
114 #define T2_PRM_CNT (T2_WORD_CNT+1)
115 #define T2_DATA_CNT (T2_PRM_CNT+2)
116 #define T2_MAXPRM_CNT (T2_DATA_CNT+2)
117 #define T2_MAXBUFFER (T2_MAXPRM_CNT+2)
118 #define T2_SETUP_CNT (T2_MAXBUFFER+2)
119 #define T2_SPRM_CNT (T2_SETUP_CNT+10)
120 #define T2_SPRM_OFS (T2_SPRM_CNT+2)
121 #define T2_SDATA_CNT (T2_SPRM_OFS+2)
122 #define T2_SDATA_OFS (T2_SDATA_CNT+2)
123 #define T2_SSETUP_CNT (T2_SDATA_OFS+2)
124 #define T2_SUB_CMD (T2_SSETUP_CNT+2)
125 #define T2_BYTE_CNT (T2_SUB_CMD+2)
128 #define SMB_PROTO 0x424d53ff
129 #define SMB_HANDLE_NULL 0xffffffff
130 #define SMB_MAX_BUFFERSIZE (62*1024) // cannot be larger than u16 (65536)
131 #define SMB_MAX_TRANSMIT_SIZE 7236
132 #define SMB_DEF_READOFFSET 59
134 #define SMB_CONNHANDLES_MAX 8
135 #define SMB_FILEHANDLES_MAX (32*SMB_CONNHANDLES_MAX)
137 #define SMB_OBJTYPE_HANDLE 7
138 #define SMB_CHECK_HANDLE(hndl) \
140 if(((hndl)==SMB_HANDLE_NULL) || (LWP_OBJTYPE(hndl)!=SMB_OBJTYPE_HANDLE)) \
141 return NULL; \
144 struct _smbfile
146 lwp_node node;
147 u16 sfid;
148 SMBCONN conn;
152 * NBT/SMB Wrapper
154 typedef struct _nbtsmb
156 u8 msg; /*** NBT Message ***/
157 u8 flags; /*** Not much here really ***/
158 u16 length; /*** Length, excluding NBT ***/
159 u8 smb[SMB_MAX_TRANSMIT_SIZE]; /*** Wii Actual is 7240 bytes ***/
160 } NBTSMB;
163 * Session Information
165 typedef struct _smbsession
167 u16 TID;
168 u16 PID;
169 u16 UID;
170 u16 MID;
171 u32 sKey;
172 u16 MaxBuffer;
173 u16 MaxMpx;
174 u16 MaxVCS;
175 u8 challenge[10];
176 u8 p_domain[64];
177 s64 timeOffset;
178 u16 sid;
179 u16 count;
180 u16 eos;
181 } SMBSESSION;
183 typedef struct _smbhandle
185 lwp_obj object;
186 char *user;
187 char *pwd;
188 char *share_name;
189 char *server_name;
190 s32 sck_server;
191 struct sockaddr_in server_addr;
192 BOOL conn_valid;
193 SMBSESSION session;
194 NBTSMB message;
195 } SMBHANDLE;
197 static u32 smb_dialectcnt = 1;
198 static BOOL smb_inited = FALSE;
199 static lwp_objinfo smb_handle_objects;
200 static lwp_queue smb_filehandle_queue;
201 static struct _smbfile smb_filehandles[SMB_FILEHANDLES_MAX];
202 static const char *smb_dialects[] = {"NT LM 0.12",NULL};
204 extern void ntlm_smb_nt_encrypt(const char *passwd, const u8 * challenge, u8 * answer);
207 * SMB Endian aware supporting functions
209 * SMB always uses Intel Little-Endian values, so htons etc are
210 * of little or no use :) ... Thanks M$
213 /*** get unsigned char ***/
214 static __inline__ u8 getUChar(u8 *buffer,u32 offset)
216 return (u8)buffer[offset];
219 /*** set unsigned char ***/
220 static __inline__ void setUChar(u8 *buffer,u32 offset,u8 value)
222 buffer[offset] = value;
225 /*** get signed short ***/
226 static __inline__ s16 getShort(u8 *buffer,u32 offset)
228 return (s16)((buffer[offset+1]<<8)|(buffer[offset]));
231 /*** get unsigned short ***/
232 static __inline__ u16 getUShort(u8 *buffer,u32 offset)
234 return (u16)((buffer[offset+1]<<8)|(buffer[offset]));
237 /*** set unsigned short ***/
238 static __inline__ void setUShort(u8 *buffer,u32 offset,u16 value)
240 buffer[offset] = (value&0xff);
241 buffer[offset+1] = ((value&0xff00)>>8);
244 /*** get unsigned int ***/
245 static __inline__ u32 getUInt(u8 *buffer,u32 offset)
247 return (u32)((buffer[offset+3]<<24)|(buffer[offset+2]<<16)|(buffer[offset+1]<<8)|buffer[offset]);
250 /*** set unsigned int ***/
251 static __inline__ void setUInt(u8 *buffer,u32 offset,u32 value)
253 buffer[offset] = (value&0xff);
254 buffer[offset+1] = ((value&0xff00)>>8);
255 buffer[offset+2] = ((value&0xff0000)>>16);
256 buffer[offset+3] = ((value&0xff000000)>>24);
259 /*** get unsigned long long ***/
260 static __inline__ u64 getULongLong(u8 *buffer,u32 offset)
262 return (u64)(getUInt(buffer, offset) | (u64)getUInt(buffer, offset+4) << 32);
265 static __inline__ SMBHANDLE* __smb_handle_open(SMBCONN smbhndl)
267 u32 level;
268 SMBHANDLE *handle;
270 SMB_CHECK_HANDLE(smbhndl);
272 _CPU_ISR_Disable(level);
273 handle = (SMBHANDLE*)__lwp_objmgr_getnoprotection(&smb_handle_objects,LWP_OBJMASKID(smbhndl));
274 _CPU_ISR_Restore(level);
275 return handle;
279 static __inline__ void __smb_handle_free(SMBHANDLE *handle)
281 u32 level;
283 _CPU_ISR_Disable(level);
284 __lwp_objmgr_close(&smb_handle_objects,&handle->object);
285 __lwp_objmgr_free(&smb_handle_objects,&handle->object);
286 _CPU_ISR_Restore(level);
289 static void __smb_init()
291 smb_inited = TRUE;
292 __lwp_objmgr_initinfo(&smb_handle_objects,SMB_CONNHANDLES_MAX,sizeof(SMBHANDLE));
293 __lwp_queue_initialize(&smb_filehandle_queue,smb_filehandles,SMB_FILEHANDLES_MAX,sizeof(struct _smbfile));
296 static SMBHANDLE* __smb_allocate_handle()
298 u32 level;
299 SMBHANDLE *handle;
301 _CPU_ISR_Disable(level);
302 handle = (SMBHANDLE*)__lwp_objmgr_allocate(&smb_handle_objects);
303 if(handle) {
304 handle->user = NULL;
305 handle->pwd = NULL;
306 handle->server_name = NULL;
307 handle->share_name = NULL;
308 handle->sck_server = INVALID_SOCKET;
309 handle->conn_valid = FALSE;
310 __lwp_objmgr_open(&smb_handle_objects,&handle->object);
312 _CPU_ISR_Restore(level);
313 return handle;
316 static void __smb_free_handle(SMBHANDLE *handle)
318 if(handle->user) free(handle->user);
319 if(handle->pwd) free(handle->pwd);
320 if(handle->server_name) free(handle->server_name);
321 if(handle->share_name) free(handle->share_name);
323 handle->user = NULL;
324 handle->pwd = NULL;
325 handle->server_name = NULL;
326 handle->share_name = NULL;
327 handle->sck_server = INVALID_SOCKET;
329 __smb_handle_free(handle);
332 static void MakeSMBHeader(u8 command,u8 flags,u16 flags2,SMBHANDLE *handle)
334 u8 *ptr = handle->message.smb;
335 NBTSMB *nbt = &handle->message;
336 SMBSESSION *sess = &handle->session;
338 memset(nbt,0,sizeof(NBTSMB));
340 setUInt(ptr,SMB_OFFSET_PROTO,SMB_PROTO);
341 setUChar(ptr,SMB_OFFSET_CMD,command);
342 setUChar(ptr,SMB_OFFSET_FLAGS,flags);
343 setUShort(ptr,SMB_OFFSET_FLAGS2,flags2);
344 setUShort(ptr,SMB_OFFSET_TID,sess->TID);
345 setUShort(ptr,SMB_OFFSET_PID,sess->PID);
346 setUShort(ptr,SMB_OFFSET_UID,sess->UID);
347 setUShort(ptr,SMB_OFFSET_MID,sess->MID);
349 ptr[SMB_HEADER_SIZE] = 0;
353 * MakeTRANS2Hdr
355 static void MakeTRANS2Header(u8 subcommand,SMBHANDLE *handle)
357 u8 *ptr = handle->message.smb;
358 SMBSESSION *sess = &handle->session;
360 setUChar(ptr, T2_WORD_CNT, 15);
361 setUShort(ptr, T2_MAXPRM_CNT, 10);
362 setUShort(ptr, T2_MAXBUFFER, sess->MaxBuffer);
363 setUChar(ptr, T2_SSETUP_CNT, 1);
364 setUShort(ptr, T2_SUB_CMD, subcommand);
368 * smb_send
370 * blocking call with timeout
371 * will return when ALL data has been sent. Number of bytes sent is returned.
372 * OR timeout. Timeout will return -1
373 * OR network error. -ve value will be returned
375 static inline s32 smb_send(s32 s,const void *data,s32 size)
377 u64 t1,t2;
378 s32 ret, len = size;
380 t1=ticks_to_millisecs(gettime());
381 while(len>0)
383 ret=net_send(s,data,len,0);
384 if(ret==-EAGAIN)
386 t2=ticks_to_millisecs(gettime());
387 if( (t2 - t1) > RECV_TIMEOUT)
389 return -1; /* timeout */
391 usleep(100); /* allow system to perform work. Stabilizes system */
392 continue;
394 else if(ret<0)
396 return ret; /* some error happened */
398 else
400 data+=ret;
401 len-=ret;
402 if(len==0) return size;
403 t1=ticks_to_millisecs(gettime());
406 return size;
410 * smb_recv
412 * blocking call with timeout
413 * will return when ANY data has been read from socket. Number of bytes read is returned.
414 * OR timeout. Timeout will return -1
415 * OR network error. -ve value will be returned
417 static s32 smb_recv(s32 s,void *mem,s32 len)
419 s32 ret;
420 u64 t1,t2;
422 t1=ticks_to_millisecs(gettime());
423 while(1)
425 ret=net_recv(s,mem,len,0);
426 if(ret>=0) return ret;
427 if(ret!=-EAGAIN) break;
428 t2=ticks_to_millisecs(gettime());
429 if( (t2 - t1) > RECV_TIMEOUT)
431 ret=-1;
432 break;
434 usleep(100); /* allow system to perform work. Stabilizes system */
436 return ret;
440 * SMBCheck
442 * Do very basic checking on the return SMB
443 * Read <readlen> bytes
444 * if <readlen>==0 then read a single SMB packet
445 * discard any NBT_KEEPALIVE_MSG packets along the way.
447 static s32 SMBCheck(u8 command, s32 readlen,SMBHANDLE *handle)
449 s32 ret,recvd = 0;
450 u8 *ptr = handle->message.smb;
451 NBTSMB *nbt = &handle->message;
452 u8 *ptr2 = (u8*)nbt;
453 u8 tempLength = (readlen==0);
455 /* if length is not specified,*/
456 if(tempLength)
458 /* read entire header if available. if not, just get whatever available.*/
459 readlen = SMB_HEADER_SIZE+4;
462 memset(nbt,0,sizeof(NBTSMB));
465 /*keep going till we get all the data we wanted*/
466 while(recvd<readlen)
468 ret=smb_recv(handle->sck_server, ptr2+recvd, readlen-recvd);
469 if(ret<0)
471 return SMB_ERROR;
473 recvd+=ret;
474 /* discard any and all keepalive packets */
475 while( (nbt->msg==NBT_KEEPALIVE_MSG) && (recvd>=KEEPALIVE_SIZE) )
477 recvd-=KEEPALIVE_SIZE;
478 memmove(ptr2, ptr2+KEEPALIVE_SIZE, recvd);
480 /* obtain required length from NBT header if readlen==0*/
481 if(tempLength && recvd>=KEEPALIVE_SIZE)
483 /* get the length header */
484 if(nbt->flags!=0 || nbt->length>SMB_MAX_TRANSMIT_SIZE)
486 /*length too big to be supported*/
487 return SMB_BAD_DATALEN;
489 else
491 readlen = nbt->length+KEEPALIVE_SIZE;
492 tempLength = 0;
497 /*** Do basic SMB Header checks ***/
498 ret = getUInt(ptr,SMB_OFFSET_PROTO);
499 if(ret!=SMB_PROTO) return SMB_BAD_PROTOCOL;
501 ret = getUChar(ptr, SMB_OFFSET_CMD);
502 if(ret!=command) return SMB_BAD_COMMAND;
504 ret = getUInt(ptr,SMB_OFFSET_NTSTATUS);
505 if(ret) return SMB_ERROR;
507 return SMB_SUCCESS;
511 * SMB_SetupAndX
513 * Setup the SMB session, including authentication with the
514 * magic 'NTLM Response'
516 static s32 SMB_SetupAndX(SMBHANDLE *handle)
518 s32 pos;
519 s32 bcpos;
520 s32 i, ret;
521 u8 *ptr = handle->message.smb;
522 SMBSESSION *sess = &handle->session;
523 char pwd[200], ntRespData[24];
525 MakeSMBHeader(SMB_SETUP_ANDX,0x08,0x01,handle);
526 pos = SMB_HEADER_SIZE;
528 setUChar(ptr,pos,13);
529 pos++; /*** Word Count ***/
530 setUChar(ptr,pos,0xff);
531 pos++; /*** Next AndX ***/
532 pos++; /*** Reserved ***/
533 pos += 2; /*** Next AndX Offset ***/
534 setUShort(ptr,pos,sess->MaxBuffer);
535 pos += 2;
536 setUShort(ptr,pos,sess->MaxMpx);
537 pos += 2;
538 setUShort(ptr,pos,sess->MaxVCS);
539 pos += 2;
540 setUInt(ptr,pos,sess->sKey);
541 pos += 4;
542 setUShort(ptr,pos,0); /*** Password length (case-insensitive) ***/
543 pos += 2;
544 setUShort(ptr,pos,24); /*** Password length (case-sensitive) ***/
545 pos += 2;
546 pos += 4; /*** Reserved ***/
547 pos += 4; /*** Capabilities ***/
548 bcpos = pos;
549 pos += 2; /*** Byte count ***/
551 /*** The magic 'NTLM Response' ***/
552 strcpy(pwd, handle->pwd);
553 ntlm_smb_nt_encrypt((const char *) pwd, (const u8 *) sess->challenge, (u8*) ntRespData);
555 /*** Build information ***/
556 memcpy(&ptr[pos],ntRespData,24);
557 pos += 24;
559 /*** Account ***/
560 strcpy(pwd, handle->user);
561 for(i=0;i<strlen(pwd);i++) pwd[i] = toupper(pwd[i]);
562 memcpy(&ptr[pos],pwd,strlen(pwd));
563 pos += strlen(pwd)+1;
565 /*** Primary Domain ***/
566 if(handle->user[0]=='\0') sess->p_domain[0] = '\0';
567 memcpy(&ptr[pos],sess->p_domain,strlen((const char*)sess->p_domain));
568 pos += strlen((const char*)sess->p_domain)+1;
570 /*** Native OS ***/
571 strcpy(pwd,"Unix (libOGC)");
572 memcpy(&ptr[pos],pwd,strlen(pwd));
573 pos += strlen(pwd)+1;
575 /*** Native LAN Manager ***/
576 strcpy(pwd,"Nintendo Wii");
577 memcpy(&ptr[pos],pwd,strlen(pwd));
578 pos += strlen (pwd)+1;
580 /*** Update byte count ***/
581 setUShort(ptr,bcpos,((pos-bcpos)-2));
583 handle->message.msg = NBT_SESSISON_MSG;
584 handle->message.length = htons (pos);
585 pos += 4;
587 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
588 if(ret<=0) return SMB_ERROR;
590 if((ret=SMBCheck(SMB_SETUP_ANDX,0,handle))==SMB_SUCCESS) {
591 /*** Collect UID ***/
592 sess->UID = getUShort(handle->message.smb,SMB_OFFSET_UID);
593 return SMB_SUCCESS;
595 return ret;
599 * SMB_TreeAndX
601 * Finally, net_connect to the remote share
603 static s32 SMB_TreeAndX(SMBHANDLE *handle)
605 s32 pos, bcpos, ret;
606 u8 path[256];
607 u8 *ptr = handle->message.smb;
608 SMBSESSION *sess = &handle->session;
610 MakeSMBHeader(SMB_TREEC_ANDX,0x08,0x01,handle);
611 pos = SMB_HEADER_SIZE;
613 setUChar(ptr,pos,4);
614 pos++; /*** Word Count ***/
615 setUChar(ptr,pos,0xff);
616 pos++; /*** Next AndX ***/
617 pos++; /*** Reserved ***/
618 pos += 2; /*** Next AndX Offset ***/
619 pos += 2; /*** Flags ***/
620 setUShort(ptr,pos,1);
621 pos += 2; /*** Password Length ***/
622 bcpos = pos;
623 pos += 2;
624 pos++; /*** NULL Password ***/
626 /*** Build server share path ***/
627 strcpy ((char*)path, "\\\\");
628 strcat ((char*)path, handle->server_name);
629 strcat ((char*)path, "\\");
630 strcat ((char*)path, handle->share_name);
631 for(ret=0;ret<strlen((const char*)path);ret++) path[ret] = toupper(path[ret]);
633 memcpy(&ptr[pos],path,strlen((const char*)path));
634 pos += strlen((const char*)path)+1;
636 /*** Service ***/
637 strcpy((char*)path,"?????");
638 memcpy(&ptr[pos],path,strlen((const char*)path));
639 pos += strlen((const char*)path)+1;
641 /*** Update byte count ***/
642 setUShort(ptr,bcpos,(pos-bcpos)-2);
644 handle->message.msg = NBT_SESSISON_MSG;
645 handle->message.length = htons (pos);
646 pos += 4;
648 ret = smb_send(handle->sck_server,(char *)&handle->message,pos);
649 if(ret<=0) return SMB_ERROR;
651 if((ret=SMBCheck(SMB_TREEC_ANDX,0,handle))==SMB_SUCCESS) {
652 /*** Collect Tree ID ***/
653 sess->TID = getUShort(handle->message.smb,SMB_OFFSET_TID);
654 return SMB_SUCCESS;
656 return ret;
660 * SMB_NegotiateProtocol
662 * The only protocol we admit to is 'NT LM 0.12'
664 static s32 SMB_NegotiateProtocol(const char *dialects[],int dialectc,SMBHANDLE *handle)
666 u8 *ptr;
667 s32 pos;
668 s32 bcnt,i,j;
669 s32 ret,len;
670 u16 bytecount;
671 u32 serverMaxBuffer;
672 SMBSESSION *sess;
674 if(!handle || !dialects || dialectc<=0)
675 return SMB_ERROR;
677 /*** Clear session variables ***/
678 sess = &handle->session;
679 memset(sess,0,sizeof(SMBSESSION));
680 sess->PID = 0xdead;
681 sess->MID = 1;
683 MakeSMBHeader(SMB_NEG_PROTOCOL,0x08,0x01,handle);
685 pos = SMB_HEADER_SIZE+3;
686 ptr = handle->message.smb;
687 for(i=0,bcnt=0;i<dialectc;i++) {
688 len = strlen(dialects[i])+1;
689 ptr[pos++] = '\x02';
690 memcpy(&ptr[pos],dialects[i],len);
691 pos += len;
692 bcnt += len+1;
694 /*** Update byte count ***/
695 setUShort(ptr,(SMB_HEADER_SIZE+1),bcnt);
697 /*** Set NBT information ***/
698 handle->message.msg = NBT_SESSISON_MSG;
699 handle->message.length = htons(pos);
700 pos += 4;
702 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
703 if(ret<=0) return SMB_ERROR;
705 /*** Check response ***/
706 if((ret=SMBCheck(SMB_NEG_PROTOCOL,0,handle))==SMB_SUCCESS) {
707 pos = SMB_HEADER_SIZE;
708 ptr = handle->message.smb;
710 /*** Collect information ***/
711 if(getUChar(ptr,pos)!=17) return SMB_PROTO_FAIL; // UCHAR WordCount; Count of parameter words = 17
713 pos++;
714 if(getUShort(ptr,pos)) return SMB_PROTO_FAIL; // USHORT DialectIndex; Index of selected dialect - should always be 0 since we only supplied 1!
716 pos += 2;
717 if(getUChar(ptr,pos)!=3) return SMB_NOT_USER; //UCHAR SecurityMode; Security mode:
719 pos++;
720 sess->MaxMpx = getUShort(ptr, pos); //USHORT MaxMpxCount; Max pending outstanding requests
722 pos += 2;
723 sess->MaxVCS = getUShort(ptr, pos); //USHORT MaxNumberVcs; Max VCs between client and server
725 pos += 2;
726 serverMaxBuffer = getUInt(ptr, pos); //ULONG MaxBufferSize; Max transmit buffer size
727 if(serverMaxBuffer>SMB_MAX_TRANSMIT_SIZE)
728 sess->MaxBuffer = SMB_MAX_TRANSMIT_SIZE;
729 else
730 sess->MaxBuffer = serverMaxBuffer;
732 pos += 4;
733 pos += 4; //ULONG MaxRawSize; Maximum raw buffer size
734 sess->sKey = getUInt(ptr,pos); pos += 4;
735 pos += 4; //ULONG Capabilities; Server capabilities
736 pos += 4; //ULONG SystemTimeLow; System (UTC) time of the server (low).
737 pos += 4; //ULONG SystemTimeHigh; System (UTC) time of the server (high).
738 sess->timeOffset = getShort(ptr,pos) * 600000000LL; pos += 2; //SHORT ServerTimeZone; Time zone of server (minutes from UTC)
739 if(getUChar(ptr,pos)!=8) return SMB_BAD_KEYLEN; //UCHAR EncryptionKeyLength - 0 or 8
741 pos++;
742 bytecount = getUShort(ptr,pos);
744 /*** Copy challenge key ***/
745 pos += 2;
746 memcpy(&sess->challenge,&ptr[pos],8);
748 /*** Primary domain ***/
749 pos += 8;
750 i = j = 0;
751 while(ptr[pos+j]!=0) {
752 sess->p_domain[i] = ptr[pos+j];
753 j += 2;
754 i++;
756 sess->p_domain[i] = '\0';
758 return SMB_SUCCESS;
761 return ret;
764 static s32 do_netconnect(SMBHANDLE *handle)
766 u32 nodelay;
767 s32 ret;
768 s32 sock;
769 u32 flags=0;
770 u64 t1,t2;
772 /*** Create the global net_socket ***/
773 sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
774 if(sock==INVALID_SOCKET) return -1;
776 /*** Switch off Nagle, ON TCP_NODELAY ***/
777 nodelay = 1;
778 ret = net_setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,&nodelay,sizeof(nodelay));
780 //create non blocking socket
781 flags = net_fcntl(sock, F_GETFL, 0);
782 flags |= IOS_O_NONBLOCK;
783 ret=net_fcntl(sock, F_SETFL, flags);
785 t1=ticks_to_millisecs(gettime());
788 ret = net_connect(sock,(struct sockaddr*)&handle->server_addr,sizeof(handle->server_addr));
789 t2=ticks_to_millisecs(gettime());
790 usleep(1000);
791 if(t2-t1 > 3000) break; // 3 secs to try to connect to handle->server_addr
792 } while(ret!=-127);
794 if(ret!=-127)
796 net_close(sock);
797 return -1;
800 handle->sck_server = sock;
801 return 0;
804 static s32 do_smbconnect(SMBHANDLE *handle)
806 s32 ret;
808 ret = SMB_NegotiateProtocol(smb_dialects,smb_dialectcnt,handle);
809 if(ret!=SMB_SUCCESS) {
810 net_close(handle->sck_server);
811 return -1;
814 ret = SMB_SetupAndX(handle);
815 if(ret!=SMB_SUCCESS) {
816 net_close(handle->sck_server);
817 return -1;
820 ret = SMB_TreeAndX(handle);
821 if(ret!=SMB_SUCCESS) {
822 net_close(handle->sck_server);
823 return -1;
826 handle->conn_valid = TRUE;
827 return 0;
830 /****************************************************************************
831 * Primary setup, logon and connection all in one :)
832 ****************************************************************************/
833 s32 SMB_Connect(SMBCONN *smbhndl, const char *user, const char *password, const char *share, const char *server)
835 s32 ret = 0;
836 SMBHANDLE *handle;
837 struct hostent *hp;
838 struct in_addr val;
840 if(!user || !password || !share || !server ||
841 strlen(user) > 20 || strlen(password) > 14 ||
842 strlen(share) > 80 || strlen(server) > 80)
844 return SMB_BAD_LOGINDATA;
847 *smbhndl = SMB_HANDLE_NULL;
849 if(smb_inited==FALSE) {
850 u32 level;
851 _CPU_ISR_Disable(level);
852 __smb_init();
853 _CPU_ISR_Restore(level);
856 handle = __smb_allocate_handle();
857 if(!handle) return SMB_ERROR;
859 handle->user = strdup(user);
860 handle->pwd = strdup(password);
861 handle->server_name = strdup(server);
862 handle->share_name = strdup(share);
863 handle->server_addr.sin_family = AF_INET;
864 handle->server_addr.sin_port = htons(445);
866 if(strlen(server) < 16 && inet_aton(server, &val))
868 handle->server_addr.sin_addr.s_addr = val.s_addr;
870 else // might be a hostname
872 hp = net_gethostbyname(server);
873 if (!hp || !(hp->h_addrtype == PF_INET))
874 ret = SMB_BAD_LOGINDATA;
875 else
876 memcpy((char *)&handle->server_addr.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
879 if(ret==0)
881 ret = do_netconnect(handle);
882 if(ret==0) ret = do_smbconnect(handle);
884 if(ret!=0)
886 // try port 139
887 handle->server_addr.sin_port = htons(139);
888 ret = do_netconnect(handle);
889 if(ret==0) ret = do_smbconnect(handle);
892 if(ret!=0)
894 __smb_free_handle(handle);
895 return SMB_ERROR;
897 else
899 *smbhndl =(SMBCONN)(LWP_OBJMASKTYPE(SMB_OBJTYPE_HANDLE)|LWP_OBJMASKID(handle->object.id));
900 return SMB_SUCCESS;
904 /****************************************************************************
905 * SMB_Destroy
907 * Probably NEVER called on GameCube, but here for completeness
908 ****************************************************************************/
909 void SMB_Close(SMBCONN smbhndl)
911 SMBHANDLE *handle;
913 handle = __smb_handle_open(smbhndl);
914 if(!handle) return;
916 if(handle->sck_server!=INVALID_SOCKET) net_close(handle->sck_server);
917 __smb_free_handle(handle);
920 s32 SMB_Reconnect(SMBCONN *_smbhndl, BOOL test_conn)
922 s32 ret = SMB_SUCCESS;
923 SMBCONN smbhndl = *_smbhndl;
924 SMBHANDLE *handle = __smb_handle_open(smbhndl);
925 if(!handle)
926 return SMB_ERROR; // we have no handle, so we can't reconnect
928 if(handle->conn_valid && test_conn)
930 SMBDIRENTRY dentry;
931 if(SMB_PathInfo("\\", &dentry, smbhndl)==SMB_SUCCESS) return SMB_SUCCESS; // no need to reconnect
932 handle->conn_valid = FALSE; // else connection is invalid
935 if(!handle->conn_valid)
937 // save connection details
938 const char * user = strdup(handle->user);
939 const char * pwd = strdup(handle->pwd);
940 const char * ip = strdup(handle->server_name);
941 const char * share = strdup(handle->share_name);
943 // shut down connection, and reopen
944 SMB_Close(smbhndl);
945 ret = SMB_Connect(_smbhndl, user, pwd, share, ip);
947 return ret;
950 SMBFILE SMB_OpenFile(const char *filename, u16 access, u16 creation,SMBCONN smbhndl)
952 s32 pos;
953 s32 bpos,ret;
954 u8 *ptr;
955 struct _smbfile *fid = NULL;
956 SMBHANDLE *handle;
957 char realfile[256];
959 if(SMB_Reconnect(&smbhndl,TRUE)!=SMB_SUCCESS) return NULL;
961 handle = __smb_handle_open(smbhndl);
962 if(!handle) return NULL;
964 MakeSMBHeader(SMB_OPEN_ANDX,0x08,0x01,handle);
966 pos = SMB_HEADER_SIZE;
967 ptr = handle->message.smb;
968 setUChar(ptr, pos, 15);
969 pos++; /*** Word Count ***/
970 setUChar(ptr, pos, 0xff);
971 pos++; /*** Next AndX ***/
972 pos += 3; /*** Next AndX Offset ***/
974 pos += 2; /*** Flags ***/
975 setUShort(ptr, pos, access);
976 pos += 2; /*** Access mode ***/
977 setUShort(ptr, pos, 0x6);
978 pos += 2; /*** Type of file ***/
979 pos += 2; /*** Attributes ***/
980 pos += 4; /*** File time - don't care - let server decide ***/
981 setUShort(ptr, pos, creation);
982 pos += 2; /*** Creation flags ***/
983 pos += 4; /*** Allocation size ***/
984 pos += 8; /*** Reserved ***/
985 pos += 2; /*** Byte Count ***/
986 bpos = pos;
988 if (filename[0] != '\\') {
989 strcpy(realfile, "\\");
990 strcat(realfile,filename);
991 } else
992 strcpy(realfile,filename);
994 memcpy(&ptr[pos],realfile,strlen(realfile));
995 pos += strlen(realfile)+1;
997 setUShort(ptr,(bpos-2),(pos-bpos));
999 handle->message.msg = NBT_SESSISON_MSG;
1000 handle->message.length = htons(pos);
1002 pos += 4;
1003 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1004 if(ret<0) goto failed;
1006 if(SMBCheck(SMB_OPEN_ANDX,0,handle)==SMB_SUCCESS) {
1007 /*** Check file handle ***/
1008 fid = (struct _smbfile*)__lwp_queue_get(&smb_filehandle_queue);
1009 if(fid) {
1010 fid->conn = smbhndl;
1011 fid->sfid = getUShort(handle->message.smb,(SMB_HEADER_SIZE+5));
1014 return (SMBFILE)fid;
1016 failed:
1017 handle->conn_valid = FALSE;
1018 return NULL;
1022 * SMB_Close
1024 void SMB_CloseFile(SMBFILE sfid)
1026 u8 *ptr;
1027 s32 pos, ret;
1028 SMBHANDLE *handle;
1029 struct _smbfile *fid = (struct _smbfile*)sfid;
1031 if(!fid) return;
1033 handle = __smb_handle_open(fid->conn);
1034 if(!handle) return;
1036 MakeSMBHeader(SMB_CLOSE,0x08,0x01,handle);
1038 pos = SMB_HEADER_SIZE;
1039 ptr = handle->message.smb;
1040 setUChar(ptr, pos, 3);
1041 pos++; /** Word Count **/
1042 setUShort(ptr, pos, fid->sfid);
1043 pos += 2;
1044 setUInt(ptr, pos, 0xffffffff);
1045 pos += 4; /*** Last Write ***/
1046 pos += 2; /*** Byte Count ***/
1048 handle->message.msg = NBT_SESSISON_MSG;
1049 handle->message.length = htons(pos);
1051 pos += 4;
1052 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1053 if(ret<0) handle->conn_valid = FALSE;
1054 else SMBCheck(SMB_CLOSE,0,handle);
1055 __lwp_queue_append(&smb_filehandle_queue,&fid->node);
1059 * SMB_Read
1061 s32 SMB_ReadFile(char *buffer, int size, int offset, SMBFILE sfid)
1063 u8 *ptr,*dest;
1064 s32 pos, ret, ofs;
1065 u16 length = 0;
1066 SMBHANDLE *handle;
1067 struct _smbfile *fid = (struct _smbfile*)sfid;
1069 if(!fid) return 0;
1071 /*** Don't let the size exceed! ***/
1072 if(size>SMB_MAX_BUFFERSIZE) return 0;
1074 handle = __smb_handle_open(fid->conn);
1075 if(!handle) return 0;
1077 MakeSMBHeader(SMB_READ_ANDX,0x08,0x01,handle);
1079 pos = SMB_HEADER_SIZE;
1080 ptr = handle->message.smb;
1081 setUChar(ptr, pos, 10);
1082 pos++; /*** Word count ***/
1083 setUChar(ptr, pos, 0xff);
1084 pos++;
1085 pos += 3; /*** Reserved, Next AndX Offset ***/
1086 setUShort(ptr, pos, fid->sfid);
1087 pos += 2; /*** FID ***/
1088 setUInt(ptr, pos, offset);
1089 pos += 4; /*** Offset ***/
1091 setUShort(ptr, pos, size & 0xffff);
1092 pos += 2;
1093 setUShort(ptr, pos, size & 0xffff);
1094 pos += 2;
1095 setUInt(ptr, pos, 0);
1096 pos += 4;
1097 pos += 2; /*** Remaining ***/
1098 pos += 2; /*** Byte count ***/
1100 handle->message.msg = NBT_SESSISON_MSG;
1101 handle->message.length = htons(pos);
1103 pos += 4;
1104 ret = smb_send(handle->sck_server,(char*)&handle->message, pos);
1105 if(ret<0) goto failed;
1107 /*** SMBCheck should now only read up to the end of a standard header ***/
1108 if((ret=SMBCheck(SMB_READ_ANDX,(SMB_HEADER_SIZE+27+4),handle))==SMB_SUCCESS) {
1109 ptr = handle->message.smb;
1110 /*** Retrieve data length for this packet ***/
1111 length = getUShort(ptr,(SMB_HEADER_SIZE+11));
1112 /*** Retrieve offset to data ***/
1113 ofs = getUShort(ptr,(SMB_HEADER_SIZE+13));
1115 /*** Default offset, with no padding is 59, so grab any outstanding padding ***/
1116 while(ofs>SMB_DEF_READOFFSET) {
1117 char pad[1024];
1118 ret = smb_recv(handle->sck_server,pad,(ofs-SMB_DEF_READOFFSET));
1119 if(ret<0) return ret;
1120 ofs-=ret;
1123 /*** Finally, go grab the data ***/
1124 ofs = 0;
1125 dest = (u8*)buffer;
1126 if(length>0) {
1127 while ((ret=smb_recv(handle->sck_server,&dest[ofs],length-ofs))!=0) {
1128 if(ret<0) return ret;
1130 ofs += ret;
1131 if (ofs>=length) break;
1134 return ofs;
1136 return 0;
1138 failed:
1139 handle->conn_valid = FALSE;
1140 return ret;
1144 * SMB_Write
1146 s32 SMB_WriteFile(const char *buffer, int size, int offset, SMBFILE sfid)
1148 u8 *ptr,*src;
1149 s32 pos, ret;
1150 s32 blocks64;
1151 u32 copy_len;
1152 SMBHANDLE *handle;
1153 struct _smbfile *fid = (struct _smbfile*)sfid;
1155 if(!fid) return 0;
1157 handle = __smb_handle_open(fid->conn);
1158 if(!handle) return SMB_ERROR;
1160 MakeSMBHeader(SMB_WRITE_ANDX,0x08,0x01,handle);
1162 pos = SMB_HEADER_SIZE;
1163 ptr = handle->message.smb;
1164 setUChar(ptr, pos, 12);
1165 pos++; /*** Word Count ***/
1166 setUChar(ptr, pos, 0xff);
1167 pos += 2; /*** Next AndX ***/
1168 pos += 2; /*** Next AndX Offset ***/
1170 setUShort(ptr, pos, fid->sfid);
1171 pos += 2;
1172 setUInt(ptr, pos, offset);
1173 pos += 4;
1174 pos += 4; /*** Reserved ***/
1175 pos += 2; /*** Write Mode ***/
1176 pos += 2; /*** Remaining ***/
1178 blocks64 = size >> 16;
1180 setUShort(ptr, pos, blocks64);
1181 pos += 2; /*** Length High ***/
1182 setUShort(ptr, pos, size & 0xffff);
1183 pos += 2; /*** Length Low ***/
1184 setUShort(ptr, pos, 59);
1185 pos += 2; /*** Data Offset ***/
1186 setUShort(ptr, pos, size & 0xffff);
1187 pos += 2; /*** Data Byte Count ***/
1189 handle->message.msg = NBT_SESSISON_MSG;
1190 handle->message.length = htons(pos+size);
1192 src = (u8*)buffer;
1193 copy_len = size;
1194 if((copy_len+pos)>SMB_MAX_TRANSMIT_SIZE) copy_len = (SMB_MAX_TRANSMIT_SIZE-pos);
1196 memcpy(&ptr[pos],src,copy_len);
1197 size -= copy_len;
1198 src += copy_len;
1199 pos += copy_len;
1201 pos += 4;
1203 /*** Send Header Information ***/
1204 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1205 if(ret<0) goto failed;
1207 if(size>0) {
1208 /*** Send the data ***/
1209 ret = smb_send(handle->sck_server,src,size);
1210 if(ret<0) goto failed;
1213 ret = 0;
1214 if(SMBCheck(SMB_WRITE_ANDX,0,handle)==SMB_SUCCESS) {
1215 ptr = handle->message.smb;
1216 ret = getUShort(ptr,(SMB_HEADER_SIZE+5));
1219 return ret;
1221 failed:
1222 handle->conn_valid = FALSE;
1223 return ret;
1227 * SMB_PathInfo
1229 s32 SMB_PathInfo(const char *filename, SMBDIRENTRY *sdir, SMBCONN smbhndl)
1231 u8 *ptr;
1232 s32 pos;
1233 s32 ret;
1234 s32 bpos;
1235 SMBHANDLE *handle;
1236 char realfile[256];
1238 handle = __smb_handle_open(smbhndl);
1239 if (!handle) return SMB_ERROR;
1241 MakeSMBHeader(SMB_TRANS2, 0x08, 0x01, handle);
1242 MakeTRANS2Header(SMB_QUERY_PATH_INFO, handle);
1244 bpos = pos = (T2_BYTE_CNT + 2);
1245 pos += 3; /*** Padding ***/
1246 ptr = handle->message.smb;
1247 setUShort(ptr, pos, SMB_QUERY_FILE_ALL_INFO);
1249 pos += 2;
1250 setUInt(ptr, pos, 0);
1251 pos += 4; /*** reserved ***/
1253 if (filename[0] != '\\') {
1254 strcpy(realfile, "\\");
1255 strcat(realfile, filename);
1256 } else
1257 strcpy(realfile, filename);
1259 memcpy(&ptr[pos], realfile, strlen(realfile));
1260 pos += strlen(realfile) + 1; /*** Include padding ***/
1262 /*** Update counts ***/
1263 setUShort(ptr, T2_PRM_CNT, (7 + strlen(realfile)));
1264 setUShort(ptr, T2_SPRM_CNT, (7 + strlen(realfile)));
1265 setUShort(ptr, T2_SPRM_OFS, 68);
1266 setUShort(ptr, T2_SDATA_OFS, (75 + strlen(realfile)));
1267 setUShort(ptr, T2_BYTE_CNT, (pos - bpos));
1269 handle->message.msg = NBT_SESSISON_MSG;
1270 handle->message.length = htons(pos);
1272 pos += 4;
1273 ret = smb_send(handle->sck_server, (char*) &handle->message, pos);
1274 if(ret<0) goto failed;
1276 ret = SMB_ERROR;
1277 if (SMBCheck(SMB_TRANS2, 0, handle) == SMB_SUCCESS) {
1279 ptr = handle->message.smb;
1280 /*** Get parameter offset ***/
1281 pos = getUShort(ptr, (SMB_HEADER_SIZE + 9));
1282 pos += 4; // padding
1283 sdir->ctime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - creation time
1284 sdir->atime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - access time
1285 sdir->mtime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - write time
1286 pos += 8; // ULONGLONG - change time
1287 sdir->attributes = getUInt(ptr,pos); pos += 4; // ULONG - file attributes
1288 pos += 4; // padding
1289 pos += 8; // ULONGLONG - allocated file size
1290 sdir->size = getULongLong(ptr, pos); pos += 8; // ULONGLONG - file size
1291 pos += 4; // ULONG NumberOfLinks;
1292 pos += 2; // UCHAR DeletePending;
1293 pos += 2; // UCHAR Directory;
1294 pos += 2; // USHORT Pad2; // for alignment only
1295 pos += 4; // ULONG EaSize;
1296 pos += 4; // ULONG FileNameLength;
1298 strcpy(sdir->name,realfile);
1300 ret = SMB_SUCCESS;
1302 return ret;
1304 failed:
1305 handle->conn_valid = FALSE;
1306 return ret;
1310 * SMB_FindFirst
1312 * Uses TRANS2 to support long filenames
1314 s32 SMB_FindFirst(const char *filename, unsigned short flags, SMBDIRENTRY *sdir, SMBCONN smbhndl)
1316 u8 *ptr;
1317 s32 pos;
1318 s32 ret;
1319 s32 bpos;
1320 SMBHANDLE *handle;
1321 SMBSESSION *sess;
1323 if(SMB_Reconnect(&smbhndl,TRUE)!=SMB_SUCCESS) return SMB_ERROR;
1325 handle = __smb_handle_open(smbhndl);
1326 if(!handle) return SMB_ERROR;
1328 sess = &handle->session;
1329 MakeSMBHeader(SMB_TRANS2,0x08,0x01,handle);
1330 MakeTRANS2Header(SMB_FIND_FIRST2,handle);
1332 bpos = pos = (T2_BYTE_CNT+2);
1333 pos += 3; /*** Padding ***/
1334 ptr = handle->message.smb;
1335 setUShort(ptr, pos, flags);
1336 pos += 2; /*** Flags ***/
1337 setUShort(ptr, pos, 1);
1338 pos += 2; /*** Count ***/
1339 setUShort(ptr, pos, 6);
1340 pos += 2; /*** Internal Flags ***/
1341 setUShort(ptr, pos, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
1342 pos += 2; /*** Level of Interest ***/
1343 pos += 4; /*** Storage Type == 0 ***/
1344 memcpy(&ptr[pos], filename, strlen(filename));
1345 pos += strlen(filename)+1; /*** Include padding ***/
1347 /*** Update counts ***/
1348 setUShort(ptr, T2_PRM_CNT, (13+strlen(filename)));
1349 setUShort(ptr, T2_SPRM_CNT, (13+strlen(filename)));
1350 setUShort(ptr, T2_SPRM_OFS, 68);
1351 setUShort(ptr, T2_SDATA_OFS,(81+strlen(filename)));
1352 setUShort(ptr, T2_BYTE_CNT,(pos-bpos));
1354 handle->message.msg = NBT_SESSISON_MSG;
1355 handle->message.length = htons(pos);
1357 pos += 4;
1358 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1359 if(ret<0) goto failed;
1361 sess->eos = 1;
1362 sess->sid = 0;
1363 sess->count = 0;
1364 ret = SMB_ERROR;
1365 if(SMBCheck(SMB_TRANS2,0,handle)==SMB_SUCCESS) {
1366 ptr = handle->message.smb;
1367 /*** Get parameter offset ***/
1368 pos = getUShort(ptr,(SMB_HEADER_SIZE+9));
1369 sess->sid = getUShort(ptr, pos); pos += 2;
1370 sess->count = getUShort(ptr, pos); pos += 2;
1371 sess->eos = getUShort(ptr, pos); pos += 2;
1372 pos += 2; // USHORT EaErrorOffset;
1373 pos += 2; // USHORT LastNameOffset;
1374 pos += 2; // padding?
1376 if (sess->count)
1378 pos += 4; // ULONG NextEntryOffset;
1379 pos += 4; // ULONG FileIndex;
1380 sdir->ctime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - creation time
1381 sdir->atime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - access time
1382 sdir->mtime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - write time
1383 pos += 8; // ULONGLONG - change time low
1384 sdir->size = getULongLong(ptr, pos); pos += 8;
1385 pos += 8;
1386 sdir->attributes = getUInt(ptr, pos); pos += 4;
1387 pos += 34;
1388 strcpy(sdir->name, (const char*)&ptr[pos]);
1390 ret = SMB_SUCCESS;
1393 return ret;
1395 failed:
1396 handle->conn_valid = FALSE;
1397 return ret;
1401 * SMB_FindNext
1403 s32 SMB_FindNext(SMBDIRENTRY *sdir,SMBCONN smbhndl)
1405 u8 *ptr;
1406 s32 pos;
1407 s32 ret;
1408 s32 bpos;
1409 SMBHANDLE *handle;
1410 SMBSESSION *sess;
1412 if(SMB_Reconnect(&smbhndl,TRUE)!=SMB_SUCCESS) return SMB_ERROR;
1414 handle = __smb_handle_open(smbhndl);
1415 if(!handle) return SMB_ERROR;
1417 sess = &handle->session;
1418 if(sess->eos || sess->sid==0) return SMB_ERROR;
1420 MakeSMBHeader(SMB_TRANS2,0x08,0x01,handle);
1421 MakeTRANS2Header(SMB_FIND_NEXT2,handle);
1423 bpos = pos = (T2_BYTE_CNT+2);
1424 pos += 3; /*** Padding ***/
1425 ptr = handle->message.smb;
1426 setUShort(ptr, pos, sess->sid);
1427 pos += 2; /*** Search ID ***/
1428 setUShort(ptr, pos, 1);
1429 pos += 2; /*** Count ***/
1430 setUShort(ptr, pos, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
1431 pos += 2; /*** Level of Interest ***/
1432 pos += 4; /*** Storage Type == 0 ***/
1433 setUShort(ptr, pos, 12);
1434 pos+=2; /*** Search flags ***/
1435 pos++;
1437 /*** Update counts ***/
1438 setUShort(ptr, T2_PRM_CNT, 13);
1439 setUShort(ptr, T2_SPRM_CNT, 13);
1440 setUShort(ptr, T2_SPRM_OFS, 68);
1441 setUShort(ptr, T2_SDATA_OFS, 81);
1442 setUShort(ptr, T2_BYTE_CNT, (pos-bpos));
1444 handle->message.msg = NBT_SESSISON_MSG;
1445 handle->message.length = htons(pos);
1447 pos += 4;
1448 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1449 if(ret<0) goto failed;
1451 ret = SMB_ERROR;
1452 if (SMBCheck(SMB_TRANS2,0,handle)==SMB_SUCCESS) {
1453 ptr = handle->message.smb;
1454 /*** Get parameter offset ***/
1455 pos = getUShort(ptr,(SMB_HEADER_SIZE+9));
1456 sess->count = getUShort(ptr, pos); pos += 2;
1457 sess->eos = getUShort(ptr, pos); pos += 2;
1458 pos += 2; // USHORT EaErrorOffset;
1459 pos += 2; // USHORT LastNameOffset;
1461 if (sess->count)
1463 pos += 4; // ULONG NextEntryOffset;
1464 pos += 4; // ULONG FileIndex;
1465 sdir->ctime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - creation time
1466 sdir->atime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - access time
1467 sdir->mtime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - write time
1468 pos += 8; // ULONGLONG - change time low
1469 sdir->size = getULongLong(ptr, pos); pos += 8;
1470 pos += 8;
1471 sdir->attributes = getUInt(ptr, pos); pos += 4;
1472 pos += 34;
1473 strcpy (sdir->name, (const char*)&ptr[pos]);
1475 ret = SMB_SUCCESS;
1478 return ret;
1480 failed:
1481 handle->conn_valid = FALSE;
1482 return ret;
1486 * SMB_FindClose
1488 s32 SMB_FindClose(SMBCONN smbhndl)
1490 u8 *ptr;
1491 s32 pos;
1492 s32 ret;
1493 SMBHANDLE *handle;
1494 SMBSESSION *sess;
1496 if(SMB_Reconnect(&smbhndl,TRUE)!=SMB_SUCCESS) return SMB_ERROR;
1498 handle = __smb_handle_open(smbhndl);
1499 if(!handle) return SMB_ERROR;
1501 sess = &handle->session;
1502 if(sess->sid==0) return SMB_ERROR;
1504 MakeSMBHeader(SMB_FIND_CLOSE2,0x08,0x01,handle);
1506 pos = SMB_HEADER_SIZE;
1507 ptr = handle->message.smb;
1508 setUChar(ptr, pos, 1);
1509 pos++; /*** Word Count ***/
1510 setUShort(ptr, pos, sess->sid);
1511 pos += 2;
1512 pos += 2; /*** Byte Count ***/
1514 handle->message.msg = NBT_SESSISON_MSG;
1515 handle->message.length = htons(pos);
1517 pos += 4;
1518 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1519 if(ret<0) goto failed;
1521 ret = SMBCheck(SMB_FIND_CLOSE2,0,handle);
1522 return ret;
1524 failed:
1525 handle->conn_valid = FALSE;
1526 return ret;