home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Wtestowe / Clico / UNIX / SAMBA / SOURCE / SAMBA.TAR / samba-1.9.17 / source / namedbname.c < prev    next >
C/C++ Source or Header  |  1997-06-06  |  16KB  |  600 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    NBT netbios routines and daemon - version 2
  5.    Copyright (C) Andrew Tridgell 1994-1997
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.    
  21.    Module name: namedbname.c
  22.  
  23.    Revision History:
  24.  
  25.    14 jan 96: lkcl@pires.co.uk
  26.    added multiple workgroup domain master support
  27.  
  28.    04 jul 96: lkcl@pires.co.uk
  29.    created module namedbname containing name database functions
  30. */
  31.  
  32. #include "includes.h"
  33.  
  34. extern int DEBUGLEVEL;
  35.  
  36. extern pstring scope;
  37. extern struct in_addr ipzero;
  38. extern struct in_addr wins_ip;
  39. extern BOOL updatedlists;
  40.  
  41. extern struct subnet_record *subnetlist;
  42.  
  43. #define WINS_LIST "wins.dat"
  44.  
  45. uint16 nb_type = 0; /* samba's NetBIOS name type */
  46.  
  47.  
  48. /****************************************************************************
  49.   samba's NetBIOS name type
  50.  
  51.   XXXX maybe functionality could be set: B, M, P or H name registration
  52.   and resolution could be set through nb_type. just a thought.  
  53.   ****************************************************************************/
  54. void set_samba_nb_type(void)
  55. {
  56.   if (lp_wins_support() || (*lp_wins_server()))
  57.   {
  58.     nb_type = NB_MFLAG; /* samba is a 'hybrid' node type */
  59.   }
  60.   else
  61.   {
  62.     nb_type = NB_BFLAG; /* samba is broadcast-only node type */
  63.   }
  64. }
  65.  
  66.  
  67. /****************************************************************************
  68.   true if two netbios names are equal
  69. ****************************************************************************/
  70. BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
  71. {
  72.   return n1->name_type == n2->name_type &&
  73.          strequal(n1->name ,n2->name ) &&
  74.          strequal(n1->scope,n2->scope);
  75. }
  76.  
  77.  
  78. /****************************************************************************
  79.   true if the netbios name is ^1^2__MSBROWSE__^2^1
  80.  
  81.   note: this name is registered if as a master browser or backup browser
  82.   you are responsible for a workgroup (when you announce a domain by
  83.   broadcasting on your local subnet, you announce it as coming from this
  84.   name: see announce_host()).
  85.  
  86.   **************************************************************************/
  87. BOOL ms_browser_name(char *name, int type)
  88. {
  89.   return strequal(name,MSBROWSE) && type == 0x01;
  90. }
  91.  
  92.  
  93. /****************************************************************************
  94.   add a netbios name into the namelist
  95.   **************************************************************************/
  96. static void add_name(struct subnet_record *d, struct name_record *n)
  97. {
  98.   struct name_record *n2;
  99.  
  100.   if (!d) return;
  101.  
  102.   if (!d->namelist)
  103.   {
  104.     d->namelist = n;
  105.     n->prev = NULL;
  106.     n->next = NULL;
  107.     return;
  108.   }
  109.  
  110.   for (n2 = d->namelist; n2->next; n2 = n2->next) ;
  111.  
  112.   n2->next = n;
  113.   n->next = NULL;
  114.   n->prev = n2;
  115.  
  116.   if((d == wins_subnet) && lp_wins_support())
  117.     updatedlists = True;
  118. }
  119.  
  120.  
  121. /****************************************************************************
  122.   remove a name from the namelist. The pointer must be an element just 
  123.   retrieved
  124.   **************************************************************************/
  125. void remove_name(struct subnet_record *d, struct name_record *n)
  126. {
  127.   struct name_record *nlist;
  128.   if (!d) return;
  129.  
  130.   nlist = d->namelist;
  131.  
  132.   while (nlist && nlist != n) nlist = nlist->next;
  133.  
  134.   if (nlist)
  135.   {
  136.     if (nlist->next) nlist->next->prev = nlist->prev;
  137.     if (nlist->prev) nlist->prev->next = nlist->next;
  138.  
  139.     if(nlist == d->namelist)
  140.       d->namelist = nlist->next;
  141.  
  142.     if(nlist->ip_flgs != NULL)
  143.       free(nlist->ip_flgs);
  144.     free(nlist);
  145.   }
  146.  
  147.   if((d == wins_subnet) && lp_wins_support())
  148.     updatedlists = True;
  149. }
  150.  
  151.  
  152. /****************************************************************************
  153.   find a name in a namelist.
  154.   **************************************************************************/
  155. struct name_record *find_name(struct name_record *n,
  156.             struct nmb_name *name, int search)
  157. {
  158.   struct name_record *ret;
  159.   
  160.   for (ret = n; ret; ret = ret->next)
  161.   {
  162.     if (name_equal(&ret->name,name))
  163.     {
  164.       /* self search: self names only */
  165.       if ((search&FIND_SELF) == FIND_SELF && ret->source != SELF)
  166.       {
  167.         continue;
  168.       }
  169.       DEBUG(9,("find_name: found name %s(%02x)\n", 
  170.                 name->name, name->name_type));
  171.       return ret;
  172.     }
  173.   }
  174.   DEBUG(9,("find_name: name %s(%02x) NOT FOUND\n", name->name, 
  175.             name->name_type));
  176.   return NULL;
  177. }
  178.  
  179.  
  180. /****************************************************************************
  181.   find a name in the domain database namelist 
  182.   search can be any of:
  183.   FIND_SELF - look exclusively for names the samba server has added for itself
  184.   FIND_LOCAL - look for names in the local subnet record.
  185.   FIND_WINS - look for names in the WINS record
  186.   **************************************************************************/
  187. struct name_record *find_name_search(struct subnet_record **d,
  188.             struct nmb_name *name,
  189.             int search, struct in_addr ip)
  190. {
  191.   if (d == NULL) return NULL; /* bad error! */
  192.     
  193.   if (search & FIND_LOCAL) {
  194.     if (*d != NULL) {
  195.       struct name_record *n = find_name((*d)->namelist, name, search);
  196.       DEBUG(4,("find_name on local: %s %s search %x\n",
  197.            namestr(name),inet_ntoa(ip), search));
  198.       if (n) return n;
  199.     }
  200.   }
  201.  
  202.   if (!(search & FIND_WINS)) return NULL;
  203.  
  204.   /* find WINS subnet record. */
  205.   *d = wins_subnet;
  206.   
  207.   if (*d == NULL) return NULL;
  208.   
  209.   DEBUG(4,("find_name on WINS: %s %s search %x\n",
  210.        namestr(name),inet_ntoa(ip), search));
  211.   return find_name((*d)->namelist, name, search);
  212. }
  213.  
  214.  
  215. /****************************************************************************
  216.   dump a copy of the name table
  217.   **************************************************************************/
  218. void dump_names(void)
  219. {
  220.   struct name_record *n;
  221.   fstring fname, fnamenew;
  222.   time_t t = time(NULL);
  223.   
  224.   FILE *f;
  225.  
  226.   if(lp_wins_support() == False || wins_subnet == 0)
  227.     return;
  228.  
  229.   strcpy(fname,lp_lockdir());
  230.   trim_string(fname,NULL,"/");
  231.   strcat(fname,"/");
  232.   strcat(fname,WINS_LIST);
  233.   strcpy(fnamenew,fname);
  234.   strcat(fnamenew,".");
  235.   
  236.   f = fopen(fnamenew,"w");
  237.   
  238.   if (!f)
  239.   {
  240.     DEBUG(3,("Can't open %s - %s\n",fnamenew,strerror(errno)));
  241.     return;
  242.   }
  243.   
  244.   DEBUG(4,("Dump of WINS name table:\n"));
  245.   
  246.   for (n = wins_subnet->namelist; n; n = n->next)
  247.    {
  248.      int i;
  249.  
  250.      DEBUG(4,("%15s ", inet_ntoa(wins_subnet->bcast_ip)));
  251.      DEBUG(4,("%15s ", inet_ntoa(wins_subnet->mask_ip)));
  252.      DEBUG(4,("%-19s TTL=%ld ",
  253.            namestr(&n->name),
  254.            n->death_time?n->death_time-t:0));
  255.  
  256.      for (i = 0; i < n->num_ips; i++)
  257.       {
  258.         DEBUG(4,("%15s NB=%2x source=%d",
  259.                  inet_ntoa(n->ip_flgs[i].ip),
  260.             n->ip_flgs[i].nb_flags,n->source));
  261.  
  262.       }
  263.      DEBUG(4,("\n"));
  264.  
  265.      if (f && ((n->source == REGISTER) || (n->source == SELF)))
  266.       {
  267.       /* XXXX i have little imagination as to how to output nb_flags as
  268.          anything other than as a hexadecimal number :-) */
  269.  
  270.         fprintf(f, "%s#%02x %ld ",
  271.            n->name.name,n->name.name_type, /* XXXX ignore scope for now */
  272.            n->death_time);
  273.  
  274.         for (i = 0; i < n->num_ips; i++)
  275.         {
  276.            fprintf(f, "%s %2x%c ",
  277.                 inet_ntoa(n->ip_flgs[i].ip),
  278.                 n->ip_flgs[i].nb_flags, (n->source == REGISTER ? 'R' : 'S'));
  279.         }
  280.         fprintf(f, "\n");
  281.       }
  282.  
  283.   }
  284.  
  285.   fclose(f);
  286.   unlink(fname);
  287.   chmod(fnamenew,0644);
  288.   rename(fnamenew,fname);   
  289.  
  290.   DEBUG(3,("Wrote wins database %s\n",fname));
  291. }
  292.  
  293.  
  294. /****************************************************************************
  295.   load a netbios name database file
  296.  
  297.   XXXX we cannot cope with loading Internet Group names, yet
  298.   ****************************************************************************/
  299. void load_netbios_names(void)
  300. {
  301.   struct subnet_record *d = wins_subnet;
  302.   fstring fname;
  303.  
  304.   FILE *f;
  305.   pstring line;
  306.  
  307.   if (!d) return;
  308.  
  309.   strcpy(fname,lp_lockdir());
  310.   trim_string(fname,NULL,"/");
  311.   strcat(fname,"/");
  312.   strcat(fname,WINS_LIST);
  313.  
  314.   f = fopen(fname,"r");
  315.  
  316.   if (!f) {
  317.     DEBUG(2,("Can't open wins database file %s\n",fname));
  318.     return;
  319.   }
  320.  
  321.   while (!feof(f))
  322.     {
  323.       pstring name_str, ip_str, ttd_str, nb_flags_str;
  324.  
  325.       pstring name;
  326.       int type = 0;
  327.       unsigned int nb_flags;
  328.       time_t ttd;
  329.       struct in_addr ipaddr;
  330.  
  331.       enum name_source source;
  332.  
  333.       char *ptr;
  334.       int count = 0;
  335.  
  336.       char *p;
  337.  
  338.       if (!fgets_slash(line,sizeof(pstring),f)) continue;
  339.  
  340.       if (*line == '#') continue;
  341.  
  342.     ptr = line;
  343.  
  344.     if (next_token(&ptr,name_str    ,NULL)) ++count;
  345.     if (next_token(&ptr,ttd_str     ,NULL)) ++count;
  346.     if (next_token(&ptr,ip_str      ,NULL)) ++count;
  347.     if (next_token(&ptr,nb_flags_str,NULL)) ++count;
  348.  
  349.     if (count <= 0) continue;
  350.  
  351.     if (count != 4) {
  352.       DEBUG(0,("Ill formed wins line"));
  353.       DEBUG(0,("[%s]: name#type abs_time ip nb_flags\n",line));
  354.       continue;
  355.     }
  356.  
  357.       /* Deal with SELF or REGISTER name encoding. Default is REGISTER 
  358.          for compatibility with old nmbds. */
  359.       if(nb_flags_str[strlen(nb_flags_str)-1] == 'S')
  360.       {
  361.         DEBUG(5,("Ignoring SELF name %s\n", line));
  362.         continue;
  363.       }
  364.  
  365.       if(nb_flags_str[strlen(nb_flags_str)-1] == 'R')
  366.         nb_flags_str[strlen(nb_flags_str)-1] = '\0';
  367.  
  368.       /* netbios name. # divides the name from the type (hex): netbios#xx */
  369.       strcpy(name,name_str);
  370.  
  371.       p = strchr(name,'#');
  372.  
  373.       if (p) {
  374.         *p = 0;
  375.         sscanf(p+1,"%x",&type);
  376.       }
  377.  
  378.       /* decode the netbios flags (hex) and the time-to-die (seconds) */
  379.       sscanf(nb_flags_str,"%x",&nb_flags);
  380.       sscanf(ttd_str,"%ld",&ttd);
  381.  
  382.       ipaddr = *interpret_addr2(ip_str);
  383.  
  384.       if (ip_equal(ipaddr,ipzero)) {
  385.          source = SELF;
  386.       }
  387.       else
  388.       {
  389.          source = REGISTER;
  390.       }
  391.  
  392.       DEBUG(4, ("add WINS line: %s#%02x %ld %s %2x\n",
  393.            name,type, ttd, inet_ntoa(ipaddr), nb_flags));
  394.  
  395.       /* add all entries that have 60 seconds or more to live */
  396.       if (ttd - 60 > time(NULL) || ttd == 0)
  397.       {
  398.         time_t t = (ttd?ttd-time(NULL):0) / 3;
  399.  
  400.         /* add netbios entry read from the wins.dat file. IF it's ok */
  401.         add_netbios_entry(d,name,type,nb_flags,t,source,ipaddr,True,True);
  402.       }
  403.     }
  404.  
  405.   fclose(f);
  406. }
  407.  
  408.  
  409. /****************************************************************************
  410.   remove an entry from the name list
  411.   ****************************************************************************/
  412. void remove_netbios_name(struct subnet_record *d,
  413.             char *name,int type, enum name_source source,
  414.              struct in_addr ip)
  415. {
  416.   struct nmb_name nn;
  417.   struct name_record *n;
  418.  
  419.   make_nmb_name(&nn, name, type, scope);
  420.   n = find_name_search(&d, &nn, FIND_LOCAL, ip);
  421.   
  422.   if (n && n->source == source) remove_name(d,n);
  423. }
  424.  
  425.  
  426. /****************************************************************************
  427.   add an entry to the name list.
  428.  
  429.   this is a multi-purpose function.
  430.  
  431.   it adds samba's own names in to its records on each interface, keeping a
  432.   record of whether it is a master browser, domain master, or WINS server.
  433.  
  434.   it also keeps a record of WINS entries.
  435.  
  436.   ****************************************************************************/
  437. struct name_record *add_netbios_entry(struct subnet_record *d,
  438.         char *name, int type, int nb_flags, 
  439.         int ttl, enum name_source source, struct in_addr ip,
  440.         BOOL new_only,BOOL wins)
  441. {
  442.   struct name_record *n;
  443.   struct name_record *n2=NULL;
  444.   struct subnet_record *found_subnet = 0;
  445.   int search = 0;
  446.   BOOL self = (source == SELF);
  447.  
  448.   /* add the name to the WINS list if the name comes from a directed query */
  449.   search |= wins ? FIND_WINS : FIND_LOCAL;
  450.  
  451.   /* If it's a local search then we need to set the subnet
  452.      we are looking at. */
  453.   if(search & FIND_LOCAL)
  454.     found_subnet = d;
  455.  
  456.   /* search for SELF names only */
  457.   search |= self ? FIND_SELF : 0;
  458.  
  459.   if (!self)
  460.   {
  461.     if (!wins && (type != 0x1b))
  462.     {
  463.        /* the only broadcast (non-WINS) names we are adding are ours
  464.           (SELF) and Domain Master type names */
  465.        return NULL;
  466.     }
  467.     if(wins && (type == 0x1d))
  468.     {
  469.       /* Do not allow any 0x1d names to be registered in a WINS,
  470.          database although we return success for them.
  471.        */
  472.       return NULL;
  473.     }
  474.   }
  475.  
  476.   n = (struct name_record *)malloc(sizeof(*n));
  477.   if (!n) return(NULL);
  478.  
  479.   bzero((char *)n,sizeof(*n));
  480.  
  481.   n->num_ips = 1; /* XXXX ONLY USE THIS FUNCTION FOR ONE ENTRY */
  482.   n->ip_flgs = (struct nmb_ip*)malloc(sizeof(*n->ip_flgs) * n->num_ips);
  483.   if (!n->ip_flgs)
  484.   {
  485.      free(n);
  486.      return NULL;
  487.   }
  488.  
  489.   make_nmb_name(&n->name,name,type,scope);
  490.  
  491.   if ((n2 = find_name_search(&found_subnet, &n->name, search, new_only?ipzero:ip)))
  492.   {
  493.     free(n->ip_flgs);
  494.     free(n);
  495.     if (new_only || (n2->source==SELF && source!=SELF)) return n2;
  496.     n = n2;
  497.     d = found_subnet;
  498.   }
  499.  
  500.   if (ttl)
  501.      n->death_time = time(NULL)+ttl*3;
  502.   n->refresh_time = time(NULL)+GET_TTL(ttl);
  503.  
  504.   /* XXXX only one entry expected with this function */
  505.   n->ip_flgs[0].ip = ip;
  506.   n->ip_flgs[0].nb_flags = nb_flags;
  507.  
  508.   n->source = source;
  509.   
  510.   if (!n2) add_name(d,n);
  511.  
  512.   DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x to interface %s\n",
  513.        namestr(&n->name),inet_ntoa(ip),ttl,nb_flags,
  514.        ip_equal(d->bcast_ip, wins_ip) ? "WINS" : (char *)inet_ntoa(d->bcast_ip)));
  515.  
  516.   return(n);
  517. }
  518.  
  519.  
  520. /*******************************************************************
  521.   expires old names in the namelist
  522.   ******************************************************************/
  523. void expire_names(time_t t)
  524. {
  525.   struct name_record *n;
  526.   struct name_record *next;
  527.   struct subnet_record *d;
  528.  
  529.   /* expire old names */
  530.   for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
  531.   {
  532.     for (n = d->namelist; n; n = next)
  533.     {
  534.       next = n->next;
  535.       if (n->death_time && n->death_time < t)
  536.       {
  537.         if (n->source == SELF) 
  538.         {
  539.           DEBUG(3,("not expiring SELF name %s\n", namestr(&n->name)));
  540.                     n->death_time += 300;
  541.           continue;
  542.         }
  543.         DEBUG(3,("Removing dead name %s\n", namestr(&n->name)));
  544.           
  545.         if (n->prev) n->prev->next = n->next;
  546.         if (n->next) n->next->prev = n->prev;
  547.           
  548.         if (d->namelist == n) d->namelist = n->next; 
  549.           
  550.         if(n->ip_flgs != NULL)
  551.           free(n->ip_flgs);
  552.         free(n);
  553.       }
  554.     }
  555.   }
  556. }
  557.  
  558.  
  559. /***************************************************************************
  560.   assume a WINS name is a dns name, and do a gethostbyname() on it.
  561.   ****************************************************************************/
  562. struct name_record *dns_name_search(struct nmb_name *question, int Time)
  563. {
  564.   int name_type = question->name_type;
  565.   char *qname = question->name;
  566.   BOOL dns_type = (name_type == 0x20 || name_type == 0);
  567.   struct in_addr dns_ip;
  568.  
  569.   if (wins_subnet == NULL) 
  570.     return NULL;
  571.  
  572.   DEBUG(3,("Search for %s - ", namestr(question)));
  573.  
  574.   /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
  575.   if (!dns_type)
  576.   {
  577.     DEBUG(3,("types 0x20 0x0 only: name not found\n"));
  578.     return NULL;
  579.   }
  580.  
  581.   /* look it up with DNS */      
  582.   dns_ip.s_addr = interpret_addr(qname);
  583.  
  584.   if (!dns_ip.s_addr)
  585.   {
  586.     /* no luck with DNS. We could possibly recurse here XXXX */
  587.     DEBUG(3,("not found. no recursion.\n"));
  588.     /* add the fail to WINS cache of names. give it 1 hour in the cache */
  589.     add_netbios_entry(wins_subnet,qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip,
  590.                   True, True);
  591.     return NULL;
  592.   }
  593.  
  594.   DEBUG(3,("found with DNS: %s\n", inet_ntoa(dns_ip)));
  595.  
  596.   /* add it to our WINS cache of names. give it 2 hours in the cache */
  597.   return add_netbios_entry(wins_subnet,qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip,
  598.                          True,True);
  599. }
  600.