📄 nmblib.c
字号:
RSSVAL(ubuf,offset,nmb->header.name_trn_id); ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3; if (nmb->header.response) ubuf[offset+2] |= (1<<7); if (nmb->header.nm_flags.authoritative && nmb->header.response) ubuf[offset+2] |= 0x4; if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2; if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1; if (nmb->header.nm_flags.recursion_available && nmb->header.response) ubuf[offset+3] |= 0x80; if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10; ubuf[offset+3] |= (nmb->header.rcode & 0xF); RSSVAL(ubuf,offset+4,nmb->header.qdcount); RSSVAL(ubuf,offset+6,nmb->header.ancount); RSSVAL(ubuf,offset+8,nmb->header.nscount); RSSVAL(ubuf,offset+10,nmb->header.arcount); offset += 12; if (nmb->header.qdcount) { /* XXXX this doesn't handle a qdcount of > 1 */ offset += put_nmb_name((char *)ubuf,offset,&nmb->question.question_name); RSSVAL(ubuf,offset,nmb->question.question_type); RSSVAL(ubuf,offset+2,nmb->question.question_class); offset += 4; } if (nmb->header.ancount) offset += put_res_rec((char *)ubuf,offset,nmb->answers, nmb->header.ancount); if (nmb->header.nscount) offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs, nmb->header.nscount); /* * The spec says we must put compressed name pointers * in the following outgoing packets : * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST, * NAME_RELEASE_REQUEST. */ if((nmb->header.response == False) && ((nmb->header.opcode == NMB_NAME_REG_OPCODE) || (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) || (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) || (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) || (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) && (nmb->header.arcount == 1)) { offset += put_compressed_name_ptr(ubuf,offset,nmb->additional,12); } else if (nmb->header.arcount) { offset += put_res_rec((char *)ubuf,offset,nmb->additional, nmb->header.arcount); } return(offset);}/******************************************************************* Linearise a packet.******************************************************************/int build_packet(char *buf, struct packet_struct *p){ int len = 0; switch (p->packet_type) { case NMB_PACKET: len = build_nmb(buf,p); break; case DGRAM_PACKET: len = build_dgram(buf,p); break; } return len;}/******************************************************************* Send a packet_struct.******************************************************************/BOOL send_packet(struct packet_struct *p){ char buf[1024]; int len=0; memset(buf,'\0',sizeof(buf)); len = build_packet(buf, p); if (!len) return(False); return(send_udp(p->fd,buf,len,p->ip,p->port));}/**************************************************************************** Receive a packet with timeout on a open UDP filedescriptor. The timeout is in milliseconds***************************************************************************/struct packet_struct *receive_packet(int fd,enum packet_type type,int t){ fd_set fds; struct timeval timeout; int ret; FD_ZERO(&fds); FD_SET(fd,&fds); timeout.tv_sec = t/1000; timeout.tv_usec = 1000*(t%1000); if ((ret = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout)) == -1) { /* errno should be EBADF or EINVAL. */ DEBUG(0,("select returned -1, errno = %s (%d)\n", strerror(errno), errno)); return NULL; } if (ret == 0) /* timeout */ return NULL; if (FD_ISSET(fd,&fds)) return(read_packet(fd,type)); return(NULL);}/**************************************************************************** Receive a UDP/137 packet either via UDP or from the unexpected packet queue. The packet must be a reply packet and have the specified trn_id. The timeout is in milliseconds.***************************************************************************/struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id){ struct packet_struct *p; p = receive_packet(fd, NMB_PACKET, t); if (p && p->packet.nmb.header.response && p->packet.nmb.header.name_trn_id == trn_id) { return p; } if (p) free_packet(p); /* try the unexpected packet queue */ return receive_unexpected(NMB_PACKET, trn_id, NULL);}/**************************************************************************** Receive a UDP/138 packet either via UDP or from the unexpected packet queue. The packet must be a reply packet and have the specified mailslot name The timeout is in milliseconds.***************************************************************************/struct packet_struct *receive_dgram_packet(int fd, int t, const char *mailslot_name){ struct packet_struct *p; p = receive_packet(fd, DGRAM_PACKET, t); if (p && match_mailslot_name(p, mailslot_name)) { return p; } if (p) free_packet(p); /* try the unexpected packet queue */ return receive_unexpected(DGRAM_PACKET, 0, mailslot_name);}/**************************************************************************** See if a datagram has the right mailslot name.***************************************************************************/BOOL match_mailslot_name(struct packet_struct *p, const char *mailslot_name){ struct dgram_packet *dgram = &p->packet.dgram; char *buf; buf = &dgram->data[0]; buf -= 4; buf = smb_buf(buf); if (memcmp(buf, mailslot_name, strlen(mailslot_name)+1) == 0) { return True; } return False;}/**************************************************************************** Return the number of bits that match between two 4 character buffers***************************************************************************/int matching_quad_bits(unsigned char *p1, unsigned char *p2){ int i, j, ret = 0; for (i=0; i<4; i++) { if (p1[i] != p2[i]) break; ret += 8; } if (i==4) return ret; for (j=0; j<8; j++) { if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j)))) break; ret++; } return ret;}static unsigned char sort_ip[4];/**************************************************************************** Compare two query reply records.***************************************************************************/static int name_query_comp(unsigned char *p1, unsigned char *p2){ return matching_quad_bits(p2+2, sort_ip) - matching_quad_bits(p1+2, sort_ip);}/**************************************************************************** Sort a set of 6 byte name query response records so that the IPs that have the most leading bits in common with the specified address come first.***************************************************************************/void sort_query_replies(char *data, int n, struct in_addr ip){ if (n <= 1) return; putip(sort_ip, (char *)&ip); qsort(data, n, 6, QSORT_CAST name_query_comp);}/******************************************************************* Convert, possibly using a stupid microsoft-ism which has destroyed the transport independence of netbios (for CIFS vendors that usually use the Win95-type methods, not for NT to NT communication, which uses DCE/RPC and therefore full-length unicode strings...) a dns name into a netbios name. The netbios name (NOT necessarily null-terminated) is truncated to 15 characters. ******************************************************************/char *dns_to_netbios_name(const char *dns_name){ static nstring netbios_name; int i; StrnCpy(netbios_name, dns_name, MAX_NETBIOSNAME_LEN-1); netbios_name[15] = 0; /* ok. this is because of a stupid microsoft-ism. if the called host name contains a '.', microsoft clients expect you to truncate the netbios name up to and including the '.' this even applies, by mistake, to workgroup (domain) names, which is _really_ daft. */ for (i = 0; i < 15; i++) { if (netbios_name[i] == '.') { netbios_name[i] = 0; break; } } return netbios_name;}/**************************************************************************** Interpret the weird netbios "name" into a unix fstring. Return the name type.****************************************************************************/static int name_interpret(char *in, fstring name){ int ret; int len = (*in++) / 2; fstring out_string; char *out = out_string; *out=0; if (len > 30 || len<1) return(0); while (len--) { if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') { *out = 0; return(0); } *out = ((in[0]-'A')<<4) + (in[1]-'A'); in += 2; out++; } ret = out[-1]; out[-1] = 0;#ifdef NETBIOS_SCOPE /* Handle any scope names */ while(*in) { *out++ = '.'; /* Scope names are separated by periods */ len = *(unsigned char *)in++; StrnCpy(out, in, len); out += len; *out=0; in += len; }#endif pull_ascii_fstring(name, out_string); return(ret);}/**************************************************************************** Mangle a name into netbios format. Note: <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.****************************************************************************/int name_mangle( char *In, char *Out, char name_type ){ int i; int len; nstring buf; char *p = Out; /* Safely copy the input string, In, into buf[]. */ if (strcmp(In,"*") == 0) put_name(buf, "*", '\0', 0x00); else { /* We use an fstring here as mb dos names can expend x3 when going to utf8. */ fstring buf_unix; nstring buf_dos; pull_ascii_fstring(buf_unix, In); strupper_m(buf_unix); push_ascii_nstring(buf_dos, buf_unix); put_name(buf, buf_dos, ' ', name_type); } /* Place the length of the first field into the output buffer. */ p[0] = 32; p++; /* Now convert the name to the rfc1001/1002 format. */ for( i = 0; i < MAX_NETBIOSNAME_LEN; i++ ) { p[i*2] = ( (buf[i] >> 4) & 0x000F ) + 'A'; p[(i*2)+1] = (buf[i] & 0x000F) + 'A'; } p += 32; p[0] = '\0'; /* Add the scope string. */ for( i = 0, len = 0; *(global_scope()) != '\0'; i++, len++ ) { switch( (global_scope())[i] ) { case '\0': p[0] = len; if( len > 0 ) p[len+1] = 0; return( name_len(Out) ); case '.': p[0] = len; p += (len + 1); len = -1; break; default: p[len+1] = (global_scope())[i]; break; } } return( name_len(Out) );}/**************************************************************************** Find a pointer to a netbios name.****************************************************************************/static char *name_ptr(char *buf,int ofs){ unsigned char c = *(unsigned char *)(buf+ofs); if ((c & 0xC0) == 0xC0) { uint16 l = RSVAL(buf, ofs) & 0x3FFF; DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l)); return(buf + l); } else { return(buf+ofs); }} /**************************************************************************** Extract a netbios name from a buf (into a unix string) return name type.****************************************************************************/int name_extract(char *buf,int ofs, fstring name){ char *p = name_ptr(buf,ofs); int d = PTR_DIFF(p,buf+ofs); name[0] = '\0'; if (d < -50 || d > 50) return(0); return(name_interpret(p,name));} /**************************************************************************** Return the total storage length of a mangled name.****************************************************************************/int name_len(char *s1){ /* NOTE: this argument _must_ be unsigned */ unsigned char *s = (unsigned char *)s1; int len; /* If the two high bits of the byte are set, return 2. */ if (0xC0 == (*s & 0xC0)) return(2); /* Add up the length bytes. */ for (len = 1; (*s); s += (*s) + 1) { len += *s + 1; SMB_ASSERT(len < 80); } return(len);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -