LCOV - code coverage report
Current view: top level - source3/nmbd - nmbd_synclists.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 3 107 2.8 %
Date: 2024-04-21 15:09:00 Functions: 1 6 16.7 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    NBT netbios routines and daemon - version 2
       4             :    Copyright (C) Andrew Tridgell 1994-1998
       5             :    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
       6             :    Copyright (C) Jeremy Allison 1994-1998
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : /* this file handles asynchronous browse synchronisation requests. The
      23             :    requests are done by forking and putting the result in a file in the
      24             :    locks directory. We do it this way because we don't want nmbd to be
      25             :    blocked waiting for some server to respond on a TCP connection. This
      26             :    also allows us to have more than 1 sync going at once (tridge) */
      27             : 
      28             : #include "includes.h"
      29             : #include "system/filesys.h"
      30             : #include "../librpc/gen_ndr/svcctl.h"
      31             : #include "nmbd/nmbd.h"
      32             : #include "libsmb/libsmb.h"
      33             : #include "libsmb/clirap.h"
      34             : #include "../libcli/smb/smbXcli_base.h"
      35             : #include "lib/util/string_wrappers.h"
      36             : #include "lib/util/util_file.h"
      37             : #include "source3/lib/substitute.h"
      38             : 
      39             : struct sync_record {
      40             :         struct sync_record *next, *prev;
      41             :         unstring workgroup;
      42             :         unstring server;
      43             :         char *fname;
      44             :         struct in_addr ip;
      45             :         pid_t pid;
      46             : };
      47             : 
      48             : /* a linked list of current sync connections */
      49             : static struct sync_record *syncs;
      50             : 
      51             : static FILE *fp;
      52             : 
      53             : /*******************************************************************
      54             :   This is the NetServerEnum callback.
      55             :   Note sname and comment are in UNIX codepage format.
      56             :   ******************************************************************/
      57             : 
      58           0 : static void callback(const char *sname, uint32_t stype,
      59             :                      const char *comment, void *state)
      60             : {
      61           0 :         fprintf(fp,"\"%s\" %08X \"%s\"\n", sname, stype, comment);
      62           0 : }
      63             : 
      64             : /*******************************************************************
      65             :   Synchronise browse lists with another browse server.
      66             :   Log in on the remote server's SMB port to their IPC$ service,
      67             :   do a NetServerEnum and record the results in fname
      68             : ******************************************************************/
      69             : 
      70           0 : static void sync_child(char *name, int nm_type, 
      71             :                        char *workgroup,
      72             :                        struct in_addr ip, bool local, bool servers,
      73             :                        char *fname)
      74             : {
      75             :         fstring unix_workgroup;
      76             :         struct cli_state *cli;
      77           0 :         uint32_t local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
      78             :         struct sockaddr_storage ss;
      79             :         NTSTATUS status;
      80             : 
      81             :         /* W2K DMB's return empty browse lists on port 445. Use 139.
      82             :          * Patch from Andy Levine andyl@epicrealm.com.
      83             :          */
      84             : 
      85           0 :         in_addr_to_sockaddr_storage(&ss, ip);
      86             : 
      87           0 :         status = cli_connect_nb(name, &ss, NBT_SMB_PORT, nm_type,
      88             :                                 get_local_machine_name(), SMB_SIGNING_DEFAULT,
      89             :                                 0, &cli);
      90           0 :         if (!NT_STATUS_IS_OK(status)) {
      91           0 :                 return;
      92             :         }
      93             : 
      94           0 :         status = smbXcli_negprot(cli->conn,
      95           0 :                                  cli->timeout,
      96             :                                  PROTOCOL_CORE,
      97             :                                  PROTOCOL_NT1,
      98             :                                  NULL,
      99             :                                  NULL,
     100             :                                  NULL);
     101           0 :         if (!NT_STATUS_IS_OK(status)) {
     102           0 :                 cli_shutdown(cli);
     103           0 :                 return;
     104             :         }
     105             : 
     106           0 :         status = cli_session_setup_anon(cli);
     107           0 :         if (!NT_STATUS_IS_OK(status)) {
     108           0 :                 cli_shutdown(cli);
     109           0 :                 return;
     110             :         }
     111             : 
     112           0 :         if (!NT_STATUS_IS_OK(cli_tree_connect(cli, "IPC$", "IPC", NULL))) {
     113           0 :                 cli_shutdown(cli);
     114           0 :                 return;
     115             :         }
     116             : 
     117             :         /* All the cli_XX functions take UNIX character set. */
     118           0 :         fstrcpy(unix_workgroup, cli->server_domain ? cli->server_domain : workgroup);
     119             : 
     120             :         /* Fetch a workgroup list. */
     121           0 :         cli_NetServerEnum(cli, unix_workgroup,
     122             :                           local_type|SV_TYPE_DOMAIN_ENUM, 
     123             :                           callback, NULL);
     124             : 
     125             :         /* Now fetch a server list. */
     126           0 :         if (servers) {
     127           0 :                 fstrcpy(unix_workgroup, workgroup);
     128           0 :                 cli_NetServerEnum(cli, unix_workgroup, 
     129             :                                   local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
     130             :                                   callback, NULL);
     131             :         }
     132             : 
     133           0 :         cli_shutdown(cli);
     134             : }
     135             : 
     136             : /*******************************************************************
     137             :   initialise a browse sync with another browse server.  Log in on the
     138             :   remote server's SMB port to their IPC$ service, do a NetServerEnum
     139             :   and record the results
     140             : ******************************************************************/
     141             : 
     142           0 : void sync_browse_lists(struct work_record *work,
     143             :                        char *name, int nm_type, 
     144             :                        struct in_addr ip, bool local, bool servers)
     145             : {
     146             :         struct sync_record *s;
     147             :         static int counter;
     148             :         int fd;
     149             : 
     150             :         /* Check we're not trying to sync with ourselves. This can
     151             :            happen if we are a domain *and* a local master browser. */
     152           0 :         if (ismyip_v4(ip)) {
     153           0 : done:
     154           0 :                 return;
     155             :         }
     156             : 
     157           0 :         s = SMB_MALLOC_P(struct sync_record);
     158           0 :         if (!s) goto done;
     159             : 
     160           0 :         ZERO_STRUCTP(s);
     161             : 
     162           0 :         unstrcpy(s->workgroup, work->work_group);
     163           0 :         unstrcpy(s->server, name);
     164           0 :         s->ip = ip;
     165             : 
     166           0 :         if (asprintf(&s->fname, "%s/sync.%d", lp_lock_directory(), counter++) < 0) {
     167           0 :                 SAFE_FREE(s);
     168           0 :                 goto done;
     169             :         }
     170             :         /* Safe to use as 0 means no size change. */
     171           0 :         all_string_sub(s->fname,"//", "/", 0);
     172             : 
     173           0 :         DLIST_ADD(syncs, s);
     174             : 
     175             :         /* the parent forks and returns, leaving the child to do the
     176             :            actual sync */
     177           0 :         CatchChild();
     178           0 :         if ((s->pid = fork())) return;
     179             : 
     180           0 :         BlockSignals( False, SIGTERM );
     181             : 
     182           0 :         DEBUG(2,("Initiating browse sync for %s to %s(%s)\n",
     183             :                  work->work_group, name, inet_ntoa(ip)));
     184             : 
     185           0 :         fd = open(s->fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
     186           0 :         if (fd == -1) {
     187           0 :                 _exit(1);
     188             :         }
     189             : 
     190           0 :         fp = fdopen(fd, "w");
     191           0 :         if (!fp) {
     192           0 :                 _exit(1);
     193             :         }
     194           0 :         fd = -1;
     195             : 
     196           0 :         sync_child(name, nm_type, work->work_group, ip, local, servers,
     197             :                    s->fname);
     198             : 
     199           0 :         fclose(fp);
     200           0 :         _exit(0);
     201             : }
     202             : 
     203             : /**********************************************************************
     204             :  Handle one line from a completed sync file.
     205             :  **********************************************************************/
     206             : 
     207           0 : static void complete_one(struct sync_record *s,
     208             :                          char *sname, uint32_t stype, char *comment)
     209             : {
     210             :         struct work_record *work;
     211             :         struct server_record *servrec;
     212             : 
     213           0 :         stype &= ~SV_TYPE_LOCAL_LIST_ONLY;
     214             : 
     215           0 :         if (stype & SV_TYPE_DOMAIN_ENUM) {
     216             :                 /* See if we can find the workgroup on this subnet. */
     217           0 :                 if((work=find_workgroup_on_subnet(unicast_subnet, sname))) {
     218             :                         /* We already know about this workgroup -
     219             :                            update the ttl. */
     220           0 :                         update_workgroup_ttl(work,lp_max_ttl());
     221             :                 } else {
     222             :                         /* Create the workgroup on the subnet. */
     223           0 :                         work = create_workgroup_on_subnet(unicast_subnet, 
     224             :                                                           sname, lp_max_ttl());
     225           0 :                         if (work) {
     226             :                                 /* remember who the master is */
     227           0 :                                 unstrcpy(work->local_master_browser_name, comment);
     228             :                         }
     229             :                 }
     230           0 :                 return;
     231             :         } 
     232             : 
     233           0 :         work = find_workgroup_on_subnet(unicast_subnet, s->workgroup);
     234           0 :         if (!work) {
     235           0 :                 DEBUG(3,("workgroup %s doesn't exist on unicast subnet?\n",
     236             :                          s->workgroup));
     237           0 :                 return;
     238             :         }
     239             : 
     240           0 :         if ((servrec = find_server_in_workgroup( work, sname))) {
     241             :                 /* Check that this is not a locally known
     242             :                    server - if so ignore the entry. */
     243           0 :                 if(!(servrec->serv.type & SV_TYPE_LOCAL_LIST_ONLY)) {
     244             :                         /* We already know about this server - update
     245             :                            the ttl. */
     246           0 :                         update_server_ttl(servrec, lp_max_ttl());
     247             :                         /* Update the type. */
     248           0 :                         servrec->serv.type = stype;
     249             :                 }
     250           0 :                 return;
     251             :         } 
     252             : 
     253             :         /* Create the server in the workgroup. */ 
     254           0 :         create_server_on_workgroup(work, sname,stype, lp_max_ttl(), comment);
     255             : }
     256             : 
     257             : /**********************************************************************
     258             :  Read the completed sync info.
     259             : **********************************************************************/
     260             : 
     261           0 : static void complete_sync(struct sync_record *s)
     262             : {
     263             :         FILE *f;
     264             :         char *server;
     265             :         char *type_str;
     266             :         unsigned type;
     267             :         char *comment;
     268             :         char line[1024];
     269             :         const char *ptr;
     270           0 :         int count=0;
     271             : 
     272           0 :         f = fopen(s->fname, "r");
     273             : 
     274           0 :         if (!f)
     275           0 :                 return;
     276             : 
     277           0 :         while (!feof(f)) {
     278           0 :                 TALLOC_CTX *frame = NULL;
     279             : 
     280           0 :                 if (!fgets_slash(NULL, line, sizeof(line), f))
     281           0 :                         continue;
     282             : 
     283           0 :                 ptr = line;
     284             : 
     285           0 :                 frame = talloc_stackframe();
     286           0 :                 if (!next_token_talloc(frame,&ptr,&server,NULL) ||
     287           0 :                     !next_token_talloc(frame,&ptr,&type_str,NULL) ||
     288           0 :                     !next_token_talloc(frame,&ptr,&comment,NULL)) {
     289           0 :                         TALLOC_FREE(frame);
     290           0 :                         continue;
     291             :                 }
     292             : 
     293           0 :                 sscanf(type_str, "%X", &type);
     294             : 
     295           0 :                 complete_one(s, server, type, comment);
     296             : 
     297           0 :                 count++;
     298           0 :                 TALLOC_FREE(frame);
     299             :         }
     300           0 :         fclose(f);
     301             : 
     302           0 :         unlink(s->fname);
     303             : 
     304           0 :         DEBUG(2,("sync with %s(%s) for workgroup %s completed (%d records)\n",
     305             :                  s->server, inet_ntoa(s->ip), s->workgroup, count));
     306             : }
     307             : 
     308             : /**********************************************************************
     309             :  Check for completion of any of the child processes.
     310             : **********************************************************************/
     311             : 
     312       17145 : void sync_check_completion(void)
     313             : {
     314             :         struct sync_record *s, *next;
     315             : 
     316       17145 :         for (s=syncs;s;s=next) {
     317           0 :                 next = s->next;
     318           0 :                 if (!process_exists_by_pid(s->pid)) {
     319             :                         /* it has completed - grab the info */
     320           0 :                         complete_sync(s);
     321           0 :                         DLIST_REMOVE(syncs, s);
     322           0 :                         SAFE_FREE(s->fname);
     323           0 :                         SAFE_FREE(s);
     324             :                 }
     325             :         }
     326       17145 : }

Generated by: LCOV version 1.14