return NULL not SMB_ERROR
[libogc.git] / libtinysmb / smb.c
blob085a5515a696c65db50f5aa2ce501dcce0dc097a
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 /* NBT Session Service Packet Type Codes
147 #define SESS_MSG 0x00
148 #define SESS_REQ 0x81
149 #define SESS_POS_RESP 0x82
150 #define SESS_NEG_RESP 0x83
151 #define SESS_RETARGET 0x84
152 #define SESS_KEEPALIVE 0x85
154 struct _smbfile
156 lwp_node node;
157 u16 sfid;
158 SMBCONN conn;
162 * NBT/SMB Wrapper
164 typedef struct _nbtsmb
166 u8 msg; /*** NBT Message ***/
167 u8 flags; /*** Not much here really ***/
168 u16 length; /*** Length, excluding NBT ***/
169 u8 smb[SMB_MAX_TRANSMIT_SIZE]; /*** Wii Actual is 7240 bytes ***/
170 } NBTSMB;
173 * Session Information
175 typedef struct _smbsession
177 u16 TID;
178 u16 PID;
179 u16 UID;
180 u16 MID;
181 u32 sKey;
182 u16 MaxBuffer;
183 u16 MaxMpx;
184 u16 MaxVCS;
185 u8 challenge[10];
186 u8 p_domain[64];
187 s64 timeOffset;
188 u16 sid;
189 u16 count;
190 u16 eos;
191 bool challengeUsed;
192 } SMBSESSION;
194 typedef struct _smbhandle
196 lwp_obj object;
197 char *user;
198 char *pwd;
199 char *share_name;
200 char *server_name;
201 s32 sck_server;
202 struct sockaddr_in server_addr;
203 BOOL conn_valid;
204 SMBSESSION session;
205 NBTSMB message;
206 } SMBHANDLE;
208 static u32 smb_dialectcnt = 1;
209 static BOOL smb_inited = FALSE;
210 static lwp_objinfo smb_handle_objects;
211 static lwp_queue smb_filehandle_queue;
212 static struct _smbfile smb_filehandles[SMB_FILEHANDLES_MAX];
213 static const char *smb_dialects[] = {"NT LM 0.12",NULL};
215 extern void ntlm_smb_nt_encrypt(const char *passwd, const u8 * challenge, u8 * answer);
218 * SMB Endian aware supporting functions
220 * SMB always uses Intel Little-Endian values, so htons etc are
221 * of little or no use :) ... Thanks M$
224 /*** get unsigned char ***/
225 static __inline__ u8 getUChar(u8 *buffer,u32 offset)
227 return (u8)buffer[offset];
230 /*** set unsigned char ***/
231 static __inline__ void setUChar(u8 *buffer,u32 offset,u8 value)
233 buffer[offset] = value;
236 /*** get signed short ***/
237 static __inline__ s16 getShort(u8 *buffer,u32 offset)
239 return (s16)((buffer[offset+1]<<8)|(buffer[offset]));
242 /*** get unsigned short ***/
243 static __inline__ u16 getUShort(u8 *buffer,u32 offset)
245 return (u16)((buffer[offset+1]<<8)|(buffer[offset]));
248 /*** set unsigned short ***/
249 static __inline__ void setUShort(u8 *buffer,u32 offset,u16 value)
251 buffer[offset] = (value&0xff);
252 buffer[offset+1] = ((value&0xff00)>>8);
255 /*** get unsigned int ***/
256 static __inline__ u32 getUInt(u8 *buffer,u32 offset)
258 return (u32)((buffer[offset+3]<<24)|(buffer[offset+2]<<16)|(buffer[offset+1]<<8)|buffer[offset]);
261 /*** set unsigned int ***/
262 static __inline__ void setUInt(u8 *buffer,u32 offset,u32 value)
264 buffer[offset] = (value&0xff);
265 buffer[offset+1] = ((value&0xff00)>>8);
266 buffer[offset+2] = ((value&0xff0000)>>16);
267 buffer[offset+3] = ((value&0xff000000)>>24);
270 /*** get unsigned long long ***/
271 static __inline__ u64 getULongLong(u8 *buffer,u32 offset)
273 return (u64)(getUInt(buffer, offset) | (u64)getUInt(buffer, offset+4) << 32);
276 static __inline__ SMBHANDLE* __smb_handle_open(SMBCONN smbhndl)
278 u32 level;
279 SMBHANDLE *handle;
281 SMB_CHECK_HANDLE(smbhndl);
283 _CPU_ISR_Disable(level);
284 handle = (SMBHANDLE*)__lwp_objmgr_getnoprotection(&smb_handle_objects,LWP_OBJMASKID(smbhndl));
285 _CPU_ISR_Restore(level);
286 return handle;
290 static __inline__ void __smb_handle_free(SMBHANDLE *handle)
292 u32 level;
294 _CPU_ISR_Disable(level);
295 __lwp_objmgr_close(&smb_handle_objects,&handle->object);
296 __lwp_objmgr_free(&smb_handle_objects,&handle->object);
297 _CPU_ISR_Restore(level);
300 static void __smb_init()
302 smb_inited = TRUE;
303 __lwp_objmgr_initinfo(&smb_handle_objects,SMB_CONNHANDLES_MAX,sizeof(SMBHANDLE));
304 __lwp_queue_initialize(&smb_filehandle_queue,smb_filehandles,SMB_FILEHANDLES_MAX,sizeof(struct _smbfile));
307 static SMBHANDLE* __smb_allocate_handle()
309 u32 level;
310 SMBHANDLE *handle;
312 _CPU_ISR_Disable(level);
313 handle = (SMBHANDLE*)__lwp_objmgr_allocate(&smb_handle_objects);
314 if(handle) {
315 handle->user = NULL;
316 handle->pwd = NULL;
317 handle->server_name = NULL;
318 handle->share_name = NULL;
319 handle->sck_server = INVALID_SOCKET;
320 handle->conn_valid = FALSE;
321 __lwp_objmgr_open(&smb_handle_objects,&handle->object);
323 _CPU_ISR_Restore(level);
324 return handle;
327 static void __smb_free_handle(SMBHANDLE *handle)
329 if(handle->user) free(handle->user);
330 if(handle->pwd) free(handle->pwd);
331 if(handle->server_name) free(handle->server_name);
332 if(handle->share_name) free(handle->share_name);
334 handle->user = NULL;
335 handle->pwd = NULL;
336 handle->server_name = NULL;
337 handle->share_name = NULL;
338 handle->sck_server = INVALID_SOCKET;
340 __smb_handle_free(handle);
343 static void MakeSMBHeader(u8 command,u8 flags,u16 flags2,SMBHANDLE *handle)
345 u8 *ptr = handle->message.smb;
346 NBTSMB *nbt = &handle->message;
347 SMBSESSION *sess = &handle->session;
349 memset(nbt,0,sizeof(NBTSMB));
351 setUInt(ptr,SMB_OFFSET_PROTO,SMB_PROTO);
352 setUChar(ptr,SMB_OFFSET_CMD,command);
353 setUChar(ptr,SMB_OFFSET_FLAGS,flags);
354 setUShort(ptr,SMB_OFFSET_FLAGS2,flags2);
355 setUShort(ptr,SMB_OFFSET_TID,sess->TID);
356 setUShort(ptr,SMB_OFFSET_PID,sess->PID);
357 setUShort(ptr,SMB_OFFSET_UID,sess->UID);
358 setUShort(ptr,SMB_OFFSET_MID,sess->MID);
360 ptr[SMB_HEADER_SIZE] = 0;
364 * MakeTRANS2Hdr
366 static void MakeTRANS2Header(u8 subcommand,SMBHANDLE *handle)
368 u8 *ptr = handle->message.smb;
369 SMBSESSION *sess = &handle->session;
371 setUChar(ptr, T2_WORD_CNT, 15);
372 setUShort(ptr, T2_MAXPRM_CNT, 10);
373 setUShort(ptr, T2_MAXBUFFER, sess->MaxBuffer);
374 setUChar(ptr, T2_SSETUP_CNT, 1);
375 setUShort(ptr, T2_SUB_CMD, subcommand);
379 * smb_send
381 * blocking call with timeout
382 * will return when ALL data has been sent. Number of bytes sent is returned.
383 * OR timeout. Timeout will return -1
384 * OR network error. -ve value will be returned
386 static inline s32 smb_send(s32 s,const void *data,s32 size)
388 u64 t1,t2;
389 s32 ret, len = size;
391 t1=ticks_to_millisecs(gettime());
392 while(len>0)
394 ret=net_send(s,data,len,0);
395 if(ret==-EAGAIN)
397 t2=ticks_to_millisecs(gettime());
398 if( (t2 - t1) > RECV_TIMEOUT)
400 return -1; /* timeout */
402 usleep(100); /* allow system to perform work. Stabilizes system */
403 continue;
405 else if(ret<0)
407 return ret; /* some error happened */
409 else
411 data+=ret;
412 len-=ret;
413 if(len==0) return size;
414 t1=ticks_to_millisecs(gettime());
417 return size;
421 * smb_recv
423 * blocking call with timeout
424 * will return when ANY data has been read from socket. Number of bytes read is returned.
425 * OR timeout. Timeout will return -1
426 * OR network error. -ve value will be returned
428 static s32 smb_recv(s32 s,void *mem,s32 len)
430 s32 ret;
431 u64 t1,t2;
433 t1=ticks_to_millisecs(gettime());
434 while(1)
436 ret=net_recv(s,mem,len,0);
437 if(ret>=0) return ret;
438 if(ret!=-EAGAIN) break;
439 t2=ticks_to_millisecs(gettime());
440 if( (t2 - t1) > RECV_TIMEOUT)
442 ret=-1;
443 break;
445 usleep(100); /* allow system to perform work. Stabilizes system */
447 return ret;
451 * SMBCheck
453 * Do very basic checking on the return SMB
454 * Read <readlen> bytes
455 * if <readlen>==0 then read a single SMB packet
456 * discard any NBT_KEEPALIVE_MSG packets along the way.
458 static s32 SMBCheck(u8 command, s32 readlen,SMBHANDLE *handle)
460 s32 ret,recvd = 0;
461 u8 *ptr = handle->message.smb;
462 NBTSMB *nbt = &handle->message;
463 u8 *ptr2 = (u8*)nbt;
464 u8 tempLength = (readlen==0);
466 /* if length is not specified,*/
467 if(tempLength)
469 /* read entire header if available. if not, just get whatever available.*/
470 readlen = SMB_HEADER_SIZE+4;
473 memset(nbt,0,sizeof(NBTSMB));
476 /*keep going till we get all the data we wanted*/
477 while(recvd<readlen)
479 ret=smb_recv(handle->sck_server, ptr2+recvd, readlen-recvd);
480 if(ret<0)
482 return SMB_ERROR;
484 recvd+=ret;
485 /* discard any and all keepalive packets */
486 while( (nbt->msg==NBT_KEEPALIVE_MSG) && (recvd>=KEEPALIVE_SIZE) )
488 recvd-=KEEPALIVE_SIZE;
489 memmove(ptr2, ptr2+KEEPALIVE_SIZE, recvd);
491 /* obtain required length from NBT header if readlen==0*/
492 if(tempLength && recvd>=KEEPALIVE_SIZE)
494 /* get the length header */
495 if(nbt->flags!=0 || nbt->length>SMB_MAX_TRANSMIT_SIZE)
497 /*length too big to be supported*/
498 return SMB_BAD_DATALEN;
500 else
502 readlen = nbt->length+KEEPALIVE_SIZE;
503 tempLength = 0;
508 /*** Do basic SMB Header checks ***/
509 ret = getUInt(ptr,SMB_OFFSET_PROTO);
510 if(ret!=SMB_PROTO) return SMB_BAD_PROTOCOL;
512 ret = getUChar(ptr, SMB_OFFSET_CMD);
513 if(ret!=command) return SMB_BAD_COMMAND;
515 ret = getUInt(ptr,SMB_OFFSET_NTSTATUS);
516 if(ret) return SMB_ERROR;
518 return SMB_SUCCESS;
522 * SMB_SetupAndX
524 * Setup the SMB session, including authentication with the
525 * magic 'NTLM Response'
527 static s32 SMB_SetupAndX(SMBHANDLE *handle)
529 s32 pos;
530 s32 bcpos;
531 s32 i, ret;
532 u8 *ptr = handle->message.smb;
533 SMBSESSION *sess = &handle->session;
534 char pwd[200], ntRespData[24];
536 MakeSMBHeader(SMB_SETUP_ANDX,0x08,0x01,handle);
537 pos = SMB_HEADER_SIZE;
539 setUChar(ptr,pos,13);
540 pos++; /*** Word Count ***/
541 setUChar(ptr,pos,0xff);
542 pos++; /*** Next AndX ***/
543 pos++; /*** Reserved ***/
544 pos += 2; /*** Next AndX Offset ***/
545 setUShort(ptr,pos,sess->MaxBuffer);
546 pos += 2;
547 setUShort(ptr,pos,sess->MaxMpx);
548 pos += 2;
549 setUShort(ptr,pos,sess->MaxVCS);
550 pos += 2;
551 setUInt(ptr,pos,sess->sKey);
552 pos += 4;
553 setUShort(ptr,pos,0); /*** Password length (case-insensitive) ***/
554 pos += 2;
555 setUShort(ptr,pos,24); /*** Password length (case-sensitive) ***/
556 pos += 2;
557 pos += 4; /*** Reserved ***/
558 pos += 4; /*** Capabilities ***/
559 bcpos = pos;
560 pos += 2; /*** Byte count ***/
562 /*** The magic 'NTLM Response' ***/
563 strcpy(pwd, handle->pwd);
564 if (sess->challengeUsed)
565 ntlm_smb_nt_encrypt((const char *) pwd, (const u8 *) sess->challenge, (u8*) ntRespData);
567 /*** Build information ***/
568 memcpy(&ptr[pos],ntRespData,24);
569 pos += 24;
571 /*** Account ***/
572 strcpy(pwd, handle->user);
573 for(i=0;i<strlen(pwd);i++) pwd[i] = toupper(pwd[i]);
574 memcpy(&ptr[pos],pwd,strlen(pwd));
575 pos += strlen(pwd)+1;
577 /*** Primary Domain ***/
578 if(handle->user[0]=='\0') sess->p_domain[0] = '\0';
579 memcpy(&ptr[pos],sess->p_domain,strlen((const char*)sess->p_domain));
580 pos += strlen((const char*)sess->p_domain)+1;
582 /*** Native OS ***/
583 strcpy(pwd,"Unix (libOGC)");
584 memcpy(&ptr[pos],pwd,strlen(pwd));
585 pos += strlen(pwd)+1;
587 /*** Native LAN Manager ***/
588 strcpy(pwd,"Nintendo Wii");
589 memcpy(&ptr[pos],pwd,strlen(pwd));
590 pos += strlen (pwd)+1;
592 /*** Update byte count ***/
593 setUShort(ptr,bcpos,((pos-bcpos)-2));
595 handle->message.msg = NBT_SESSISON_MSG;
596 handle->message.length = htons (pos);
597 pos += 4;
599 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
600 if(ret<=0) return SMB_ERROR;
602 if((ret=SMBCheck(SMB_SETUP_ANDX,0,handle))==SMB_SUCCESS) {
603 /*** Collect UID ***/
604 sess->UID = getUShort(handle->message.smb,SMB_OFFSET_UID);
605 return SMB_SUCCESS;
607 return ret;
611 * SMB_TreeAndX
613 * Finally, net_connect to the remote share
615 static s32 SMB_TreeAndX(SMBHANDLE *handle)
617 s32 pos, bcpos, ret;
618 u8 path[256];
619 u8 *ptr = handle->message.smb;
620 SMBSESSION *sess = &handle->session;
622 MakeSMBHeader(SMB_TREEC_ANDX,0x08,0x01,handle);
623 pos = SMB_HEADER_SIZE;
625 setUChar(ptr,pos,4);
626 pos++; /*** Word Count ***/
627 setUChar(ptr,pos,0xff);
628 pos++; /*** Next AndX ***/
629 pos++; /*** Reserved ***/
630 pos += 2; /*** Next AndX Offset ***/
631 pos += 2; /*** Flags ***/
632 setUShort(ptr,pos,1);
633 pos += 2; /*** Password Length ***/
634 bcpos = pos;
635 pos += 2;
636 pos++; /*** NULL Password ***/
638 /*** Build server share path ***/
639 strcpy ((char*)path, "\\\\");
640 strcat ((char*)path, handle->server_name);
641 strcat ((char*)path, "\\");
642 strcat ((char*)path, handle->share_name);
643 for(ret=0;ret<strlen((const char*)path);ret++) path[ret] = toupper(path[ret]);
645 memcpy(&ptr[pos],path,strlen((const char*)path));
646 pos += strlen((const char*)path)+1;
648 /*** Service ***/
649 strcpy((char*)path,"?????");
650 memcpy(&ptr[pos],path,strlen((const char*)path));
651 pos += strlen((const char*)path)+1;
653 /*** Update byte count ***/
654 setUShort(ptr,bcpos,(pos-bcpos)-2);
656 handle->message.msg = NBT_SESSISON_MSG;
657 handle->message.length = htons (pos);
658 pos += 4;
660 ret = smb_send(handle->sck_server,(char *)&handle->message,pos);
661 if(ret<=0) return SMB_ERROR;
663 if((ret=SMBCheck(SMB_TREEC_ANDX,0,handle))==SMB_SUCCESS) {
664 /*** Collect Tree ID ***/
665 sess->TID = getUShort(handle->message.smb,SMB_OFFSET_TID);
666 return SMB_SUCCESS;
668 return ret;
672 * SMB_NegotiateProtocol
674 * The only protocol we admit to is 'NT LM 0.12'
676 static s32 SMB_NegotiateProtocol(const char *dialects[],int dialectc,SMBHANDLE *handle)
678 u8 *ptr;
679 s32 pos;
680 s32 bcnt,i,j;
681 s32 ret,len;
682 u16 bytecount;
683 u32 serverMaxBuffer;
684 SMBSESSION *sess;
686 if(!handle || !dialects || dialectc<=0)
687 return SMB_ERROR;
689 /*** Clear session variables ***/
690 sess = &handle->session;
691 memset(sess,0,sizeof(SMBSESSION));
692 sess->PID = 0xdead;
693 sess->MID = 1;
695 MakeSMBHeader(SMB_NEG_PROTOCOL,0x08,0x01,handle);
697 pos = SMB_HEADER_SIZE+3;
698 ptr = handle->message.smb;
699 for(i=0,bcnt=0;i<dialectc;i++) {
700 len = strlen(dialects[i])+1;
701 ptr[pos++] = '\x02';
702 memcpy(&ptr[pos],dialects[i],len);
703 pos += len;
704 bcnt += len+1;
706 /*** Update byte count ***/
707 setUShort(ptr,(SMB_HEADER_SIZE+1),bcnt);
709 /*** Set NBT information ***/
710 handle->message.msg = NBT_SESSISON_MSG;
711 handle->message.length = htons(pos);
712 pos += 4;
714 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
715 if(ret<=0) return SMB_ERROR;
717 /*** Check response ***/
718 if((ret=SMBCheck(SMB_NEG_PROTOCOL,0,handle))==SMB_SUCCESS)
720 pos = SMB_HEADER_SIZE;
721 ptr = handle->message.smb;
723 /*** Collect information ***/
724 if(getUChar(ptr,pos)!=17) return SMB_PROTO_FAIL; // UCHAR WordCount; Count of parameter words = 17
726 pos++;
727 if(getUShort(ptr,pos)!=0) return SMB_PROTO_FAIL; // USHORT DialectIndex; Index of selected dialect - should always be 0 since we only supplied 1!
729 pos += 2;
730 if(getUChar(ptr,pos)!=3)
732 // user level security
734 else
736 // share level security
739 pos++;
740 sess->MaxMpx = getUShort(ptr, pos); //USHORT MaxMpxCount; Max pending outstanding requests
742 pos += 2;
743 sess->MaxVCS = getUShort(ptr, pos); //USHORT MaxNumberVcs; Max VCs between client and server
745 pos += 2;
746 serverMaxBuffer = getUInt(ptr, pos); //ULONG MaxBufferSize; Max transmit buffer size
747 if(serverMaxBuffer>SMB_MAX_TRANSMIT_SIZE)
748 sess->MaxBuffer = SMB_MAX_TRANSMIT_SIZE;
749 else
750 sess->MaxBuffer = serverMaxBuffer;
752 pos += 4;
753 pos += 4; //ULONG MaxRawSize; Maximum raw buffer size
754 sess->sKey = getUInt(ptr,pos); pos += 4;
755 pos += 4; //ULONG Capabilities; Server capabilities
756 pos += 4; //ULONG SystemTimeLow; System (UTC) time of the server (low).
757 pos += 4; //ULONG SystemTimeHigh; System (UTC) time of the server (high).
758 sess->timeOffset = getShort(ptr,pos) * 600000000LL; pos += 2; //SHORT ServerTimeZone; Time zone of server (minutes from UTC)
760 //UCHAR EncryptionKeyLength - 0 or 8
761 if(getUChar(ptr,pos)!=8)
763 if (getUChar(ptr,pos)!=0)
765 return SMB_BAD_KEYLEN;
767 else
769 // Challenge key not used
770 sess->challengeUsed = false;
773 else
775 sess->challengeUsed = true;
778 pos++;
779 bytecount = getUShort(ptr,pos);
781 if (sess->challengeUsed)
783 /*** Copy challenge key ***/
784 pos += 2;
785 memcpy(&sess->challenge,&ptr[pos],8);
788 /*** Primary domain ***/
789 pos += 8;
790 i = j = 0;
791 while(ptr[pos+j]!=0) {
792 sess->p_domain[i] = ptr[pos+j];
793 j += 2;
794 i++;
796 sess->p_domain[i] = '\0';
798 return SMB_SUCCESS;
801 return ret;
804 static s32 do_netconnect(SMBHANDLE *handle)
806 u32 nodelay;
807 s32 ret;
808 s32 sock;
809 u32 flags=0;
810 u64 t1,t2;
812 /*** Create the global net_socket ***/
813 sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
814 if(sock==INVALID_SOCKET) return -1;
816 /*** Switch off Nagle, ON TCP_NODELAY ***/
817 nodelay = 1;
818 ret = net_setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,&nodelay,sizeof(nodelay));
820 //create non blocking socket
821 flags = net_fcntl(sock, F_GETFL, 0);
822 flags |= IOS_O_NONBLOCK;
823 ret=net_fcntl(sock, F_SETFL, flags);
825 t1=ticks_to_millisecs(gettime());
828 ret = net_connect(sock,(struct sockaddr*)&handle->server_addr,sizeof(handle->server_addr));
829 t2=ticks_to_millisecs(gettime());
830 usleep(1000);
831 if(t2-t1 > 6000) break; // 6 secs to try to connect to handle->server_addr
832 } while(ret!=-127);
834 if(ret!=-127)
836 net_close(sock);
837 return -1;
840 handle->sck_server = sock;
841 return 0;
844 static s32 do_smbconnect(SMBHANDLE *handle)
846 s32 ret;
848 ret = SMB_NegotiateProtocol(smb_dialects,smb_dialectcnt,handle);
849 if(ret!=SMB_SUCCESS)
851 net_close(handle->sck_server);
852 return -1;
855 ret = SMB_SetupAndX(handle);
856 if(ret!=SMB_SUCCESS)
858 net_close(handle->sck_server);
859 return -1;
862 ret = SMB_TreeAndX(handle);
863 if(ret!=SMB_SUCCESS)
865 net_close(handle->sck_server);
866 return -1;
869 handle->conn_valid = TRUE;
870 return 0;
873 /****************************************************************************
874 * Create an NBT SESSION REQUEST message.
875 ****************************************************************************/
876 static int MakeSessReq(unsigned char *bufr, unsigned char *Called, unsigned char *Calling)
878 // Write the header.
879 bufr[0] = SESS_REQ;
880 bufr[1] = 0;
881 bufr[2] = 0;
882 bufr[3] = 68; // 2x34 bytes in length.
884 // Copy the Called and Calling names into the buffer.
885 (void) memcpy(&bufr[4], Called, 34);
886 (void) memcpy(&bufr[38], Calling, 34);
888 // Return the total message length.
889 return 72;
892 static unsigned char *L1_Encode(unsigned char *dst, const unsigned char *name,
893 const unsigned char pad, const unsigned char sfx)
895 int i = 0;
896 int j = 0;
897 int k = 0;
899 while (('\0' != name[i]) && (i < 15))
901 k = toupper(name[i++]);
902 dst[j++] = 'A' + ((k & 0xF0) >> 4);
903 dst[j++] = 'A' + (k & 0x0F);
906 i = 'A' + ((pad & 0xF0) >> 4);
907 k = 'A' + (pad & 0x0F);
908 while (j < 30)
910 dst[j++] = i;
911 dst[j++] = k;
914 dst[30] = 'A' + ((sfx & 0xF0) >> 4);
915 dst[31] = 'A' + (sfx & 0x0F);
916 dst[32] = '\0';
918 return (dst);
921 static int L2_Encode(unsigned char *dst, const unsigned char *name,
922 const unsigned char pad, const unsigned char sfx,
923 const unsigned char *scope)
925 int lenpos;
926 int i;
927 int j;
929 if (NULL == L1_Encode(&dst[1], name, pad, sfx))
930 return (-1);
932 dst[0] = 0x20;
933 lenpos = 33;
935 if ('\0' != *scope)
939 for (i = 0, j = (lenpos + 1); ('.' != scope[i]) && ('\0'
940 != scope[i]); i++, j++)
941 dst[j] = toupper(scope[i]);
943 dst[lenpos] = (unsigned char) i;
944 lenpos += i + 1;
945 scope += i;
946 } while ('.' == *(scope++));
948 dst[lenpos] = '\0';
951 return (lenpos + 1);
954 /****************************************************************************
955 * Send an NBT SESSION REQUEST over the TCP connection, then wait for a reply.
956 ****************************************************************************/
957 static s32 SMB_RequestNBTSession(SMBHANDLE *handle)
959 unsigned char Called[34];
960 unsigned char Calling[34];
961 unsigned char bufr[128];
962 int result;
964 L2_Encode(Called, (const unsigned char*) "*SMBSERVER", 0x20, 0x20,
965 (const unsigned char*) "");
966 L2_Encode(Calling, (const unsigned char*) "SMBCLIENT", 0x20, 0x00,
967 (const unsigned char*) "");
969 // Create the NBT Session Request message.
970 result = MakeSessReq(bufr, Called, Calling);
972 //Send the NBT Session Request message.
973 result = smb_send(handle->sck_server, bufr, result);
974 if (result < 0)
976 // Error sending Session Request message
977 return -1;
980 // Now wait for and handle the reply (2 seconds).
981 result = smb_recv(handle->sck_server, bufr, 128);
982 if (result <= 0)
984 // Timeout waiting for NBT Session Response
985 return -1;
988 switch (*bufr)
990 case SESS_POS_RESP:
991 // Positive Session Response
992 return 0;
994 case SESS_NEG_RESP:
995 // Negative Session Response
996 return -1;
998 case SESS_RETARGET:
999 // Retarget Session Response
1000 return -1;
1002 default:
1003 // Unexpected Session Response
1004 return -1;
1008 /****************************************************************************
1009 * Primary setup, logon and connection all in one :)
1010 ****************************************************************************/
1011 s32 SMB_Connect(SMBCONN *smbhndl, const char *user, const char *password, const char *share, const char *server)
1013 s32 ret = 0;
1014 SMBHANDLE *handle;
1015 struct hostent *hp;
1016 struct in_addr val;
1018 if(!user || !password || !share || !server ||
1019 strlen(user) > 20 || strlen(password) > 14 ||
1020 strlen(share) > 80 || strlen(server) > 80)
1022 return SMB_BAD_LOGINDATA;
1025 *smbhndl = SMB_HANDLE_NULL;
1027 if(smb_inited==FALSE)
1029 u32 level;
1030 _CPU_ISR_Disable(level);
1031 __smb_init();
1032 _CPU_ISR_Restore(level);
1035 handle = __smb_allocate_handle();
1036 if(!handle) return SMB_ERROR;
1038 handle->user = strdup(user);
1039 handle->pwd = strdup(password);
1040 handle->server_name = strdup(server);
1041 handle->share_name = strdup(share);
1042 handle->server_addr.sin_family = AF_INET;
1043 handle->server_addr.sin_port = htons(445);
1045 if(strlen(server) < 16 && inet_aton(server, &val))
1047 handle->server_addr.sin_addr.s_addr = val.s_addr;
1049 else // might be a hostname
1051 hp = net_gethostbyname(server);
1052 if (!hp || !(hp->h_addrtype == PF_INET))
1053 ret = SMB_BAD_LOGINDATA;
1054 else
1055 memcpy((char *)&handle->server_addr.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
1058 if(ret==0)
1060 ret = do_netconnect(handle);
1061 if(ret==0) ret = do_smbconnect(handle);
1063 if(ret!=0)
1065 // try port 139
1066 handle->server_addr.sin_port = htons(139);
1067 ret = do_netconnect(handle);
1068 if(ret==0) ret = SMB_RequestNBTSession(handle);
1069 if(ret==0) ret = do_smbconnect(handle);
1072 if(ret!=0)
1074 __smb_free_handle(handle);
1075 return SMB_ERROR;
1077 else
1079 *smbhndl =(SMBCONN)(LWP_OBJMASKTYPE(SMB_OBJTYPE_HANDLE)|LWP_OBJMASKID(handle->object.id));
1080 return SMB_SUCCESS;
1084 /****************************************************************************
1085 * SMB_Destroy
1087 * Probably NEVER called on GameCube, but here for completeness
1088 ****************************************************************************/
1089 void SMB_Close(SMBCONN smbhndl)
1091 SMBHANDLE *handle;
1093 handle = __smb_handle_open(smbhndl);
1094 if(!handle) return;
1096 if(handle->sck_server!=INVALID_SOCKET) net_close(handle->sck_server);
1097 __smb_free_handle(handle);
1100 s32 SMB_Reconnect(SMBCONN *_smbhndl, BOOL test_conn)
1102 s32 ret = SMB_SUCCESS;
1103 SMBCONN smbhndl = *_smbhndl;
1104 SMBHANDLE *handle = __smb_handle_open(smbhndl);
1105 if(!handle)
1106 return SMB_ERROR; // we have no handle, so we can't reconnect
1108 if(handle->conn_valid && test_conn)
1110 SMBDIRENTRY dentry;
1111 if(SMB_PathInfo("\\", &dentry, smbhndl)==SMB_SUCCESS) return SMB_SUCCESS; // no need to reconnect
1112 handle->conn_valid = FALSE; // else connection is invalid
1115 if(!handle->conn_valid)
1117 // shut down connection
1118 if(handle->sck_server!=INVALID_SOCKET)
1119 net_close(handle->sck_server);
1121 // reconnect
1122 ret = do_netconnect(handle);
1123 if(handle->server_addr.sin_port == htons(139))
1124 if(ret==0) ret = SMB_RequestNBTSession(handle);
1125 if(ret==0) ret = do_smbconnect(handle);
1127 return ret;
1130 SMBFILE SMB_OpenFile(const char *filename, u16 access, u16 creation,SMBCONN smbhndl)
1132 s32 pos;
1133 s32 bpos,ret;
1134 u8 *ptr;
1135 struct _smbfile *fid = NULL;
1136 SMBHANDLE *handle;
1137 char realfile[256];
1139 if(filename == NULL)
1140 return NULL;
1142 if(SMB_Reconnect(&smbhndl,TRUE)!=SMB_SUCCESS) return NULL;
1144 handle = __smb_handle_open(smbhndl);
1145 if(!handle) return NULL;
1147 MakeSMBHeader(SMB_OPEN_ANDX,0x08,0x01,handle);
1149 pos = SMB_HEADER_SIZE;
1150 ptr = handle->message.smb;
1151 setUChar(ptr, pos, 15);
1152 pos++; /*** Word Count ***/
1153 setUChar(ptr, pos, 0xff);
1154 pos++; /*** Next AndX ***/
1155 pos += 3; /*** Next AndX Offset ***/
1157 pos += 2; /*** Flags ***/
1158 setUShort(ptr, pos, access);
1159 pos += 2; /*** Access mode ***/
1160 setUShort(ptr, pos, 0x6);
1161 pos += 2; /*** Type of file ***/
1162 pos += 2; /*** Attributes ***/
1163 pos += 4; /*** File time - don't care - let server decide ***/
1164 setUShort(ptr, pos, creation);
1165 pos += 2; /*** Creation flags ***/
1166 pos += 4; /*** Allocation size ***/
1167 pos += 8; /*** Reserved ***/
1168 pos += 2; /*** Byte Count ***/
1169 bpos = pos;
1171 if (filename[0] != '\\') {
1172 strcpy(realfile, "\\");
1173 strcat(realfile,filename);
1174 } else
1175 strcpy(realfile,filename);
1177 memcpy(&ptr[pos],realfile,strlen(realfile));
1178 pos += strlen(realfile)+1;
1180 setUShort(ptr,(bpos-2),(pos-bpos));
1182 handle->message.msg = NBT_SESSISON_MSG;
1183 handle->message.length = htons(pos);
1185 pos += 4;
1186 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1187 if(ret<0) goto failed;
1189 if(SMBCheck(SMB_OPEN_ANDX,0,handle)==SMB_SUCCESS) {
1190 /*** Check file handle ***/
1191 fid = (struct _smbfile*)__lwp_queue_get(&smb_filehandle_queue);
1192 if(fid) {
1193 fid->conn = smbhndl;
1194 fid->sfid = getUShort(handle->message.smb,(SMB_HEADER_SIZE+5));
1197 return (SMBFILE)fid;
1199 failed:
1200 handle->conn_valid = FALSE;
1201 return NULL;
1205 * SMB_Close
1207 void SMB_CloseFile(SMBFILE sfid)
1209 u8 *ptr;
1210 s32 pos, ret;
1211 SMBHANDLE *handle;
1212 struct _smbfile *fid = (struct _smbfile*)sfid;
1214 if(!fid) return;
1216 handle = __smb_handle_open(fid->conn);
1217 if(!handle) return;
1219 MakeSMBHeader(SMB_CLOSE,0x08,0x01,handle);
1221 pos = SMB_HEADER_SIZE;
1222 ptr = handle->message.smb;
1223 setUChar(ptr, pos, 3);
1224 pos++; /** Word Count **/
1225 setUShort(ptr, pos, fid->sfid);
1226 pos += 2;
1227 setUInt(ptr, pos, 0xffffffff);
1228 pos += 4; /*** Last Write ***/
1229 pos += 2; /*** Byte Count ***/
1231 handle->message.msg = NBT_SESSISON_MSG;
1232 handle->message.length = htons(pos);
1234 pos += 4;
1235 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1236 if(ret<0) handle->conn_valid = FALSE;
1237 else SMBCheck(SMB_CLOSE,0,handle);
1238 __lwp_queue_append(&smb_filehandle_queue,&fid->node);
1242 * SMB_Read
1244 s32 SMB_ReadFile(char *buffer, size_t size, off_t offset, SMBFILE sfid)
1246 u8 *ptr,*dest;
1247 s32 pos, ret, ofs;
1248 u16 length = 0;
1249 SMBHANDLE *handle;
1250 struct _smbfile *fid = (struct _smbfile*)sfid;
1252 if(!fid) return 0;
1254 // Check for invalid size
1255 if(size == 0 || size > SMB_MAX_BUFFERSIZE) return 0;
1257 handle = __smb_handle_open(fid->conn);
1258 if(!handle) return 0;
1260 MakeSMBHeader(SMB_READ_ANDX,0x08,0x01,handle);
1262 pos = SMB_HEADER_SIZE;
1263 ptr = handle->message.smb;
1264 setUChar(ptr, pos, 10);
1265 pos++; /*** Word count ***/
1266 setUChar(ptr, pos, 0xff);
1267 pos++;
1268 pos += 3; /*** Reserved, Next AndX Offset ***/
1269 setUShort(ptr, pos, fid->sfid);
1270 pos += 2; /*** FID ***/
1271 setUInt(ptr, pos, offset);
1272 pos += 4; /*** Offset ***/
1274 setUShort(ptr, pos, size & 0xffff);
1275 pos += 2;
1276 setUShort(ptr, pos, size & 0xffff);
1277 pos += 2;
1278 setUInt(ptr, pos, 0);
1279 pos += 4;
1280 pos += 2; /*** Remaining ***/
1281 pos += 2; /*** Byte count ***/
1283 handle->message.msg = NBT_SESSISON_MSG;
1284 handle->message.length = htons(pos);
1286 pos += 4;
1287 ret = smb_send(handle->sck_server,(char*)&handle->message, pos);
1288 if(ret<0) goto failed;
1290 /*** SMBCheck should now only read up to the end of a standard header ***/
1291 if((ret=SMBCheck(SMB_READ_ANDX,(SMB_HEADER_SIZE+27+4),handle))==SMB_SUCCESS) {
1292 ptr = handle->message.smb;
1293 /*** Retrieve data length for this packet ***/
1294 length = getUShort(ptr,(SMB_HEADER_SIZE+11));
1295 /*** Retrieve offset to data ***/
1296 ofs = getUShort(ptr,(SMB_HEADER_SIZE+13));
1298 /*** Default offset, with no padding is 59, so grab any outstanding padding ***/
1299 while(ofs>SMB_DEF_READOFFSET) {
1300 char pad[1024];
1301 ret = smb_recv(handle->sck_server,pad,(ofs-SMB_DEF_READOFFSET));
1302 if(ret<0) return ret;
1303 ofs-=ret;
1306 /*** Finally, go grab the data ***/
1307 ofs = 0;
1308 dest = (u8*)buffer;
1309 if(length>0) {
1310 while ((ret=smb_recv(handle->sck_server,&dest[ofs],length-ofs))!=0) {
1311 if(ret<0) return ret;
1313 ofs += ret;
1314 if (ofs>=length) break;
1317 return ofs;
1319 return 0;
1321 failed:
1322 handle->conn_valid = FALSE;
1323 return ret;
1327 * SMB_Write
1329 s32 SMB_WriteFile(const char *buffer, size_t size, off_t offset, SMBFILE sfid)
1331 u8 *ptr,*src;
1332 s32 pos, ret;
1333 s32 blocks64;
1334 u32 copy_len;
1335 SMBHANDLE *handle;
1336 struct _smbfile *fid = (struct _smbfile*)sfid;
1338 if(!fid) return 0;
1340 handle = __smb_handle_open(fid->conn);
1341 if(!handle) return SMB_ERROR;
1343 MakeSMBHeader(SMB_WRITE_ANDX,0x08,0x01,handle);
1345 pos = SMB_HEADER_SIZE;
1346 ptr = handle->message.smb;
1347 setUChar(ptr, pos, 12);
1348 pos++; /*** Word Count ***/
1349 setUChar(ptr, pos, 0xff);
1350 pos += 2; /*** Next AndX ***/
1351 pos += 2; /*** Next AndX Offset ***/
1353 setUShort(ptr, pos, fid->sfid);
1354 pos += 2;
1355 setUInt(ptr, pos, offset);
1356 pos += 4;
1357 pos += 4; /*** Reserved ***/
1358 pos += 2; /*** Write Mode ***/
1359 pos += 2; /*** Remaining ***/
1361 blocks64 = size >> 16;
1363 setUShort(ptr, pos, blocks64);
1364 pos += 2; /*** Length High ***/
1365 setUShort(ptr, pos, size & 0xffff);
1366 pos += 2; /*** Length Low ***/
1367 setUShort(ptr, pos, 59);
1368 pos += 2; /*** Data Offset ***/
1369 setUShort(ptr, pos, size & 0xffff);
1370 pos += 2; /*** Data Byte Count ***/
1372 handle->message.msg = NBT_SESSISON_MSG;
1373 handle->message.length = htons(pos+size);
1375 src = (u8*)buffer;
1376 copy_len = size;
1377 if((copy_len+pos)>SMB_MAX_TRANSMIT_SIZE) copy_len = (SMB_MAX_TRANSMIT_SIZE-pos);
1379 memcpy(&ptr[pos],src,copy_len);
1380 size -= copy_len;
1381 src += copy_len;
1382 pos += copy_len;
1384 pos += 4;
1386 /*** Send Header Information ***/
1387 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1388 if(ret<0) goto failed;
1390 if(size>0) {
1391 /*** Send the data ***/
1392 ret = smb_send(handle->sck_server,src,size);
1393 if(ret<0) goto failed;
1396 ret = 0;
1397 if(SMBCheck(SMB_WRITE_ANDX,0,handle)==SMB_SUCCESS) {
1398 ptr = handle->message.smb;
1399 ret = getUShort(ptr,(SMB_HEADER_SIZE+5));
1402 return ret;
1404 failed:
1405 handle->conn_valid = FALSE;
1406 return ret;
1410 * SMB_PathInfo
1412 s32 SMB_PathInfo(const char *filename, SMBDIRENTRY *sdir, SMBCONN smbhndl)
1414 u8 *ptr;
1415 s32 pos;
1416 s32 ret;
1417 s32 bpos;
1418 SMBHANDLE *handle;
1419 char realfile[256];
1421 if(filename == NULL)
1422 return SMB_ERROR;
1424 handle = __smb_handle_open(smbhndl);
1425 if (!handle) return SMB_ERROR;
1427 MakeSMBHeader(SMB_TRANS2, 0x08, 0x01, handle);
1428 MakeTRANS2Header(SMB_QUERY_PATH_INFO, handle);
1430 bpos = pos = (T2_BYTE_CNT + 2);
1431 pos += 3; /*** Padding ***/
1432 ptr = handle->message.smb;
1433 setUShort(ptr, pos, SMB_QUERY_FILE_ALL_INFO);
1435 pos += 2;
1436 setUInt(ptr, pos, 0);
1437 pos += 4; /*** reserved ***/
1439 if (filename[0] != '\\') {
1440 strcpy(realfile, "\\");
1441 strcat(realfile, filename);
1442 } else
1443 strcpy(realfile, filename);
1445 memcpy(&ptr[pos], realfile, strlen(realfile));
1446 pos += strlen(realfile) + 1; /*** Include padding ***/
1448 /*** Update counts ***/
1449 setUShort(ptr, T2_PRM_CNT, (7 + strlen(realfile)));
1450 setUShort(ptr, T2_SPRM_CNT, (7 + strlen(realfile)));
1451 setUShort(ptr, T2_SPRM_OFS, 68);
1452 setUShort(ptr, T2_SDATA_OFS, (75 + strlen(realfile)));
1453 setUShort(ptr, T2_BYTE_CNT, (pos - bpos));
1455 handle->message.msg = NBT_SESSISON_MSG;
1456 handle->message.length = htons(pos);
1458 pos += 4;
1459 ret = smb_send(handle->sck_server, (char*) &handle->message, pos);
1460 if(ret<0) goto failed;
1462 ret = SMB_ERROR;
1463 if (SMBCheck(SMB_TRANS2, 0, handle) == SMB_SUCCESS) {
1465 ptr = handle->message.smb;
1466 /*** Get parameter offset ***/
1467 pos = getUShort(ptr, (SMB_HEADER_SIZE + 9));
1468 pos += 4; // padding
1469 sdir->ctime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - creation time
1470 sdir->atime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - access time
1471 sdir->mtime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - write time
1472 pos += 8; // ULONGLONG - change time
1473 sdir->attributes = getUInt(ptr,pos); pos += 4; // ULONG - file attributes
1474 pos += 4; // padding
1475 pos += 8; // ULONGLONG - allocated file size
1476 sdir->size = getULongLong(ptr, pos); pos += 8; // ULONGLONG - file size
1477 pos += 4; // ULONG NumberOfLinks;
1478 pos += 2; // UCHAR DeletePending;
1479 pos += 2; // UCHAR Directory;
1480 pos += 2; // USHORT Pad2; // for alignment only
1481 pos += 4; // ULONG EaSize;
1482 pos += 4; // ULONG FileNameLength;
1484 strcpy(sdir->name,realfile);
1486 ret = SMB_SUCCESS;
1488 return ret;
1490 failed:
1491 handle->conn_valid = FALSE;
1492 return ret;
1496 * SMB_FindFirst
1498 * Uses TRANS2 to support long filenames
1500 s32 SMB_FindFirst(const char *filename, unsigned short flags, SMBDIRENTRY *sdir, SMBCONN smbhndl)
1502 u8 *ptr;
1503 s32 pos;
1504 s32 ret;
1505 s32 bpos;
1506 SMBHANDLE *handle;
1507 SMBSESSION *sess;
1509 if(filename == NULL)
1510 return SMB_ERROR;
1512 if(SMB_Reconnect(&smbhndl,TRUE)!=SMB_SUCCESS) return SMB_ERROR;
1514 handle = __smb_handle_open(smbhndl);
1515 if(!handle) return SMB_ERROR;
1517 sess = &handle->session;
1518 MakeSMBHeader(SMB_TRANS2,0x08,0x01,handle);
1519 MakeTRANS2Header(SMB_FIND_FIRST2,handle);
1521 bpos = pos = (T2_BYTE_CNT+2);
1522 pos += 3; /*** Padding ***/
1523 ptr = handle->message.smb;
1524 setUShort(ptr, pos, flags);
1525 pos += 2; /*** Flags ***/
1526 setUShort(ptr, pos, 1);
1527 pos += 2; /*** Count ***/
1528 setUShort(ptr, pos, 6);
1529 pos += 2; /*** Internal Flags ***/
1530 setUShort(ptr, pos, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
1531 pos += 2; /*** Level of Interest ***/
1532 pos += 4; /*** Storage Type == 0 ***/
1533 memcpy(&ptr[pos], filename, strlen(filename));
1534 pos += strlen(filename)+1; /*** Include padding ***/
1536 /*** Update counts ***/
1537 setUShort(ptr, T2_PRM_CNT, (13+strlen(filename)));
1538 setUShort(ptr, T2_SPRM_CNT, (13+strlen(filename)));
1539 setUShort(ptr, T2_SPRM_OFS, 68);
1540 setUShort(ptr, T2_SDATA_OFS,(81+strlen(filename)));
1541 setUShort(ptr, T2_BYTE_CNT,(pos-bpos));
1543 handle->message.msg = NBT_SESSISON_MSG;
1544 handle->message.length = htons(pos);
1546 pos += 4;
1547 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1548 if(ret<0) goto failed;
1550 sess->eos = 1;
1551 sess->sid = 0;
1552 sess->count = 0;
1553 ret = SMB_ERROR;
1554 if(SMBCheck(SMB_TRANS2,0,handle)==SMB_SUCCESS) {
1555 ptr = handle->message.smb;
1556 /*** Get parameter offset ***/
1557 pos = getUShort(ptr,(SMB_HEADER_SIZE+9));
1558 sess->sid = getUShort(ptr, pos); pos += 2;
1559 sess->count = getUShort(ptr, pos); pos += 2;
1560 sess->eos = getUShort(ptr, pos); pos += 2;
1561 pos += 2; // USHORT EaErrorOffset;
1562 pos += 2; // USHORT LastNameOffset;
1563 pos += 2; // padding?
1565 if (sess->count)
1567 pos += 4; // ULONG NextEntryOffset;
1568 pos += 4; // ULONG FileIndex;
1569 sdir->ctime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - creation time
1570 sdir->atime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - access time
1571 sdir->mtime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - write time
1572 pos += 8; // ULONGLONG - change time low
1573 sdir->size = getULongLong(ptr, pos); pos += 8;
1574 pos += 8;
1575 sdir->attributes = getUInt(ptr, pos); pos += 4;
1576 pos += 34;
1577 strcpy(sdir->name, (const char*)&ptr[pos]);
1579 ret = SMB_SUCCESS;
1582 return ret;
1584 failed:
1585 handle->conn_valid = FALSE;
1586 return ret;
1590 * SMB_FindNext
1592 s32 SMB_FindNext(SMBDIRENTRY *sdir,SMBCONN smbhndl)
1594 u8 *ptr;
1595 s32 pos;
1596 s32 ret;
1597 s32 bpos;
1598 SMBHANDLE *handle;
1599 SMBSESSION *sess;
1601 handle = __smb_handle_open(smbhndl);
1602 if(!handle) return SMB_ERROR;
1604 sess = &handle->session;
1605 if(sess->eos || sess->sid==0) return SMB_ERROR;
1607 MakeSMBHeader(SMB_TRANS2,0x08,0x01,handle);
1608 MakeTRANS2Header(SMB_FIND_NEXT2,handle);
1610 bpos = pos = (T2_BYTE_CNT+2);
1611 pos += 3; /*** Padding ***/
1612 ptr = handle->message.smb;
1613 setUShort(ptr, pos, sess->sid);
1614 pos += 2; /*** Search ID ***/
1615 setUShort(ptr, pos, 1);
1616 pos += 2; /*** Count ***/
1617 setUShort(ptr, pos, 260); // SMB_FIND_FILE_BOTH_DIRECTORY_INFO
1618 pos += 2; /*** Level of Interest ***/
1619 pos += 4; /*** Storage Type == 0 ***/
1620 setUShort(ptr, pos, 12);
1621 pos+=2; /*** Search flags ***/
1622 pos++;
1624 /*** Update counts ***/
1625 setUShort(ptr, T2_PRM_CNT, 13);
1626 setUShort(ptr, T2_SPRM_CNT, 13);
1627 setUShort(ptr, T2_SPRM_OFS, 68);
1628 setUShort(ptr, T2_SDATA_OFS, 81);
1629 setUShort(ptr, T2_BYTE_CNT, (pos-bpos));
1631 handle->message.msg = NBT_SESSISON_MSG;
1632 handle->message.length = htons(pos);
1634 pos += 4;
1635 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1636 if(ret<0) goto failed;
1638 ret = SMB_ERROR;
1639 if (SMBCheck(SMB_TRANS2,0,handle)==SMB_SUCCESS) {
1640 ptr = handle->message.smb;
1641 /*** Get parameter offset ***/
1642 pos = getUShort(ptr,(SMB_HEADER_SIZE+9));
1643 sess->count = getUShort(ptr, pos); pos += 2;
1644 sess->eos = getUShort(ptr, pos); pos += 2;
1645 pos += 2; // USHORT EaErrorOffset;
1646 pos += 2; // USHORT LastNameOffset;
1648 if (sess->count)
1650 pos += 4; // ULONG NextEntryOffset;
1651 pos += 4; // ULONG FileIndex;
1652 sdir->ctime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - creation time
1653 sdir->atime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - access time
1654 sdir->mtime = getULongLong(ptr, pos) - handle->session.timeOffset; pos += 8; // ULONGLONG - write time
1655 pos += 8; // ULONGLONG - change time low
1656 sdir->size = getULongLong(ptr, pos); pos += 8;
1657 pos += 8;
1658 sdir->attributes = getUInt(ptr, pos); pos += 4;
1659 pos += 34;
1660 strcpy (sdir->name, (const char*)&ptr[pos]);
1662 ret = SMB_SUCCESS;
1665 return ret;
1667 failed:
1668 handle->conn_valid = FALSE;
1669 return ret;
1673 * SMB_FindClose
1675 s32 SMB_FindClose(SMBCONN smbhndl)
1677 u8 *ptr;
1678 s32 pos;
1679 s32 ret;
1680 SMBHANDLE *handle;
1681 SMBSESSION *sess;
1683 handle = __smb_handle_open(smbhndl);
1684 if(!handle) return SMB_ERROR;
1686 sess = &handle->session;
1687 if(sess->sid==0) return SMB_ERROR;
1689 MakeSMBHeader(SMB_FIND_CLOSE2,0x08,0x01,handle);
1691 pos = SMB_HEADER_SIZE;
1692 ptr = handle->message.smb;
1693 setUChar(ptr, pos, 1);
1694 pos++; /*** Word Count ***/
1695 setUShort(ptr, pos, sess->sid);
1696 pos += 2;
1697 pos += 2; /*** Byte Count ***/
1699 handle->message.msg = NBT_SESSISON_MSG;
1700 handle->message.length = htons(pos);
1702 pos += 4;
1703 ret = smb_send(handle->sck_server,(char*)&handle->message,pos);
1704 if(ret<0) goto failed;
1706 ret = SMBCheck(SMB_FIND_CLOSE2,0,handle);
1707 return ret;
1709 failed:
1710 handle->conn_valid = FALSE;
1711 return ret;