nmbd/nmbd_incomingrequests.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    NBT netbios routines and daemon - version 2
00004    Copyright (C) Andrew Tridgell 1994-1998
00005    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
00006    Copyright (C) Jeremy Allison 1994-2003
00007    
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012    
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017    
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021    
00022    This file contains all the code to process NetBIOS requests coming
00023    in on port 137. It does not deal with the code needed to service
00024    WINS server requests, but only broadcast and unicast requests.
00025 
00026 */
00027 
00028 #include "includes.h"
00029 
00030 /****************************************************************************
00031 Send a name release response.
00032 **************************************************************************/
00033 
00034 static void send_name_release_response(int rcode, struct packet_struct *p)
00035 {
00036         struct nmb_packet *nmb = &p->packet.nmb;
00037         char rdata[6];
00038 
00039         memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
00040   
00041         reply_netbios_packet(p,                       /* Packet to reply to. */
00042                         rcode,                        /* Result code. */
00043                         NMB_REL,                      /* nmbd type code. */
00044                         NMB_NAME_RELEASE_OPCODE,      /* opcode. */
00045                         0,                            /* ttl. */
00046                         rdata,                        /* data to send. */
00047                         6);                           /* data length. */
00048 }
00049 
00050 /****************************************************************************
00051 Process a name release packet on a broadcast subnet.
00052 Ignore it if it's not one of our names.
00053 ****************************************************************************/
00054 
00055 void process_name_release_request(struct subnet_record *subrec, 
00056                                   struct packet_struct *p)
00057 {
00058         struct nmb_packet *nmb = &p->packet.nmb;
00059         struct in_addr owner_ip;
00060         struct nmb_name *question = &nmb->question.question_name;
00061         unstring qname;
00062         BOOL bcast = nmb->header.nm_flags.bcast;
00063         uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
00064         BOOL group = (nb_flags & NB_GROUP) ? True : False;
00065         struct name_record *namerec;
00066         int rcode = 0;
00067   
00068         putip((char *)&owner_ip,&nmb->additional->rdata[2]);  
00069   
00070         if(!bcast) {
00071                 /* We should only get broadcast name release packets here.
00072                    Anyone trying to release unicast should be going to a WINS
00073                    server. If the code gets here, then either we are not a wins
00074                    server and they sent it anyway, or we are a WINS server and
00075                    the request was malformed. Either way, log an error here.
00076                    and send an error reply back.
00077                 */
00078                 DEBUG(0,("process_name_release_request: unicast name release request \
00079 received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
00080                         nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));      
00081 
00082                 send_name_release_response(FMT_ERR, p);
00083                 return;
00084         }
00085 
00086         DEBUG(3,("process_name_release_request: Name release on name %s, \
00087 subnet %s from owner IP %s\n",
00088                 nmb_namestr(&nmb->question.question_name),
00089                 subrec->subnet_name, inet_ntoa(owner_ip)));
00090   
00091         /* If someone is releasing a broadcast group name, just ignore it. */
00092         if( group && !ismyip(owner_ip) )
00093                 return;
00094 
00095         /*
00096          * Code to work around a bug in FTP OnNet software NBT implementation.
00097          * They do a broadcast name release for WORKGROUP<0> and WORKGROUP<1e>
00098          * names and *don't set the group bit* !!!!!
00099          */
00100 
00101         pull_ascii_nstring(qname, sizeof(qname), question->name);
00102         if( !group && !ismyip(owner_ip) && strequal(qname, lp_workgroup()) && 
00103                         ((question->name_type == 0x0) || (question->name_type == 0x1e))) {
00104                 DEBUG(6,("process_name_release_request: FTP OnNet bug workaround. Ignoring \
00105 group release name %s from IP %s on subnet %s with no group bit set.\n",
00106                         nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name ));
00107                 return;
00108         }
00109 
00110         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
00111 
00112         /* We only care about someone trying to release one of our names. */
00113         if( namerec && ( (namerec->data.source == SELF_NAME)
00114                         || (namerec->data.source == PERMANENT_NAME) ) ) {
00115                 rcode = ACT_ERR;
00116                 DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
00117 on subnet %s being rejected as it is one of our names.\n", 
00118                 nmb_namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
00119         }
00120 
00121         if(rcode == 0)
00122                 return;
00123 
00124         /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
00125         send_name_release_response(rcode, p);
00126 }
00127 
00128 /****************************************************************************
00129 Send a name registration response.
00130 **************************************************************************/
00131 
00132 static void send_name_registration_response(int rcode, int ttl, struct packet_struct *p)
00133 {
00134         struct nmb_packet *nmb = &p->packet.nmb;
00135         char rdata[6];
00136 
00137         memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
00138   
00139         reply_netbios_packet(p,                                /* Packet to reply to. */
00140                                 rcode,                         /* Result code. */
00141                                 NMB_REG,                       /* nmbd type code. */
00142                                 NMB_NAME_REG_OPCODE,           /* opcode. */
00143                                 ttl,                           /* ttl. */
00144                                 rdata,                         /* data to send. */
00145                                 6);                            /* data length. */
00146 }
00147 
00148 /****************************************************************************
00149 Process a name refresh request on a broadcast subnet.
00150 **************************************************************************/
00151      
00152 void process_name_refresh_request(struct subnet_record *subrec,
00153                                   struct packet_struct *p)
00154 {    
00155         struct nmb_packet *nmb = &p->packet.nmb;
00156         struct nmb_name *question = &nmb->question.question_name;
00157         BOOL bcast = nmb->header.nm_flags.bcast;
00158         struct in_addr from_ip;
00159   
00160         putip((char *)&from_ip,&nmb->additional->rdata[2]);
00161 
00162         if(!bcast) { 
00163                 /* We should only get broadcast name refresh packets here.
00164                    Anyone trying to refresh unicast should be going to a WINS
00165                    server. If the code gets here, then either we are not a wins
00166                    server and they sent it anyway, or we are a WINS server and
00167                    the request was malformed. Either way, log an error here.
00168                    and send an error reply back.
00169                 */
00170                 DEBUG(0,("process_name_refresh_request: unicast name registration request \
00171 received for name %s from IP %s on subnet %s.\n",
00172                         nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
00173                 DEBUG(0,("Error - should be sent to WINS server\n"));
00174     
00175                 send_name_registration_response(FMT_ERR, 0, p);
00176                 return;
00177         } 
00178 
00179         /* Just log a message. We really don't care about broadcast name refreshes. */
00180      
00181         DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
00182 IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
00183 }
00184     
00185 /****************************************************************************
00186 Process a name registration request on a broadcast subnet.
00187 **************************************************************************/
00188 
00189 void process_name_registration_request(struct subnet_record *subrec, 
00190                                        struct packet_struct *p)
00191 {
00192         struct nmb_packet *nmb = &p->packet.nmb;
00193         struct nmb_name *question = &nmb->question.question_name;
00194         BOOL bcast = nmb->header.nm_flags.bcast;
00195         uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
00196         BOOL group = (nb_flags & NB_GROUP) ? True : False;
00197         struct name_record *namerec = NULL;
00198         int ttl = nmb->additional->ttl;
00199         struct in_addr from_ip;
00200   
00201         putip((char *)&from_ip,&nmb->additional->rdata[2]);
00202   
00203         if(!bcast) {
00204                 /* We should only get broadcast name registration packets here.
00205                    Anyone trying to register unicast should be going to a WINS
00206                    server. If the code gets here, then either we are not a wins
00207                    server and they sent it anyway, or we are a WINS server and
00208                    the request was malformed. Either way, log an error here.
00209                    and send an error reply back.
00210                 */
00211                 DEBUG(0,("process_name_registration_request: unicast name registration request \
00212 received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
00213                         nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));      
00214 
00215                 send_name_registration_response(FMT_ERR, 0, p);
00216                 return;
00217         }
00218 
00219         DEBUG(3,("process_name_registration_request: Name registration for name %s \
00220 IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
00221   
00222         /* See if the name already exists. */
00223         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
00224  
00225         /* 
00226          * If the name being registered exists and is a WINS_PROXY_NAME 
00227          * then delete the WINS proxy name entry so we don't reply erroneously
00228          * later to queries.
00229          */
00230 
00231         if((namerec != NULL) && (namerec->data.source == WINS_PROXY_NAME)) {
00232                 remove_name_from_namelist( subrec, namerec );
00233                 namerec = NULL;
00234         }
00235 
00236         if (!group) {
00237                 /* Unique name. */
00238 
00239                 if( (namerec != NULL)
00240                                 && ( (namerec->data.source == SELF_NAME)
00241                                 || (namerec->data.source == PERMANENT_NAME)
00242                                 || NAME_GROUP(namerec) ) ) {
00243                         /* No-one can register one of Samba's names, nor can they
00244                                 register a name that's a group name as a unique name */
00245 
00246                         send_name_registration_response(ACT_ERR, 0, p);
00247                         return;
00248                 } else if(namerec != NULL) {
00249                         /* Update the namelist record with the new information. */
00250                         namerec->data.ip[0] = from_ip;
00251                         update_name_ttl(namerec, ttl);
00252 
00253                         DEBUG(3,("process_name_registration_request: Updated name record %s \
00254 with IP %s on subnet %s\n",nmb_namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
00255                         return;
00256                 }
00257         } else {
00258                 /* Group name. */
00259 
00260                 if( (namerec != NULL)
00261                                 && !NAME_GROUP(namerec)
00262                                 && ( (namerec->data.source == SELF_NAME)
00263                                 || (namerec->data.source == PERMANENT_NAME) ) ) {
00264                         /* Disallow group names when we have a unique name. */
00265                         send_name_registration_response(ACT_ERR, 0, p);  
00266                         return;  
00267                 }  
00268         }
00269 }
00270 
00271 /****************************************************************************
00272 This is used to sort names for a name status into a sensible order.
00273 We put our own names first, then in alphabetical order.
00274 **************************************************************************/
00275 
00276 static int status_compare(char *n1,char *n2)
00277 {
00278         unstring name1, name2;
00279         int l1,l2,l3;
00280 
00281         memset(name1, '\0', sizeof(name1));
00282         memset(name2, '\0', sizeof(name2));
00283         pull_ascii_nstring(name1, sizeof(name1), n1);
00284         pull_ascii_nstring(name2, sizeof(name2), n2);
00285         n1 = name1;
00286         n2 = name2;
00287 
00288         /* It's a bit tricky because the names are space padded */
00289         for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++)
00290                 ;
00291         for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++)
00292                 ;
00293         l3 = strlen(global_myname());
00294 
00295         if ((l1==l3) && strncmp(n1,global_myname(),l3) == 0 && 
00296                         (l2!=l3 || strncmp(n2,global_myname(),l3) != 0))
00297                 return -1;
00298 
00299         if ((l2==l3) && strncmp(n2,global_myname(),l3) == 0 && 
00300                         (l1!=l3 || strncmp(n1,global_myname(),l3) != 0))
00301                 return 1;
00302 
00303         return memcmp(n1,n2,sizeof(name1));
00304 }
00305 
00306 /****************************************************************************
00307   Process a node status query
00308   ****************************************************************************/
00309 
00310 void process_node_status_request(struct subnet_record *subrec, struct packet_struct *p)
00311 {
00312         struct nmb_packet *nmb = &p->packet.nmb;
00313         unstring qname;
00314         int ques_type = nmb->question.question_name.name_type;
00315         char rdata[MAX_DGRAM_SIZE];
00316         char *countptr, *buf, *bufend, *buf0;
00317         int names_added,i;
00318         struct name_record *namerec;
00319 
00320         pull_ascii_nstring(qname, sizeof(qname), nmb->question.question_name.name);
00321 
00322         DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
00323 subnet %s.\n", nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip), subrec->subnet_name));
00324 
00325         if((namerec = find_name_on_subnet(subrec, &nmb->question.question_name, FIND_SELF_NAME)) == 0) {
00326                 DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
00327 subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name),
00328                         inet_ntoa(p->ip), subrec->subnet_name));
00329 
00330                 return;
00331         }
00332  
00333         /* this is not an exact calculation. the 46 is for the stats buffer
00334                 and the 60 is to leave room for the header etc */
00335         bufend = &rdata[MAX_DGRAM_SIZE] - (18 + 46 + 60);
00336         countptr = buf = rdata;
00337         buf += 1;
00338         buf0 = buf;
00339 
00340         names_added = 0;
00341 
00342         namerec = subrec->namelist;
00343 
00344         while (buf < bufend) {
00345                 if( (namerec->data.source == SELF_NAME) || (namerec->data.source == PERMANENT_NAME) ) {
00346                         int name_type = namerec->name.name_type;
00347                         unstring name;
00348 
00349                         pull_ascii_nstring(name, sizeof(name), namerec->name.name);
00350                         strupper_m(name);
00351                         if (!strequal(name,"*") &&
00352                                         !strequal(name,"__SAMBA__") &&
00353                                         (name_type < 0x1b || name_type >= 0x20 || 
00354                                         ques_type < 0x1b || ques_type >= 0x20 ||
00355                                         strequal(qname, name))) {
00356                                 /* Start with the name. */
00357                                 size_t len;
00358                                 push_ascii_nstring(buf, name);
00359                                 len = strlen(buf);
00360                                 memset(buf + len, ' ', MAX_NETBIOSNAME_LEN - len - 1);
00361                                 buf[MAX_NETBIOSNAME_LEN - 1] = '\0';
00362 
00363                                 /* Put the name type and netbios flags in the buffer. */
00364 
00365                                 buf[15] = name_type;
00366                                 set_nb_flags( &buf[16],namerec->data.nb_flags );
00367                                 buf[16] |= NB_ACTIVE; /* all our names are active */
00368 
00369                                 buf += 18;
00370 
00371                                 names_added++;
00372                         }
00373                 }
00374 
00375                 /* Remove duplicate names. */
00376                 if (names_added > 1) {
00377                         qsort( buf0, names_added, 18, QSORT_CAST status_compare );
00378                 }
00379 
00380                 for( i=1; i < names_added ; i++ ) {
00381                         if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
00382                                 names_added--;
00383                                 if (names_added == i)
00384                                         break;
00385                                 memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
00386                                 i--;
00387                         }
00388                 }
00389 
00390                 buf = buf0 + 18*names_added;
00391 
00392                 namerec = namerec->next;
00393 
00394                 if (!namerec) {
00395                         /* End of the subnet specific name list. Now 
00396                                 add the names on the unicast subnet . */
00397                         struct subnet_record *uni_subrec = unicast_subnet;
00398 
00399                         if (uni_subrec != subrec) {
00400                                 subrec = uni_subrec;
00401                                 namerec = subrec->namelist;
00402                         }
00403                 }
00404                 if (!namerec)
00405                         break;
00406 
00407         }
00408   
00409         SCVAL(countptr,0,names_added);
00410   
00411         /* We don't send any stats as they could be used to attack
00412                 the protocol. */
00413         memset(buf,'\0',46);
00414   
00415         buf += 46;
00416   
00417         /* Send a NODE STATUS RESPONSE */
00418         reply_netbios_packet(p,                               /* Packet to reply to. */
00419                                 0,                            /* Result code. */
00420                                 NMB_STATUS,                   /* nmbd type code. */
00421                                 NMB_NAME_QUERY_OPCODE,        /* opcode. */
00422                                 0,                            /* ttl. */
00423                                 rdata,                        /* data to send. */
00424                                 PTR_DIFF(buf,rdata));         /* data length. */
00425 }
00426 
00427 
00428 /***************************************************************************
00429 Process a name query.
00430 
00431 For broadcast name queries:
00432 
00433   - Only reply if the query is for one of YOUR names.
00434   - NEVER send a negative response to a broadcast query.
00435 
00436 ****************************************************************************/
00437 
00438 void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p)
00439 {
00440         struct nmb_packet *nmb = &p->packet.nmb;
00441         struct nmb_name *question = &nmb->question.question_name;
00442         int name_type = question->name_type;
00443         BOOL bcast = nmb->header.nm_flags.bcast;
00444         int ttl=0;
00445         int rcode = 0;
00446         char *prdata = NULL;
00447         char rdata[6];
00448         BOOL success = False;
00449         struct name_record *namerec = NULL;
00450         int reply_data_len = 0;
00451         int i;
00452         
00453         DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n", 
00454                  inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question)));
00455   
00456         /* Look up the name in the cache - if the request is a broadcast request that
00457            came from a subnet we don't know about then search all the broadcast subnets
00458            for a match (as we don't know what interface the request came in on). */
00459 
00460         if(subrec == remote_broadcast_subnet)
00461                 namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
00462         else
00463                 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
00464 
00465         /* Check if it is a name that expired */
00466         if (namerec && 
00467             ((namerec->data.death_time != PERMANENT_TTL) && 
00468              (namerec->data.death_time < p->timestamp))) {
00469                 DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name)));
00470                 namerec = NULL;
00471         }
00472 
00473         if (namerec) {
00474                 /* 
00475                  * Always respond to unicast queries.
00476                  * Don't respond to broadcast queries unless the query is for
00477                  * a name we own, a Primary Domain Controller name, or a WINS_PROXY 
00478                  * name with type 0 or 0x20. WINS_PROXY names are only ever added
00479                  * into the namelist if we were configured as a WINS proxy.
00480                  */
00481                 
00482                 if (!bcast || 
00483                     (bcast && ((name_type == 0x1b) ||
00484                                (namerec->data.source == SELF_NAME) ||
00485                                (namerec->data.source == PERMANENT_NAME) ||
00486                                ((namerec->data.source == WINS_PROXY_NAME) &&
00487                                 ((name_type == 0) || (name_type == 0x20)))))) {
00488                         /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY, 
00489                            or it's a Domain Master type. */
00490 
00491                         /*
00492                          * If this is a WINS_PROXY_NAME, then ceck that none of the IP 
00493                          * addresses we are returning is on the same broadcast subnet 
00494                          * as the requesting packet. If it is then don't reply as the 
00495                          * actual machine will be replying also and we don't want two 
00496                          * replies to a broadcast query.
00497                          */
00498                         
00499                         if (namerec->data.source == WINS_PROXY_NAME) {
00500                                 for( i = 0; i < namerec->data.num_ips; i++) {
00501                                         if (same_net(namerec->data.ip[i], subrec->myip, subrec->mask_ip)) {
00502                                                 DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also on the same subnet (%s) as the requestor. Not replying.\n", 
00503                                                          nmb_namestr(&namerec->name), subrec->subnet_name ));
00504                                                 return;
00505                                         }
00506                                 }
00507                         }
00508 
00509                         ttl = (namerec->data.death_time != PERMANENT_TTL) ?
00510                                 namerec->data.death_time - p->timestamp : lp_max_ttl();
00511 
00512                         /* Copy all known ip addresses into the return data. */
00513                         /* Optimise for the common case of one IP address so 
00514                            we don't need a malloc. */
00515 
00516                         if (namerec->data.num_ips == 1) {
00517                                 prdata = rdata;
00518                         } else {
00519                                 if ((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
00520                                         DEBUG(0,("process_name_query_request: malloc fail !\n"));
00521                                         return;
00522                                 }
00523                         }
00524 
00525                         for (i = 0; i < namerec->data.num_ips; i++) {
00526                                 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
00527                                 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
00528                         }
00529 
00530                         sort_query_replies(prdata, i, p->ip);
00531                         
00532                         reply_data_len = namerec->data.num_ips * 6;
00533                         success = True;
00534                 }
00535         }
00536 
00537         /*
00538          * If a machine is broadcasting a name lookup request and we have lp_wins_proxy()
00539          * set we should initiate a WINS query here. On success we add the resolved name 
00540          * into our namelist with a type of WINS_PROXY_NAME and then reply to the query.
00541          */
00542         
00543         if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() && 
00544            bcast && (subrec != remote_broadcast_subnet)) {
00545                 make_wins_proxy_name_query_request( subrec, p, question );
00546                 return;
00547         }
00548 
00549         if (!success && bcast) {
00550                 if(prdata != rdata)
00551                         SAFE_FREE(prdata);
00552                 return; /* Never reply with a negative response to broadcasts. */
00553         }
00554 
00555         /* 
00556          * Final check. From observation, if a unicast packet is sent
00557          * to a non-WINS server with the recursion desired bit set
00558          * then never send a negative response.
00559          */
00560         
00561         if(!success && !bcast && nmb->header.nm_flags.recursion_desired) {
00562                 if(prdata != rdata)
00563                         SAFE_FREE(prdata);
00564                 return;
00565         }
00566 
00567         if (success) {
00568                 rcode = 0;
00569                 DEBUG(3,("OK\n"));
00570         } else {
00571                 rcode = NAM_ERR;
00572                 DEBUG(3,("UNKNOWN\n"));      
00573         }
00574 
00575         /* See rfc1002.txt 4.2.13. */
00576 
00577         reply_netbios_packet(p,                              /* Packet to reply to. */
00578                              rcode,                          /* Result code. */
00579                              NMB_QUERY,                      /* nmbd type code. */
00580                              NMB_NAME_QUERY_OPCODE,          /* opcode. */
00581                              ttl,                            /* ttl. */
00582                              prdata,                         /* data to send. */
00583                              reply_data_len);                /* data length. */
00584         
00585         if(prdata != rdata)
00586                 SAFE_FREE(prdata);
00587 }

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