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

Generated by: LCOV version 1.14