UCHAR Protocol[4]; //4字节}
UCHAR Command; //1字节
SMB_ERROR Status; //4字节
UCHAR Flags; //1字节
USHORT Flags2; //2字节
USHORT PIDHigh; //2字节
UCHAR SecurityFeatures[8]; //8字节 =4 key+2 CID+2 sequenceNumber
USHORT Reserved; //2字节
USHORT TID; //2字节
USHORT PIDLow; //2字节
USHORT UID; //2字节
USHORT MID; //2字节
SMB_Data //数据块UCHAR WordCount; //1字节
USHORT Words[WordCount] (variable); //2字节*n 最后一项为空
}
USHORT ByteCount; //2字节
UCHAR Bytes[ByteCount] (variable); //1字节*n
}
(注:数据为空时包的长度为39,此时 参数块和数据块均为空)
AndX //批处理消息(只发送一次命令头,然后是 参数/数据块对,链表以一个空命令结束)UCHAR AndXCommand;//1字节,下一个数据块对的命令码
UCHAR AndXReserved;//1字节,为0x0000
USHORT AndXOffset;//1字节,下一个数据块相对命令头的偏移
}
SMB 命令:(按功能分)
Session management:会话管理
SMB_COM_NEGOTIATE: 0x72 协义协商(当前使用)
SMB_COM_SESSION_SETUP_ANDX: 0x73 开始一个AndX链会话(当前使用)
SMB_COM_TREE_CONNECT: 0x70 连接到一个共享(不推荐)
SMB_COM_TREE_CONNECT_ANDX: 0x75 tree连接用andX链(当前使用)[0x76-0x7d unused]
SMB_COM_TREE_DISCONNECT: 0x71 断开一个共享(当前使用)
SMB_COM_LOGOFF_ANDX: 0x74 用户退出用AndX链(当前使用)
Transaction subprotocol:传输子协议
SMB_COM_TRANSACTION: 0x25 传输(当前使用)
SMB_COM_TRANSACTION_SECONDARY:0x26 传输子请求(当前使用)
SMB_COM_TRANSACTION2: 0x32 传输两种格式请求/响应(当前使用)
SMB_COM_TRANSACTION2_SECONDARY:0x33 传输二级子请求(当前使用)
SMB_COM_NT_TRANSACT: 0xa0 NT格式的请求/响应(当前使用)
SMB_COM_NT_TRANSACT_SECONDARY:0xa1 NT格式的传输子请求
File/directory access methods:文件/目录访问
SMB_COM_CREATE_DIRECTORY: 0x00 创建一个目录(不推荐)
SMB_COM_DELETE_DIRECTORY: 0x01 删除一个空目录(当前使用)
SMB_COM_OPEN: 0x02 打开一个文件(不推荐)
SMB_COM_OPEN_ANDX: 0x2d 打开一个扩展文件(不推荐)
SMB_COM_CREATE: 0x03 创建或打开一个文件(不推荐)
SMB_COM_CREATE_NEW: 0x0f 创建或打开一个新的文件(不推荐)
SMB_COM_CREATE_TEMPORARY: 0x0e 创建一个临时文件(obsolescent)
SMB_COM_NT_CREATE_ANDX: 0xa2 创建或打开一个目录(当前使用)
SMB_COM_CLOSE: 0x04 关闭一个文件(当前使用)
SMB_COM_DELETE: 0x06 删除一个文件(当前使用)
Read/write/lock methods:读/写/锁方法
SMB_COM_FLUSH: 0x05 刷新文件(当前使用)
SMB_COM_SEEK: 0x12 (obsolescent)
SMB_COM_READ: 0x0a 从文件读(不推荐)
SMB_COM_LOCK_AND_READ: 0x13 锁定并且读取一个字节范围的文件(不推荐)
SMB_COM_LOCK_BYTE_RANGE: 0x0c 请求一个字节范围锁(不推荐)
SMB_COM_UNLOCK_BYTE_RANGE: 0x0d 释放字节范围锁(不推荐)
SMB_COM_LOCKING_ANDX: 0x24 锁定多字节范围,AndX链(当前使用)
SMB_COM_READ_ANDX: 0x2e 读扩展文件用AndX链(当前使用)
SMB_COM_READ_RAW: 0x1a 读一个块以raw模式(不推荐)
SMB_COM_READ_MPX: 0x1b 多点读块(已废除)
SMB_COM_WRITE: 0x0b 从文件写(不推荐)
SMB_COM_WRITE_AND_CLOSE: 0x2c 写并关闭文件(不推荐)
SMB_COM_WRITE_AND_UNLOCK: 0x14 写并解锁一个字节范围的文件(不推荐)[0x15-0x19 未使用]
SMB_COM_WRITE_ANDX: 0x2f 写扩展文件用AndX链(当前使用)
SMB_COM_WRITE_RAW: 0x1d 写一个块以raw模式(不推荐)
SMB_COM_WRITE_COMPLETE: 0x20 写raw块,最后响应(不推荐)
SMB_COM_WRITE_MPX: 0x1e 多点(multiplexed)写块(已废除)
Query directory information:查询目录信息
SMB_COM_CHECK_DIRECTORY: 0x10 验证路径名解析到目录(当前使用)
SMB_COM_SEARCH: 0x81 目录通配符搜索(不推荐)
SMB_COM_FIND: 0x82 开始或继续一个扩展的通配符搜索(不推荐)
SMB_COM_FIND_UNIQUE: 0x83 执行一次性通配符搜索(不推荐)
SMB_COM_FIND_CLOSE: 0x84 结束一个扩展的通配符搜索(不推荐)[0x85-0x9f unused]
SMB_COM_FIND_CLOSE2: 0x34 关闭一个激活的搜索(当前使用) [0x36-0x5f Unused][0x60-0x6f Reserved]
Query/set attributes methods:查询或设置属性类
SMB_COM_RENAME: 0x07 重命名一个文件(当前使用)
SMB_COM_NT_RENAME: 0xa5 用扩展语义重命名文件(已废除)[0xa6-0xbf unused]
SMB_COM_QUERY_INFORMATION: 0x8 获取文件属性(不推荐)
SMB_COM_SET_INFORMATION: 0x09 设置文件属性(不推荐)
SMB_COM_QUERY_INFORMATION_DISK:0x80 获取文件系统信息(不推荐)
SMB_COM_QUERY_INFORMATION2: 0x23 获取文件扩展属性(不推荐)
SMB_COM_SET_INFORMATION2: 0x22 设置文件的扩展属性(不推荐)
Printing methods:打印类
SMB_COM_OPEN_PRINT_FILE: 0xc0 创建一个打印队列文件(当前使用)
SMB_COM_WRITE_PRINT_FILE: 0xc1 写打印队列文件(不推荐)
SMB_COM_CLOSE_PRINT_FILE: 0xc2 关闭打印队列文件(不推荐) [0xc4-0xcf unused 0xd0-0xd7 reserved]
Other:其它
SMB_COM_ECHO: 0x2b 回显一个请求ping(当前使用)
SMB_COM_PROCESS_EXIT: 0x11 表明进程退出(已废除)
SMB_COM_NT_CANCEL: 0xa4 取消一个正在阻塞的请求(当前使用)
SMB_COM_INVALID: 0xfe 不可能命令(当前使用)
SMB_COM_IOCTL: 0x27 IO控制请求(已废除)
SMB_COM_NO_ANDX_COMMAND: 0xff 表示AndX链接尾的空命令(当前使用)
样例:(只能打印第一个包信息)
#include <stdio.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> typedef unsigned short uint16; int NeedSwap=0; typedef unsigned char BOOL; #define PVAL(buf,pos,type) (*((type*)(buf+pos))) #define CVAL(buf,pos) PVAL(buf,pos,unsigned char) #define SVAL(buf,pos) sval((char *)buf,pos) #define SSWP(x) (NeedSwap? uint16_byte_swap((uint16)x):(x)) void object_byte_swap(void *obj,int size) { int i; char c; char *p1 = (char *)obj; char *p2 = p1 + size - 1; size /= 2; for (i=0;i<size;i++){ c = *p1; *p1 = *p2; *p2 = c; p1++; p2--; } } uint16 uint16_byte_swap(uint16 x) { uint16 res; res = x; object_byte_swap(&res,sizeof(res)); return(res); } uint16 sval(char *buf,int pos) { uint16 res; memcpy((char *)&res,buf + pos,sizeof(uint16)); res = SSWP(res); return(res); } #define smb_size 39 //DATA块为空时包的长度 #define smb_com 8 //SMB head 头中:command #define smb_rcls 9 //status1 #define smb_reh 10 //status2 #define smb_err 11 //status3 #define smb_flg 13 //flags1 #define smb_flg2 14 //flags2 #define smb_reb 13 //flags1+2 #define smb_tid 28 //tid域 #define smb_pid 30 //PID域 #define smb_uid 32 //UID域 #define smb_mid 34 //MID域 #define smb_wct 36 //parameter 参数个数 #define smb_vwv 37 //参数域 #define smb_vwv0 37 //第0个参数 #define smb_vwv1 39 //第1个参数 #define smb_vwv2 41 #define smb_vwv3 43 #define smb_vwv4 45 #define smb_vwv5 47 #define smb_vwv6 49 #define smb_vwv7 51 #define smb_vwv8 53 #define smb_vwv9 55 #define smb_vwv10 57 #define smb_vwv11 59 int Client; int smb_len(char *buf) { int msg_flags = CVAL(buf,1); int len = (CVAL(buf,2) << 8) + CVAL(buf,3); if (msg_flags & 1) len += 1<<16; return len; } void show_msg(char *buf) { int i; printf("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\n", \ smb_len(buf), \ (int)CVAL(buf,smb_com), \ (int)CVAL(buf,smb_rcls), \ (int)CVAL(buf,smb_reh), \ (int)SVAL(buf,smb_err)); \ printf("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n", \ (int)SVAL(buf,smb_tid), \ (int)SVAL(buf,smb_pid), \ (int)SVAL(buf,smb_uid), \ (int)SVAL(buf,smb_mid), \ (int)CVAL(buf,smb_wct)); for (i=0;i<(int)CVAL(buf,smb_wct);i++) printf("smb_vwv[%d]=%d (0x%X)\n",i, SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)); printf("smb_bcc=%d\n",(int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)))); //data块 } int read_data(int fd,char*buf,int N){ int nready; int nread=0; while(nread<N){ nready=read(fd,buf+nread,N-nread); if(nready<=0) {printf("read failed !\n");exit(1);} nread+=nready; } return 1; } int receive_smb(char *buffer) { int len, msg_type; int fd = Client; memset(buffer,0,smb_size + 100); again: if (!read_data(fd,buffer,4)) { printf("couldn't read from client\n"); close(Client); exit(1); } len = smb_len(buffer); msg_type = CVAL(buffer,0); if(len == 0 && msg_type == 0x85) { printf("Got keepalive packet\n"); goto again; } if (!read_data(fd,buffer + 4,len)) { printf("couldn't read %d bytes from client. Exiting\n",len); close(Client); exit(1); } //log_in(buffer,len+4); return(len + 4); } void process(int fd){ //接受客户访问 int trans_num=0; //记录传输次数 int nread; char*inbuffer; char*outbuffer; inbuffer=(char*)malloc(0xffff);//64k outbuffer=(char*)malloc(0xffff);//64k //while(1){ int len,msg_type,msg_flags,type; if(!receive_smb(inbuffer)) return ; msg_type=CVAL(inbuffer,0); //netbios head type(代表SMB包类型) msg_flags=CVAL(inbuffer,1); //netbios flag len=smb_len(inbuffer); //lenth SMB包长度 nread=len+4; //SMB长度+4 NETBIOS头长度 type=CVAL(inbuffer,smb_com); //smb command printf("got netbios message[type:0x%x,flag=0x%x,len=%d]\n",msg_type,msg_flags,len); show_msg(inbuffer); //} } BOOL big_endian(void){ int x=2; char*s; s=(char*)&x; return (s[0]==0); } int main(){ int daemon=0; int port=139; NeedSwap=big_endian(); //init_structs(); //lp_load(CONFIG_FILE); struct sockaddr addr; socklen_t addr_len; struct sockaddr_in sock; char host_name[100]; struct hostent *hp; int in_addrlen = sizeof(addr); int s; memset(&sock, 0, sizeof(sock)); sock.sin_port = htons( 139 ); sock.sin_family = AF_INET; sock.sin_addr.s_addr = htonl(INADDR_ANY); s = socket(AF_INET, SOCK_STREAM, 0); /* now we've got a socket - we need to bind it */ bind(s, (struct sockaddr * ) &sock,sizeof(sock)); listen(s, 5); while(Client=accept(s,&addr,&addr_len)){ if(fork()==0){ //int one=1; //signal(SIGPIPE, abort); //setsockopt(Client,SOL_SOCKET,SO_KEEPALIVE,&one,sizeof(one)); process(Client); exit(0); } } }