LCOV - code coverage report
Current view: top level - source3/nmbd - nmbd_synclists.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 3 106 2.8 %
Date: 2024-06-13 04:01:37 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 "source3/lib/substitute.h"
      37             : 
      38             : struct sync_record {
      39             :         struct sync_record *next, *prev;
      40             :         unstring workgroup;
      41             :         unstring server;
      42             :         char *fname;
      43             :         struct in_addr ip;
      44             :         pid_t pid;
      45             : };
      46             : 
      47             : /* a linked list of current sync connections */
      48             : static struct sync_record *syncs;
      49             : 
      50             : static FILE *fp;
      51             : 
      52             : /*******************************************************************
      53             :   This is the NetServerEnum callback.
      54             :   Note sname and comment are in UNIX codepage format.
      55             :   ******************************************************************/
      56             : 
      57           0 : static void callback(const char *sname, uint32_t stype,
      58             :                      const char *comment, void *state)
      59             : {
      60           0 :         fprintf(fp,"\"%s\" %08X \"%s\"\n", sname, stype, comment);
      61           0 : }
      62             : 
      63             : /*******************************************************************
      64             :   Synchronise browse lists with another browse server.
      65             :   Log in on the remote server's SMB port to their IPC$ service,
      66             :   do a NetServerEnum and record the results in fname
      67             : ******************************************************************/
      68             : 
      69           0 : static void sync_child(char *name, int nm_type, 
      70             :                        char *workgroup,
      71             :                        struct in_addr ip, bool local, bool servers,
      72             :                        char *fname)
      73             : {
      74             :         fstring unix_workgroup;
      75             :         struct cli_state *cli;
      76           0 :         uint32_t local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
      77             :         struct sockaddr_storage ss;
      78             :         NTSTATUS status;
      79             : 
      80             :         /* W2K DMB's return empty browse lists on port 445. Use 139.
      81             :          * Patch from Andy Levine andyl@epicrealm.com.
      82             :          */
      83             : 
      84           0 :         in_addr_to_sockaddr_storage(&ss, ip);
      85             : 
      86           0 :         status = cli_connect_nb(name, &ss, NBT_SMB_PORT, nm_type,
      87             :                                 get_local_machine_name(), SMB_SIGNING_DEFAULT,
      88             :                                 0, &cli);
      89           0 :         if (!NT_STATUS_IS_OK(status)) {
      90           0 :                 return;
      91             :         }
      92             : 
      93           0 :         status = smbXcli_negprot(cli->conn, cli->timeout, PROTOCOL_CORE,
      94             :                                  PROTOCOL_NT1);
      95           0 :         if (!NT_STATUS_IS_OK(status)) {
      96           0 :                 cli_shutdown(cli);
      97           0 :                 return;
      98             :         }
      99             : 
     100           0 :         status = cli_session_setup_anon(cli);
     101           0 :         if (!NT_STATUS_IS_OK(status)) {
     102           0 :                 cli_shutdown(cli);
     103           0 :                 return;
     104             :         }
     105             : 
     106           0 :         if (!NT_STATUS_IS_OK(cli_tree_connect(cli, "IPC$", "IPC", NULL))) {
     107           0 :                 cli_shutdown(cli);
     108           0 :                 return;
     109             :         }
     110             : 
     111             :         /* All the cli_XX functions take UNIX character set. */
     112           0 :         fstrcpy(unix_workgroup, cli->server_domain ? cli->server_domain : workgroup);
     113             : 
     114             :         /* Fetch a workgroup list. */
     115           0 :         cli_NetServerEnum(cli, unix_workgroup,
     116             :                           local_type|SV_TYPE_DOMAIN_ENUM, 
     117             :                           callback, NULL);
     118             : 
     119             :         /* Now fetch a server list. */
     120           0 :         if (servers) {
     121           0 :                 fstrcpy(unix_workgroup, workgroup);
     122           0 :                 cli_NetServerEnum(cli, unix_workgroup, 
     123             :                                   local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
     124             :                                   callback, NULL);
     125             :         }
     126             : 
     127           0 :         cli_shutdown(cli);
     128             : }
     129             : 
     130             : /*******************************************************************
     131             :   initialise a browse sync with another browse server.  Log in on the
     132             :   remote server's SMB port to their IPC$ service, do a NetServerEnum
     133             :   and record the results
     134             : ******************************************************************/
     135             : 
     136           0 : void sync_browse_lists(struct work_record *work,
     137             :                        char *name, int nm_type, 
     138             :                        struct in_addr ip, bool local, bool servers)
     139             : {
     140             :         struct sync_record *s;
     141             :         static int counter;
     142             :         int fd;
     143             : 
     144             :         /* Check we're not trying to sync with ourselves. This can
     145             :            happen if we are a domain *and* a local master browser. */
     146           0 :         if (ismyip_v4(ip)) {
     147           0 : done:
     148           0 :                 return;
     149             :         }
     150             : 
     151           0 :         s = SMB_MALLOC_P(struct sync_record);
     152           0 :         if (!s) goto done;
     153             : 
     154           0 :         ZERO_STRUCTP(s);
     155             : 
     156           0 :         unstrcpy(s->workgroup, work->work_group);
     157           0 :         unstrcpy(s->server, name);
     158           0 :         s->ip = ip;
     159             : 
     160           0 :         if (asprintf(&s->fname, "%s/sync.%d", lp_lock_directory(), counter++) < 0) {
     161           0 :                 SAFE_FREE(s);
     162           0 :                 goto done;
     163             :         }
     164             :         /* Safe to use as 0 means no size change. */
     165           0 :         all_string_sub(s->fname,"//", "/", 0);
     166             : 
     167           0 :         DLIST_ADD(syncs, s);
     168             : 
     169             :         /* the parent forks and returns, leaving the child to do the
     170             :            actual sync */
     171           0 :         CatchChild();
     172           0 :         if ((s->pid = fork())) return;
     173             : 
     174           0 :         BlockSignals( False, SIGTERM );
     175             : 
     176           0 :         DEBUG(2,("Initiating browse sync for %s to %s(%s)\n",
     177             :                  work->work_group, name, inet_ntoa(ip)));
     178             : 
     179           0 :         fd = open(s->fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
     180           0 :         if (fd == -1) {
     181           0 :                 _exit(1);
     182             :         }
     183             : 
     184           0 :         fp = fdopen(fd, "w");
     185           0 :         if (!fp) {
     186           0 :                 _exit(1);
     187             :         }
     188           0 :         fd = -1;
     189             : 
     190           0 :         sync_child(name, nm_type, work->work_group, ip, local, servers,
     191             :                    s->fname);
     192             : 
     193           0 :         fclose(fp);
     194           0 :         _exit(0);
     195             : }
     196             : 
     197             : /**********************************************************************
     198             :  Handle one line from a completed sync file.
     199             :  **********************************************************************/
     200             : 
     201           0 : static void complete_one(struct sync_record *s,
     202             :                          char *sname, uint32_t stype, char *comment)
     203             : {
     204             :         struct work_record *work;
     205             :         struct server_record *servrec;
     206             : 
     207           0 :         stype &= ~SV_TYPE_LOCAL_LIST_ONLY;
     208             : 
     209           0 :         if (stype & SV_TYPE_DOMAIN_ENUM) {
     210             :                 /* See if we can find the workgroup on this subnet. */
     211           0 :                 if((work=find_workgroup_on_subnet(unicast_subnet, sname))) {
     212             :                         /* We already know about this workgroup -
     213             :                            update the ttl. */
     214           0 :                         update_workgroup_ttl(work,lp_max_ttl());
     215             :                 } else {
     216             :                         /* Create the workgroup on the subnet. */
     217           0 :                         work = create_workgroup_on_subnet(unicast_subnet, 
     218             :                                                           sname, lp_max_ttl());
     219           0 :                         if (work) {
     220             :                                 /* remember who the master is */
     221           0 :                                 unstrcpy(work->local_master_browser_name, comment);
     222             :                         }
     223             :                 }
     224           0 :                 return;
     225             :         } 
     226             : 
     227           0 :         work = find_workgroup_on_subnet(unicast_subnet, s->workgroup);
     228           0 :         if (!work) {
     229           0 :                 DEBUG(3,("workgroup %s doesn't exist on unicast subnet?\n",
     230             :                          s->workgroup));
     231           0 :                 return;
     232             :         }
     233             : 
     234           0 :         if ((servrec = find_server_in_workgroup( work, sname))) {
     235             :                 /* Check that this is not a locally known
     236             :                    server - if so ignore the entry. */
     237           0 :                 if(!(servrec->serv.type & SV_TYPE_LOCAL_LIST_ONLY)) {
     238             :                         /* We already know about this server - update
     239             :                            the ttl. */
     240           0 :                         update_server_ttl(servrec, lp_max_ttl());
     241             :                         /* Update the type. */
     242           0 :                         servrec->serv.type = stype;
     243             :                 }
     244           0 :                 return;
     245             :         } 
     246             : 
     247             :         /* Create the server in the workgroup. */ 
     248           0 :         create_server_on_workgroup(work, sname,stype, lp_max_ttl(), comment);
     249             : }
     250             : 
     251             : /**********************************************************************
     252             :  Read the completed sync info.
     253             : **********************************************************************/
     254             : 
     255           0 : static void complete_sync(struct sync_record *s)
     256             : {
     257             :         FILE *f;
     258             :         char *server;
     259             :         char *type_str;
     260             :         unsigned type;
     261             :         char *comment;
     262             :         char line[1024];
     263             :         const char *ptr;
     264           0 :         int count=0;
     265             : 
     266           0 :         f = fopen(s->fname, "r");
     267             : 
     268           0 :         if (!f)
     269           0 :                 return;
     270             : 
     271           0 :         while (!feof(f)) {
     272           0 :                 TALLOC_CTX *frame = NULL;
     273             : 
     274           0 :                 if (!fgets_slash(NULL, line, sizeof(line), f))
     275           0 :                         continue;
     276             : 
     277           0 :                 ptr = line;
     278             : 
     279           0 :                 frame = talloc_stackframe();
     280           0 :                 if (!next_token_talloc(frame,&ptr,&server,NULL) ||
     281           0 :                     !next_token_talloc(frame,&ptr,&type_str,NULL) ||
     282           0 :                     !next_token_talloc(frame,&ptr,&comment,NULL)) {
     283           0 :                         TALLOC_FREE(frame);
     284           0 :                         continue;
     285             :                 }
     286             : 
     287           0 :                 sscanf(type_str, "%X", &type);
     288             : 
     289           0 :                 complete_one(s, server, type, comment);
     290             : 
     291           0 :                 count++;
     292           0 :                 TALLOC_FREE(frame);
     293             :         }
     294           0 :         fclose(f);
     295             : 
     296           0 :         unlink(s->fname);
     297             : 
     298           0 :         DEBUG(2,("sync with %s(%s) for workgroup %s completed (%d records)\n",
     299             :                  s->server, inet_ntoa(s->ip), s->workgroup, count));
     300             : }
     301             : 
     302             : /**********************************************************************
     303             :  Check for completion of any of the child processes.
     304             : **********************************************************************/
     305             : 
     306        5884 : void sync_check_completion(void)
     307             : {
     308             :         struct sync_record *s, *next;
     309             : 
     310        5884 :         for (s=syncs;s;s=next) {
     311           0 :                 next = s->next;
     312           0 :                 if (!process_exists_by_pid(s->pid)) {
     313             :                         /* it has completed - grab the info */
     314           0 :                         complete_sync(s);
     315           0 :                         DLIST_REMOVE(syncs, s);
     316           0 :                         SAFE_FREE(s->fname);
     317           0 :                         SAFE_FREE(s);
     318             :                 }
     319             :         }
     320        5884 : }

Generated by: LCOV version 1.13