libsmb/nmblib.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    NBT netbios library routines
00004    Copyright (C) Andrew Tridgell 1994-1998
00005    
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015    
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019    
00020 */
00021 
00022 #include "includes.h"
00023 
00024 extern struct in_addr lastip;
00025 extern int lastport;
00026 
00027 int num_good_sends = 0;
00028 int num_good_receives = 0;
00029 
00030 static const struct opcode_names {
00031         const char *nmb_opcode_name;
00032         int opcode;
00033 } nmb_header_opcode_names[] = {
00034         {"Query",           0 },
00035         {"Registration",      5 },
00036         {"Release",           6 },
00037         {"WACK",              7 },
00038         {"Refresh",           8 },
00039         {"Refresh(altcode)",  9 },
00040         {"Multi-homed Registration", 15 },
00041         {0, -1 }
00042 };
00043 
00044 /****************************************************************************
00045  Lookup a nmb opcode name.
00046 ****************************************************************************/
00047 
00048 static const char *lookup_opcode_name( int opcode )
00049 {
00050         const struct opcode_names *op_namep;
00051         int i;
00052 
00053         for(i = 0; nmb_header_opcode_names[i].nmb_opcode_name != 0; i++) {
00054                 op_namep = &nmb_header_opcode_names[i];
00055                 if(opcode == op_namep->opcode)
00056                         return op_namep->nmb_opcode_name;
00057         }
00058         return "<unknown opcode>";
00059 }
00060 
00061 /****************************************************************************
00062  Print out a res_rec structure.
00063 ****************************************************************************/
00064 
00065 static void debug_nmb_res_rec(struct res_rec *res, const char *hdr)
00066 {
00067         int i, j;
00068 
00069         DEBUGADD( 4, ( "    %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n",
00070                 hdr,
00071                 nmb_namestr(&res->rr_name),
00072                 res->rr_type,
00073                 res->rr_class,
00074                 res->ttl ) );
00075 
00076         if( res->rdlength == 0 || res->rdata == NULL )
00077                 return;
00078 
00079         for (i = 0; i < res->rdlength; i+= MAX_NETBIOSNAME_LEN) {
00080                 DEBUGADD(4, ("    %s %3x char ", hdr, i));
00081 
00082                 for (j = 0; j < MAX_NETBIOSNAME_LEN; j++) {
00083                         unsigned char x = res->rdata[i+j];
00084                         if (x < 32 || x > 127)
00085                                 x = '.';
00086           
00087                         if (i+j >= res->rdlength)
00088                                 break;
00089                         DEBUGADD(4, ("%c", x));
00090                 }
00091       
00092                 DEBUGADD(4, ("   hex "));
00093 
00094                 for (j = 0; j < MAX_NETBIOSNAME_LEN; j++) {
00095                         if (i+j >= res->rdlength)
00096                                 break;
00097                         DEBUGADD(4, ("%02X", (unsigned char)res->rdata[i+j]));
00098                 }
00099       
00100                 DEBUGADD(4, ("\n"));
00101         }
00102 }
00103 
00104 /****************************************************************************
00105  Process a nmb packet.
00106 ****************************************************************************/
00107 
00108 void debug_nmb_packet(struct packet_struct *p)
00109 {
00110         struct nmb_packet *nmb = &p->packet.nmb;
00111 
00112         if( DEBUGLVL( 4 ) ) {
00113                 dbgtext( "nmb packet from %s(%d) header: id=%d opcode=%s(%d) response=%s\n",
00114                         inet_ntoa(p->ip), p->port,
00115                         nmb->header.name_trn_id,
00116                         lookup_opcode_name(nmb->header.opcode),
00117                         nmb->header.opcode,
00118                         BOOLSTR(nmb->header.response) );
00119                 dbgtext( "    header: flags: bcast=%s rec_avail=%s rec_des=%s trunc=%s auth=%s\n",
00120                         BOOLSTR(nmb->header.nm_flags.bcast),
00121                         BOOLSTR(nmb->header.nm_flags.recursion_available),
00122                         BOOLSTR(nmb->header.nm_flags.recursion_desired),
00123                         BOOLSTR(nmb->header.nm_flags.trunc),
00124                         BOOLSTR(nmb->header.nm_flags.authoritative) );
00125                 dbgtext( "    header: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d\n",
00126                         nmb->header.rcode,
00127                         nmb->header.qdcount,
00128                         nmb->header.ancount,
00129                         nmb->header.nscount,
00130                         nmb->header.arcount );
00131         }
00132 
00133         if (nmb->header.qdcount) {
00134                 DEBUGADD( 4, ( "    question: q_name=%s q_type=%d q_class=%d\n",
00135                         nmb_namestr(&nmb->question.question_name),
00136                         nmb->question.question_type,
00137                         nmb->question.question_class) );
00138         }
00139 
00140         if (nmb->answers && nmb->header.ancount) {
00141                 debug_nmb_res_rec(nmb->answers,"answers");
00142         }
00143         if (nmb->nsrecs && nmb->header.nscount) {
00144                 debug_nmb_res_rec(nmb->nsrecs,"nsrecs");
00145         }
00146         if (nmb->additional && nmb->header.arcount) {
00147                 debug_nmb_res_rec(nmb->additional,"additional");
00148         }
00149 }
00150 
00151 /*******************************************************************
00152  Handle "compressed" name pointers.
00153 ******************************************************************/
00154 
00155 static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
00156                              BOOL *got_pointer,int *ret)
00157 {
00158         int loop_count=0;
00159   
00160         while ((ubuf[*offset] & 0xC0) == 0xC0) {
00161                 if (!*got_pointer)
00162                         (*ret) += 2;
00163                 (*got_pointer)=True;
00164                 (*offset) = ((ubuf[*offset] & ~0xC0)<<8) | ubuf[(*offset)+1];
00165                 if (loop_count++ == 10 || (*offset) < 0 || (*offset)>(length-2)) {
00166                         return(False);
00167                 }
00168         }
00169         return(True);
00170 }
00171 
00172 /*******************************************************************
00173  Parse a nmb name from "compressed" format to something readable
00174  return the space taken by the name, or 0 if the name is invalid
00175 ******************************************************************/
00176 
00177 static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name)
00178 {
00179         int m,n=0;
00180         unsigned char *ubuf = (unsigned char *)inbuf;
00181         int ret = 0;
00182         BOOL got_pointer=False;
00183         int loop_count=0;
00184         int offset = ofs;
00185 
00186         if (length - offset < 2)
00187                 return(0);  
00188 
00189         /* handle initial name pointers */
00190         if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
00191                 return(0);
00192   
00193         m = ubuf[offset];
00194 
00195         if (!m)
00196                 return(0);
00197         if ((m & 0xC0) || offset+m+2 > length)
00198                 return(0);
00199 
00200         memset((char *)name,'\0',sizeof(*name));
00201 
00202         /* the "compressed" part */
00203         if (!got_pointer)
00204                 ret += m + 2;
00205         offset++;
00206         while (m > 0) {
00207                 unsigned char c1,c2;
00208                 c1 = ubuf[offset++]-'A';
00209                 c2 = ubuf[offset++]-'A';
00210                 if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1))
00211                         return(0);
00212                 name->name[n++] = (c1<<4) | c2;
00213                 m -= 2;
00214         }
00215         name->name[n] = 0;
00216 
00217         if (n==MAX_NETBIOSNAME_LEN) {
00218                 /* parse out the name type, its always in the 16th byte of the name */
00219                 name->name_type = ((unsigned char)name->name[15]) & 0xff;
00220   
00221                 /* remove trailing spaces */
00222                 name->name[15] = 0;
00223                 n = 14;
00224                 while (n && name->name[n]==' ')
00225                         name->name[n--] = 0;  
00226         }
00227 
00228         /* now the domain parts (if any) */
00229         n = 0;
00230         while (ubuf[offset]) {
00231                 /* we can have pointers within the domain part as well */
00232                 if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
00233                         return(0);
00234 
00235                 m = ubuf[offset];
00236                 /*
00237                  * Don't allow null domain parts.
00238                  */
00239                 if (!m)
00240                         return(0);
00241                 if (!got_pointer)
00242                         ret += m+1;
00243                 if (n)
00244                         name->scope[n++] = '.';
00245                 if (m+2+offset>length || n+m+1>sizeof(name->scope))
00246                         return(0);
00247                 offset++;
00248                 while (m--)
00249                         name->scope[n++] = (char)ubuf[offset++];
00250 
00251                 /*
00252                  * Watch for malicious loops.
00253                  */
00254                 if (loop_count++ == 10)
00255                         return 0;
00256         }
00257         name->scope[n++] = 0;  
00258 
00259         return(ret);
00260 }
00261 
00262 /****************************************************************************
00263  Put a netbios name, padding(s) and a name type into a 16 character buffer.
00264  name is already in DOS charset.
00265  [15 bytes name + padding][1 byte name type].
00266 ****************************************************************************/
00267 
00268 void put_name(char *dest, const char *name, int pad, unsigned int name_type)
00269 {
00270         size_t len = strlen(name);
00271 
00272         memcpy(dest, name, (len < MAX_NETBIOSNAME_LEN) ? len : MAX_NETBIOSNAME_LEN - 1);
00273         if (len < MAX_NETBIOSNAME_LEN - 1) {
00274                 memset(dest + len, pad, MAX_NETBIOSNAME_LEN - 1 - len);
00275         }
00276         dest[MAX_NETBIOSNAME_LEN - 1] = name_type;
00277 }
00278 
00279 /*******************************************************************
00280  Put a compressed nmb name into a buffer. Return the length of the
00281  compressed name.
00282 
00283  Compressed names are really weird. The "compression" doubles the
00284  size. The idea is that it also means that compressed names conform
00285  to the doman name system. See RFC1002.
00286 ******************************************************************/
00287 
00288 static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
00289 {
00290         int ret,m;
00291         nstring buf1;
00292         char *p;
00293 
00294         if (strcmp(name->name,"*") == 0) {
00295                 /* special case for wildcard name */
00296                 put_name(buf1, "*", '\0', name->name_type);
00297         } else {
00298                 put_name(buf1, name->name, ' ', name->name_type);
00299         }
00300 
00301         buf[offset] = 0x20;
00302 
00303         ret = 34;
00304 
00305         for (m=0;m<MAX_NETBIOSNAME_LEN;m++) {
00306                 buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF);
00307                 buf[offset+2+2*m] = 'A' + (buf1[m]&0xF);
00308         }
00309         offset += 33;
00310 
00311         buf[offset] = 0;
00312 
00313         if (name->scope[0]) {
00314                 /* XXXX this scope handling needs testing */
00315                 ret += strlen(name->scope) + 1;
00316                 safe_strcpy(&buf[offset+1],name->scope,sizeof(name->scope));  
00317   
00318                 p = &buf[offset+1];
00319                 while ((p = strchr_m(p,'.'))) {
00320                         buf[offset] = PTR_DIFF(p,&buf[offset+1]);
00321                         offset += (buf[offset] + 1);
00322                         p = &buf[offset+1];
00323                 }
00324                 buf[offset] = strlen(&buf[offset+1]);
00325         }
00326 
00327         return(ret);
00328 }
00329 
00330 /*******************************************************************
00331  Useful for debugging messages.
00332 ******************************************************************/
00333 
00334 char *nmb_namestr(const struct nmb_name *n)
00335 {
00336         static int i=0;
00337         static fstring ret[4];
00338         fstring name;
00339         char *p = ret[i];
00340 
00341         pull_ascii_fstring(name, n->name);
00342         if (!n->scope[0])
00343                 slprintf(p,sizeof(fstring)-1, "%s<%02x>",name,n->name_type);
00344         else
00345                 slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",name,n->name_type,n->scope);
00346 
00347         i = (i+1)%4;
00348         return(p);
00349 }
00350 
00351 /*******************************************************************
00352  Allocate and parse some resource records.
00353 ******************************************************************/
00354 
00355 static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
00356                                 struct res_rec **recs, int count)
00357 {
00358         int i;
00359 
00360         *recs = SMB_MALLOC_ARRAY(struct res_rec, count);
00361         if (!*recs)
00362                 return(False);
00363 
00364         memset((char *)*recs,'\0',sizeof(**recs)*count);
00365 
00366         for (i=0;i<count;i++) {
00367                 int l = parse_nmb_name(inbuf,*offset,length,&(*recs)[i].rr_name);
00368                 (*offset) += l;
00369                 if (!l || (*offset)+10 > length) {
00370                         SAFE_FREE(*recs);
00371                         return(False);
00372                 }
00373                 (*recs)[i].rr_type = RSVAL(inbuf,(*offset));
00374                 (*recs)[i].rr_class = RSVAL(inbuf,(*offset)+2);
00375                 (*recs)[i].ttl = RIVAL(inbuf,(*offset)+4);
00376                 (*recs)[i].rdlength = RSVAL(inbuf,(*offset)+8);
00377                 (*offset) += 10;
00378                 if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) || 
00379                                 (*offset)+(*recs)[i].rdlength > length) {
00380                         SAFE_FREE(*recs);
00381                         return(False);
00382                 }
00383                 memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength);
00384                 (*offset) += (*recs)[i].rdlength;    
00385         }
00386         return(True);
00387 }
00388 
00389 /*******************************************************************
00390  Put a resource record into a packet.
00391 ******************************************************************/
00392 
00393 static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
00394 {
00395         int ret=0;
00396         int i;
00397 
00398         for (i=0;i<count;i++) {
00399                 int l = put_nmb_name(buf,offset,&recs[i].rr_name);
00400                 offset += l;
00401                 ret += l;
00402                 RSSVAL(buf,offset,recs[i].rr_type);
00403                 RSSVAL(buf,offset+2,recs[i].rr_class);
00404                 RSIVAL(buf,offset+4,recs[i].ttl);
00405                 RSSVAL(buf,offset+8,recs[i].rdlength);
00406                 memcpy(buf+offset+10,recs[i].rdata,recs[i].rdlength);
00407                 offset += 10+recs[i].rdlength;
00408                 ret += 10+recs[i].rdlength;
00409         }
00410 
00411         return(ret);
00412 }
00413 
00414 /*******************************************************************
00415  Put a compressed name pointer record into a packet.
00416 ******************************************************************/
00417 
00418 static int put_compressed_name_ptr(unsigned char *buf,int offset,struct res_rec *rec,int ptr_offset)
00419 {  
00420         int ret=0;
00421         buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF));
00422         buf[offset+1] = (ptr_offset & 0xFF);
00423         offset += 2;
00424         ret += 2;
00425         RSSVAL(buf,offset,rec->rr_type);
00426         RSSVAL(buf,offset+2,rec->rr_class);
00427         RSIVAL(buf,offset+4,rec->ttl);
00428         RSSVAL(buf,offset+8,rec->rdlength);
00429         memcpy(buf+offset+10,rec->rdata,rec->rdlength);
00430         offset += 10+rec->rdlength;
00431         ret += 10+rec->rdlength;
00432     
00433         return(ret);
00434 }
00435 
00436 /*******************************************************************
00437  Parse a dgram packet. Return False if the packet can't be parsed 
00438  or is invalid for some reason, True otherwise.
00439 
00440  This is documented in section 4.4.1 of RFC1002.
00441 ******************************************************************/
00442 
00443 static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
00444 {
00445         int offset;
00446         int flags;
00447 
00448         memset((char *)dgram,'\0',sizeof(*dgram));
00449 
00450         if (length < 14)
00451                 return(False);
00452 
00453         dgram->header.msg_type = CVAL(inbuf,0);
00454         flags = CVAL(inbuf,1);
00455         dgram->header.flags.node_type = (enum node_type)((flags>>2)&3);
00456         if (flags & 1)
00457                 dgram->header.flags.more = True;
00458         if (flags & 2)
00459                 dgram->header.flags.first = True;
00460         dgram->header.dgm_id = RSVAL(inbuf,2);
00461         putip((char *)&dgram->header.source_ip,inbuf+4);
00462         dgram->header.source_port = RSVAL(inbuf,8);
00463         dgram->header.dgm_length = RSVAL(inbuf,10);
00464         dgram->header.packet_offset = RSVAL(inbuf,12);
00465 
00466         offset = 14;
00467 
00468         if (dgram->header.msg_type == 0x10 ||
00469                         dgram->header.msg_type == 0x11 ||
00470                         dgram->header.msg_type == 0x12) {      
00471                 offset += parse_nmb_name(inbuf,offset,length,&dgram->source_name);
00472                 offset += parse_nmb_name(inbuf,offset,length,&dgram->dest_name);
00473         }
00474 
00475         if (offset >= length || (length-offset > sizeof(dgram->data))) 
00476                 return(False);
00477 
00478         dgram->datasize = length-offset;
00479         memcpy(dgram->data,inbuf+offset,dgram->datasize);
00480 
00481         /* Paranioa. Ensure the last 2 bytes in the dgram buffer are
00482            zero. This should be true anyway, just enforce it for paranioa sake. JRA. */
00483         SMB_ASSERT(dgram->datasize <= (sizeof(dgram->data)-2));
00484         memset(&dgram->data[sizeof(dgram->data)-2], '\0', 2);
00485 
00486         return(True);
00487 }
00488 
00489 /*******************************************************************
00490  Parse a nmb packet. Return False if the packet can't be parsed 
00491  or is invalid for some reason, True otherwise.
00492 ******************************************************************/
00493 
00494 static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
00495 {
00496         int nm_flags,offset;
00497 
00498         memset((char *)nmb,'\0',sizeof(*nmb));
00499 
00500         if (length < 12)
00501                 return(False);
00502 
00503         /* parse the header */
00504         nmb->header.name_trn_id = RSVAL(inbuf,0);
00505 
00506         DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id));
00507 
00508         nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF;
00509         nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False;
00510         nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4);
00511         nmb->header.nm_flags.bcast = (nm_flags&1)?True:False;
00512         nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False;
00513         nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False;
00514         nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False;
00515         nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False;  
00516         nmb->header.rcode = CVAL(inbuf,3) & 0xF;
00517         nmb->header.qdcount = RSVAL(inbuf,4);
00518         nmb->header.ancount = RSVAL(inbuf,6);
00519         nmb->header.nscount = RSVAL(inbuf,8);
00520         nmb->header.arcount = RSVAL(inbuf,10);
00521   
00522         if (nmb->header.qdcount) {
00523                 offset = parse_nmb_name(inbuf,12,length,&nmb->question.question_name);
00524                 if (!offset)
00525                         return(False);
00526 
00527                 if (length - (12+offset) < 4)
00528                         return(False);
00529                 nmb->question.question_type = RSVAL(inbuf,12+offset);
00530                 nmb->question.question_class = RSVAL(inbuf,12+offset+2);
00531 
00532                 offset += 12+4;
00533         } else {
00534                 offset = 12;
00535         }
00536 
00537         /* and any resource records */
00538         if (nmb->header.ancount && !parse_alloc_res_rec(inbuf,&offset,length,&nmb->answers,
00539                                         nmb->header.ancount))
00540                 return(False);
00541 
00542         if (nmb->header.nscount && !parse_alloc_res_rec(inbuf,&offset,length,&nmb->nsrecs,
00543                                         nmb->header.nscount))
00544                 return(False);
00545   
00546         if (nmb->header.arcount && !parse_alloc_res_rec(inbuf,&offset,length,&nmb->additional,
00547                                         nmb->header.arcount))
00548                 return(False);
00549 
00550         return(True);
00551 }
00552 
00553 /*******************************************************************
00554  'Copy constructor' for an nmb packet.
00555 ******************************************************************/
00556 
00557 static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
00558 {  
00559         struct nmb_packet *nmb;
00560         struct nmb_packet *copy_nmb;
00561         struct packet_struct *pkt_copy;
00562 
00563         if(( pkt_copy = SMB_MALLOC_P(struct packet_struct)) == NULL) {
00564                 DEBUG(0,("copy_nmb_packet: malloc fail.\n"));
00565                 return NULL;
00566         }
00567 
00568         /* Structure copy of entire thing. */
00569 
00570         *pkt_copy = *packet;
00571 
00572         /* Ensure this copy is not locked. */
00573         pkt_copy->locked = False;
00574 
00575         /* Ensure this copy has no resource records. */
00576         nmb = &packet->packet.nmb;
00577         copy_nmb = &pkt_copy->packet.nmb;
00578 
00579         copy_nmb->answers = NULL;
00580         copy_nmb->nsrecs = NULL;
00581         copy_nmb->additional = NULL;
00582 
00583         /* Now copy any resource records. */
00584 
00585         if (nmb->answers) {
00586                 if((copy_nmb->answers = SMB_MALLOC_ARRAY(struct res_rec,nmb->header.ancount)) == NULL)
00587                         goto free_and_exit;
00588                 memcpy((char *)copy_nmb->answers, (char *)nmb->answers, 
00589                                 nmb->header.ancount * sizeof(struct res_rec));
00590         }
00591         if (nmb->nsrecs) {
00592                 if((copy_nmb->nsrecs = SMB_MALLOC_ARRAY(struct res_rec, nmb->header.nscount)) == NULL)
00593                         goto free_and_exit;
00594                 memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs, 
00595                                 nmb->header.nscount * sizeof(struct res_rec));
00596         }
00597         if (nmb->additional) {
00598                 if((copy_nmb->additional = SMB_MALLOC_ARRAY(struct res_rec, nmb->header.arcount)) == NULL)
00599                         goto free_and_exit;
00600                 memcpy((char *)copy_nmb->additional, (char *)nmb->additional, 
00601                                 nmb->header.arcount * sizeof(struct res_rec));
00602         }
00603 
00604         return pkt_copy;
00605 
00606  free_and_exit:
00607 
00608         SAFE_FREE(copy_nmb->answers);
00609         SAFE_FREE(copy_nmb->nsrecs);
00610         SAFE_FREE(copy_nmb->additional);
00611         SAFE_FREE(pkt_copy);
00612 
00613         DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n"));
00614         return NULL;
00615 }
00616 
00617 /*******************************************************************
00618   'Copy constructor' for a dgram packet.
00619 ******************************************************************/
00620 
00621 static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
00622 { 
00623         struct packet_struct *pkt_copy;
00624 
00625         if(( pkt_copy = SMB_MALLOC_P(struct packet_struct)) == NULL) {
00626                 DEBUG(0,("copy_dgram_packet: malloc fail.\n"));
00627                 return NULL;
00628         }
00629 
00630         /* Structure copy of entire thing. */
00631 
00632         *pkt_copy = *packet;
00633 
00634         /* Ensure this copy is not locked. */
00635         pkt_copy->locked = False;
00636 
00637         /* There are no additional pointers in a dgram packet,
00638                 we are finished. */
00639         return pkt_copy;
00640 }
00641 
00642 /*******************************************************************
00643  'Copy constructor' for a generic packet.
00644 ******************************************************************/
00645 
00646 struct packet_struct *copy_packet(struct packet_struct *packet)
00647 {  
00648         if(packet->packet_type == NMB_PACKET)
00649                 return copy_nmb_packet(packet);
00650         else if (packet->packet_type == DGRAM_PACKET)
00651                 return copy_dgram_packet(packet);
00652         return NULL;
00653 }
00654  
00655 /*******************************************************************
00656  Free up any resources associated with an nmb packet.
00657 ******************************************************************/
00658 
00659 static void free_nmb_packet(struct nmb_packet *nmb)
00660 {  
00661         SAFE_FREE(nmb->answers);
00662         SAFE_FREE(nmb->nsrecs);
00663         SAFE_FREE(nmb->additional);
00664 }
00665 
00666 /*******************************************************************
00667  Free up any resources associated with a dgram packet.
00668 ******************************************************************/
00669 
00670 static void free_dgram_packet(struct dgram_packet *nmb)
00671 {  
00672         /* We have nothing to do for a dgram packet. */
00673 }
00674 
00675 /*******************************************************************
00676  Free up any resources associated with a packet.
00677 ******************************************************************/
00678 
00679 void free_packet(struct packet_struct *packet)
00680 {  
00681         if (packet->locked) 
00682                 return;
00683         if (packet->packet_type == NMB_PACKET)
00684                 free_nmb_packet(&packet->packet.nmb);
00685         else if (packet->packet_type == DGRAM_PACKET)
00686                 free_dgram_packet(&packet->packet.dgram);
00687         ZERO_STRUCTPN(packet);
00688         SAFE_FREE(packet);
00689 }
00690 
00691 /*******************************************************************
00692  Parse a packet buffer into a packet structure.
00693 ******************************************************************/
00694 
00695 struct packet_struct *parse_packet(char *buf,int length,
00696                                    enum packet_type packet_type)
00697 {
00698         struct packet_struct *p;
00699         BOOL ok=False;
00700 
00701         p = SMB_MALLOC_P(struct packet_struct);
00702         if (!p)
00703                 return(NULL);
00704 
00705         ZERO_STRUCTP(p);        /* initialize for possible padding */
00706 
00707         p->next = NULL;
00708         p->prev = NULL;
00709         p->ip = lastip;
00710         p->port = lastport;
00711         p->locked = False;
00712         p->timestamp = time(NULL);
00713         p->packet_type = packet_type;
00714 
00715         switch (packet_type) {
00716         case NMB_PACKET:
00717                 ok = parse_nmb(buf,length,&p->packet.nmb);
00718                 break;
00719                 
00720         case DGRAM_PACKET:
00721                 ok = parse_dgram(buf,length,&p->packet.dgram);
00722                 break;
00723         }
00724 
00725         if (!ok) {
00726                 free_packet(p);
00727                 return NULL;
00728         }
00729 
00730         return p;
00731 }
00732 
00733 /*******************************************************************
00734  Read a packet from a socket and parse it, returning a packet ready
00735  to be used or put on the queue. This assumes a UDP socket.
00736 ******************************************************************/
00737 
00738 struct packet_struct *read_packet(int fd,enum packet_type packet_type)
00739 {
00740         struct packet_struct *packet;
00741         char buf[MAX_DGRAM_SIZE];
00742         int length;
00743         
00744         length = read_udp_socket(fd,buf,sizeof(buf));
00745         if (length < MIN_DGRAM_SIZE)
00746                 return(NULL);
00747         
00748         packet = parse_packet(buf, length, packet_type);
00749         if (!packet)
00750                 return NULL;
00751 
00752         packet->fd = fd;
00753         
00754         num_good_receives++;
00755         
00756         DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
00757                  length, inet_ntoa(packet->ip), packet->port ) );
00758         
00759         return(packet);
00760 }
00761                                          
00762 /*******************************************************************
00763  Send a udp packet on a already open socket.
00764 ******************************************************************/
00765 
00766 static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
00767 {
00768         BOOL ret = False;
00769         int i;
00770         struct sockaddr_in sock_out;
00771 
00772         /* set the address and port */
00773         memset((char *)&sock_out,'\0',sizeof(sock_out));
00774         putip((char *)&sock_out.sin_addr,(char *)&ip);
00775         sock_out.sin_port = htons( port );
00776         sock_out.sin_family = AF_INET;
00777   
00778         DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n",
00779                         len, inet_ntoa(ip), port ) );
00780 
00781         /*
00782          * Patch to fix asynch error notifications from Linux kernel.
00783          */
00784         
00785         for (i = 0; i < 5; i++) {
00786                 ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, sizeof(sock_out)) >= 0);
00787                 if (ret || errno != ECONNREFUSED)
00788                         break;
00789         }
00790 
00791         if (!ret)
00792                 DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n",
00793                         inet_ntoa(ip),port,strerror(errno)));
00794 
00795         if (ret)
00796                 num_good_sends++;
00797 
00798         return(ret);
00799 }
00800 
00801 /*******************************************************************
00802  Build a dgram packet ready for sending.
00803 
00804  XXXX This currently doesn't handle packets too big for one
00805  datagram. It should split them and use the packet_offset, more and
00806  first flags to handle the fragmentation. Yuck.
00807 
00808    [...but it isn't clear that we would ever need to send a
00809    a fragmented NBT Datagram.  The IP layer does its own
00810    fragmentation to ensure that messages can fit into the path
00811    MTU.  It *is* important to be able to receive and rebuild
00812    fragmented NBT datagrams, just in case someone out there
00813    really has implemented this 'feature'.  crh -)------ ]
00814 
00815 ******************************************************************/
00816 
00817 static int build_dgram(char *buf,struct packet_struct *p)
00818 {
00819         struct dgram_packet *dgram = &p->packet.dgram;
00820         unsigned char *ubuf = (unsigned char *)buf;
00821         int offset=0;
00822 
00823         /* put in the header */
00824         ubuf[0] = dgram->header.msg_type;
00825         ubuf[1] = (((int)dgram->header.flags.node_type)<<2);
00826         if (dgram->header.flags.more)
00827                 ubuf[1] |= 1;
00828         if (dgram->header.flags.first)
00829                 ubuf[1] |= 2;
00830         RSSVAL(ubuf,2,dgram->header.dgm_id);
00831         putip(ubuf+4,(char *)&dgram->header.source_ip);
00832         RSSVAL(ubuf,8,dgram->header.source_port);
00833         RSSVAL(ubuf,12,dgram->header.packet_offset);
00834 
00835         offset = 14;
00836 
00837         if (dgram->header.msg_type == 0x10 ||
00838                         dgram->header.msg_type == 0x11 ||
00839                         dgram->header.msg_type == 0x12) {      
00840                 offset += put_nmb_name((char *)ubuf,offset,&dgram->source_name);
00841                 offset += put_nmb_name((char *)ubuf,offset,&dgram->dest_name);
00842         }
00843 
00844         memcpy(ubuf+offset,dgram->data,dgram->datasize);
00845         offset += dgram->datasize;
00846 
00847         /* automatically set the dgm_length
00848          * NOTE: RFC1002 says the dgm_length does *not*
00849          *       include the fourteen-byte header. crh
00850          */
00851         dgram->header.dgm_length = (offset - 14);
00852         RSSVAL(ubuf,10,dgram->header.dgm_length); 
00853 
00854         return(offset);
00855 }
00856 
00857 /*******************************************************************
00858  Build a nmb name
00859 *******************************************************************/
00860 
00861 void make_nmb_name( struct nmb_name *n, const char *name, int type)
00862 {
00863         fstring unix_name;
00864         memset( (char *)n, '\0', sizeof(struct nmb_name) );
00865         fstrcpy(unix_name, name);
00866         strupper_m(unix_name);
00867         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
00868         n->name_type = (unsigned int)type & 0xFF;
00869         push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
00870 }
00871 
00872 /*******************************************************************
00873   Compare two nmb names
00874 ******************************************************************/
00875 
00876 BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
00877 {
00878         return ((n1->name_type == n2->name_type) &&
00879                 strequal(n1->name ,n2->name ) &&
00880                 strequal(n1->scope,n2->scope));
00881 }
00882 
00883 /*******************************************************************
00884  Build a nmb packet ready for sending.
00885 
00886  XXXX this currently relies on not being passed something that expands
00887  to a packet too big for the buffer. Eventually this should be
00888  changed to set the trunc bit so the receiver can request the rest
00889  via tcp (when that becomes supported)
00890 ******************************************************************/
00891 
00892 static int build_nmb(char *buf,struct packet_struct *p)
00893 {
00894         struct nmb_packet *nmb = &p->packet.nmb;
00895         unsigned char *ubuf = (unsigned char *)buf;
00896         int offset=0;
00897 
00898         /* put in the header */
00899         RSSVAL(ubuf,offset,nmb->header.name_trn_id);
00900         ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3;
00901         if (nmb->header.response)
00902                 ubuf[offset+2] |= (1<<7);
00903         if (nmb->header.nm_flags.authoritative && 
00904                         nmb->header.response)
00905                 ubuf[offset+2] |= 0x4;
00906         if (nmb->header.nm_flags.trunc)
00907                 ubuf[offset+2] |= 0x2;
00908         if (nmb->header.nm_flags.recursion_desired)
00909                 ubuf[offset+2] |= 0x1;
00910         if (nmb->header.nm_flags.recursion_available &&
00911                         nmb->header.response)
00912                 ubuf[offset+3] |= 0x80;
00913         if (nmb->header.nm_flags.bcast)
00914                 ubuf[offset+3] |= 0x10;
00915         ubuf[offset+3] |= (nmb->header.rcode & 0xF);
00916 
00917         RSSVAL(ubuf,offset+4,nmb->header.qdcount);
00918         RSSVAL(ubuf,offset+6,nmb->header.ancount);
00919         RSSVAL(ubuf,offset+8,nmb->header.nscount);
00920         RSSVAL(ubuf,offset+10,nmb->header.arcount);
00921   
00922         offset += 12;
00923         if (nmb->header.qdcount) {
00924                 /* XXXX this doesn't handle a qdcount of > 1 */
00925                 offset += put_nmb_name((char *)ubuf,offset,&nmb->question.question_name);
00926                 RSSVAL(ubuf,offset,nmb->question.question_type);
00927                 RSSVAL(ubuf,offset+2,nmb->question.question_class);
00928                 offset += 4;
00929         }
00930 
00931         if (nmb->header.ancount)
00932                 offset += put_res_rec((char *)ubuf,offset,nmb->answers,
00933                                 nmb->header.ancount);
00934 
00935         if (nmb->header.nscount)
00936                 offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs,
00937                                 nmb->header.nscount);
00938 
00939         /*
00940          * The spec says we must put compressed name pointers
00941          * in the following outgoing packets :
00942          * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST,
00943          * NAME_RELEASE_REQUEST.
00944          */
00945 
00946         if((nmb->header.response == False) &&
00947                         ((nmb->header.opcode == NMB_NAME_REG_OPCODE) ||
00948                         (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) ||
00949                         (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
00950                         (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) ||
00951                         (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) &&
00952                         (nmb->header.arcount == 1)) {
00953 
00954                 offset += put_compressed_name_ptr(ubuf,offset,nmb->additional,12);
00955 
00956         } else if (nmb->header.arcount) {
00957                 offset += put_res_rec((char *)ubuf,offset,nmb->additional,
00958                         nmb->header.arcount);  
00959         }
00960         return(offset);
00961 }
00962 
00963 /*******************************************************************
00964  Linearise a packet.
00965 ******************************************************************/
00966 
00967 int build_packet(char *buf, struct packet_struct *p)
00968 {
00969         int len = 0;
00970 
00971         switch (p->packet_type) {
00972         case NMB_PACKET:
00973                 len = build_nmb(buf,p);
00974                 break;
00975 
00976         case DGRAM_PACKET:
00977                 len = build_dgram(buf,p);
00978                 break;
00979         }
00980 
00981         return len;
00982 }
00983 
00984 /*******************************************************************
00985  Send a packet_struct.
00986 ******************************************************************/
00987 
00988 BOOL send_packet(struct packet_struct *p)
00989 {
00990         char buf[1024];
00991         int len=0;
00992 
00993         memset(buf,'\0',sizeof(buf));
00994 
00995         len = build_packet(buf, p);
00996 
00997         if (!len)
00998                 return(False);
00999 
01000         return(send_udp(p->fd,buf,len,p->ip,p->port));
01001 }
01002 
01003 /****************************************************************************
01004  Receive a packet with timeout on a open UDP filedescriptor.
01005  The timeout is in milliseconds
01006 ***************************************************************************/
01007 
01008 struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
01009 {
01010         fd_set fds;
01011         struct timeval timeout;
01012         int ret;
01013 
01014         FD_ZERO(&fds);
01015         FD_SET(fd,&fds);
01016         timeout.tv_sec = t/1000;
01017         timeout.tv_usec = 1000*(t%1000);
01018 
01019         if ((ret = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout)) == -1) {
01020                 /* errno should be EBADF or EINVAL. */
01021                 DEBUG(0,("select returned -1, errno = %s (%d)\n", strerror(errno), errno));
01022                 return NULL;
01023         }
01024 
01025         if (ret == 0) /* timeout */
01026                 return NULL;
01027 
01028         if (FD_ISSET(fd,&fds)) 
01029                 return(read_packet(fd,type));
01030         
01031         return(NULL);
01032 }
01033 
01034 /****************************************************************************
01035  Receive a UDP/137 packet either via UDP or from the unexpected packet
01036  queue. The packet must be a reply packet and have the specified trn_id.
01037  The timeout is in milliseconds.
01038 ***************************************************************************/
01039 
01040 struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id)
01041 {
01042         struct packet_struct *p;
01043 
01044         p = receive_packet(fd, NMB_PACKET, t);
01045 
01046         if (p && p->packet.nmb.header.response &&
01047                         p->packet.nmb.header.name_trn_id == trn_id) {
01048                 return p;
01049         }
01050         if (p)
01051                 free_packet(p);
01052 
01053         /* try the unexpected packet queue */
01054         return receive_unexpected(NMB_PACKET, trn_id, NULL);
01055 }
01056 
01057 /****************************************************************************
01058  Receive a UDP/138 packet either via UDP or from the unexpected packet
01059  queue. The packet must be a reply packet and have the specified mailslot name
01060  The timeout is in milliseconds.
01061 ***************************************************************************/
01062 
01063 struct packet_struct *receive_dgram_packet(int fd, int t, const char *mailslot_name)
01064 {
01065         struct packet_struct *p;
01066 
01067         p = receive_packet(fd, DGRAM_PACKET, t);
01068 
01069         if (p && match_mailslot_name(p, mailslot_name)) {
01070                 return p;
01071         }
01072         if (p)
01073                 free_packet(p);
01074 
01075         /* try the unexpected packet queue */
01076         return receive_unexpected(DGRAM_PACKET, 0, mailslot_name);
01077 }
01078 
01079 /****************************************************************************
01080  See if a datagram has the right mailslot name.
01081 ***************************************************************************/
01082 
01083 BOOL match_mailslot_name(struct packet_struct *p, const char *mailslot_name)
01084 {
01085         struct dgram_packet *dgram = &p->packet.dgram;
01086         char *buf;
01087 
01088         buf = &dgram->data[0];
01089         buf -= 4;
01090 
01091         buf = smb_buf(buf);
01092 
01093         if (memcmp(buf, mailslot_name, strlen(mailslot_name)+1) == 0) {
01094                 return True;
01095         }
01096 
01097         return False;
01098 }
01099 
01100 /****************************************************************************
01101  Return the number of bits that match between two 4 character buffers
01102 ***************************************************************************/
01103 
01104 int matching_quad_bits(unsigned char *p1, unsigned char *p2)
01105 {
01106         int i, j, ret = 0;
01107         for (i=0; i<4; i++) {
01108                 if (p1[i] != p2[i])
01109                         break;
01110                 ret += 8;
01111         }
01112 
01113         if (i==4)
01114                 return ret;
01115 
01116         for (j=0; j<8; j++) {
01117                 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
01118                         break;
01119                 ret++;
01120         }       
01121         
01122         return ret;
01123 }
01124 
01125 static unsigned char sort_ip[4];
01126 
01127 /****************************************************************************
01128  Compare two query reply records.
01129 ***************************************************************************/
01130 
01131 static int name_query_comp(unsigned char *p1, unsigned char *p2)
01132 {
01133         return matching_quad_bits(p2+2, sort_ip) - matching_quad_bits(p1+2, sort_ip);
01134 }
01135 
01136 /****************************************************************************
01137  Sort a set of 6 byte name query response records so that the IPs that
01138  have the most leading bits in common with the specified address come first.
01139 ***************************************************************************/
01140 
01141 void sort_query_replies(char *data, int n, struct in_addr ip)
01142 {
01143         if (n <= 1)
01144                 return;
01145 
01146         putip(sort_ip, (char *)&ip);
01147 
01148         qsort(data, n, 6, QSORT_CAST name_query_comp);
01149 }
01150 
01151 /*******************************************************************
01152  Convert, possibly using a stupid microsoft-ism which has destroyed
01153  the transport independence of netbios (for CIFS vendors that usually
01154  use the Win95-type methods, not for NT to NT communication, which uses
01155  DCE/RPC and therefore full-length unicode strings...) a dns name into
01156  a netbios name.
01157 
01158  The netbios name (NOT necessarily null-terminated) is truncated to 15
01159  characters.
01160 
01161  ******************************************************************/
01162 
01163 char *dns_to_netbios_name(const char *dns_name)
01164 {
01165         static nstring netbios_name;
01166         int i;
01167         StrnCpy(netbios_name, dns_name, MAX_NETBIOSNAME_LEN-1);
01168         netbios_name[15] = 0;
01169         
01170         /* ok.  this is because of a stupid microsoft-ism.  if the called host
01171            name contains a '.', microsoft clients expect you to truncate the
01172            netbios name up to and including the '.'  this even applies, by
01173            mistake, to workgroup (domain) names, which is _really_ daft.
01174          */
01175         for (i = 0; i < 15; i++) {
01176                 if (netbios_name[i] == '.') {
01177                         netbios_name[i] = 0;
01178                         break;
01179                 }
01180         }
01181 
01182         return netbios_name;
01183 }
01184 
01185 /****************************************************************************
01186  Interpret the weird netbios "name" into a unix fstring. Return the name type.
01187 ****************************************************************************/
01188 
01189 static int name_interpret(char *in, fstring name)
01190 {
01191         int ret;
01192         int len = (*in++) / 2;
01193         fstring out_string;
01194         char *out = out_string;
01195 
01196         *out=0;
01197 
01198         if (len > 30 || len<1)
01199                 return(0);
01200 
01201         while (len--) {
01202                 if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
01203                         *out = 0;
01204                         return(0);
01205                 }
01206                 *out = ((in[0]-'A')<<4) + (in[1]-'A');
01207                 in += 2;
01208                 out++;
01209         }
01210         ret = out[-1];
01211         out[-1] = 0;
01212 
01213 #ifdef NETBIOS_SCOPE
01214         /* Handle any scope names */
01215         while(*in) {
01216                 *out++ = '.'; /* Scope names are separated by periods */
01217                 len = *(unsigned char *)in++;
01218                 StrnCpy(out, in, len);
01219                 out += len;
01220                 *out=0;
01221                 in += len;
01222         }
01223 #endif
01224         pull_ascii_fstring(name, out_string);
01225 
01226         return(ret);
01227 }
01228 
01229 /****************************************************************************
01230  Mangle a name into netbios format.
01231  Note:  <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
01232 ****************************************************************************/
01233 
01234 int name_mangle( char *In, char *Out, char name_type )
01235 {
01236         int   i;
01237         int   len;
01238         nstring buf;
01239         char *p = Out;
01240 
01241         /* Safely copy the input string, In, into buf[]. */
01242         if (strcmp(In,"*") == 0)
01243                 put_name(buf, "*", '\0', 0x00);
01244         else {
01245                 /* We use an fstring here as mb dos names can expend x3 when
01246                    going to utf8. */
01247                 fstring buf_unix;
01248                 nstring buf_dos;
01249 
01250                 pull_ascii_fstring(buf_unix, In);
01251                 strupper_m(buf_unix);
01252 
01253                 push_ascii_nstring(buf_dos, buf_unix);
01254                 put_name(buf, buf_dos, ' ', name_type);
01255         }
01256 
01257         /* Place the length of the first field into the output buffer. */
01258         p[0] = 32;
01259         p++;
01260 
01261         /* Now convert the name to the rfc1001/1002 format. */
01262         for( i = 0; i < MAX_NETBIOSNAME_LEN; i++ ) {
01263                 p[i*2]     = ( (buf[i] >> 4) & 0x000F ) + 'A';
01264                 p[(i*2)+1] = (buf[i] & 0x000F) + 'A';
01265         }
01266         p += 32;
01267         p[0] = '\0';
01268 
01269         /* Add the scope string. */
01270         for( i = 0, len = 0; *(global_scope()) != '\0'; i++, len++ ) {
01271                 switch( (global_scope())[i] ) {
01272                         case '\0':
01273                                 p[0] = len;
01274                                 if( len > 0 )
01275                                         p[len+1] = 0;
01276                                 return( name_len(Out) );
01277                         case '.':
01278                                 p[0] = len;
01279                                 p   += (len + 1);
01280                                 len  = -1;
01281                                 break;
01282                         default:
01283                                 p[len+1] = (global_scope())[i];
01284                                 break;
01285                 }
01286         }
01287 
01288         return( name_len(Out) );
01289 }
01290 
01291 /****************************************************************************
01292  Find a pointer to a netbios name.
01293 ****************************************************************************/
01294 
01295 static char *name_ptr(char *buf,int ofs)
01296 {
01297         unsigned char c = *(unsigned char *)(buf+ofs);
01298 
01299         if ((c & 0xC0) == 0xC0) {
01300                 uint16 l = RSVAL(buf, ofs) & 0x3FFF;
01301                 DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
01302                 return(buf + l);
01303         } else {
01304                 return(buf+ofs);
01305         }
01306 }  
01307 
01308 /****************************************************************************
01309  Extract a netbios name from a buf (into a unix string) return name type.
01310 ****************************************************************************/
01311 
01312 int name_extract(char *buf,int ofs, fstring name)
01313 {
01314         char *p = name_ptr(buf,ofs);
01315         int d = PTR_DIFF(p,buf+ofs);
01316 
01317         name[0] = '\0';
01318         if (d < -50 || d > 50)
01319                 return(0);
01320         return(name_interpret(p,name));
01321 }
01322   
01323 /****************************************************************************
01324  Return the total storage length of a mangled name.
01325 ****************************************************************************/
01326 
01327 int name_len(char *s1)
01328 {
01329         /* NOTE: this argument _must_ be unsigned */
01330         unsigned char *s = (unsigned char *)s1;
01331         int len;
01332 
01333         /* If the two high bits of the byte are set, return 2. */
01334         if (0xC0 == (*s & 0xC0))
01335                 return(2);
01336 
01337         /* Add up the length bytes. */
01338         for (len = 1; (*s); s += (*s) + 1) {
01339                 len += *s + 1;
01340                 SMB_ASSERT(len < 80);
01341         }
01342 
01343         return(len);
01344 }

Sambaに対してSat Aug 29 21:23:05 2009に生成されました。  doxygen 1.4.7