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

Generated by: LCOV version 1.14