~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/nmbd/nmbd_synclists.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 2 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, write to the Free Software
20
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
 
   
22
 
*/
23
 
 
24
 
/* this file handles asynchronous browse synchronisation requests. The
25
 
   requests are done by forking and putting the result in a file in the
26
 
   locks directory. We do it this way because we don't want nmbd to be
27
 
   blocked waiting for some server to respond on a TCP connection. This
28
 
   also allows us to have more than 1 sync going at once (tridge) */
29
 
 
30
 
#include "includes.h"
31
 
 
32
 
extern fstring local_machine;
33
 
 
34
 
struct sync_record {
35
 
        struct sync_record *next, *prev;
36
 
        unstring workgroup;
37
 
        unstring server;
38
 
        pstring fname;
39
 
        struct in_addr ip;
40
 
        pid_t pid;
41
 
};
42
 
 
43
 
/* a linked list of current sync connections */
44
 
static struct sync_record *syncs;
45
 
 
46
 
static XFILE *fp;
47
 
 
48
 
/*******************************************************************
49
 
  This is the NetServerEnum callback.
50
 
  Note sname and comment are in UNIX codepage format.
51
 
  ******************************************************************/
52
 
 
53
 
static void callback(const char *sname, uint32 stype, 
54
 
                     const char *comment, void *state)
55
 
{
56
 
        x_fprintf(fp,"\"%s\" %08X \"%s\"\n", sname, stype, comment);
57
 
}
58
 
 
59
 
/*******************************************************************
60
 
  Synchronise browse lists with another browse server.
61
 
  Log in on the remote server's SMB port to their IPC$ service,
62
 
  do a NetServerEnum and record the results in fname
63
 
******************************************************************/
64
 
 
65
 
static void sync_child(char *name, int nm_type, 
66
 
                       char *workgroup,
67
 
                       struct in_addr ip, BOOL local, BOOL servers,
68
 
                       char *fname)
69
 
{
70
 
        fstring unix_workgroup;
71
 
        struct cli_state *cli;
72
 
        uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
73
 
        struct nmb_name called, calling;
74
 
 
75
 
        /* W2K DMB's return empty browse lists on port 445. Use 139.
76
 
         * Patch from Andy Levine andyl@epicrealm.com.
77
 
         */
78
 
 
79
 
        cli = cli_initialise();
80
 
        if (!cli) {
81
 
                return;
82
 
        }
83
 
 
84
 
        if (!cli_set_port(cli, 139) || !cli_connect(cli, name, &ip)) {
85
 
                return;
86
 
        }
87
 
 
88
 
        make_nmb_name(&calling, local_machine, 0x0);
89
 
        make_nmb_name(&called , name, nm_type);
90
 
 
91
 
        if (!cli_session_request(cli, &calling, &called)) {
92
 
                cli_shutdown(cli);
93
 
                return;
94
 
        }
95
 
 
96
 
        if (!cli_negprot(cli)) {
97
 
                cli_shutdown(cli);
98
 
                return;
99
 
        }
100
 
 
101
 
        if (!cli_session_setup(cli, "", "", 1, "", 0, workgroup)) {
102
 
                cli_shutdown(cli);
103
 
                return;
104
 
        }
105
 
 
106
 
        if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
107
 
                cli_shutdown(cli);
108
 
                return;
109
 
        }
110
 
 
111
 
        /* All the cli_XX functions take UNIX character set. */
112
 
        fstrcpy(unix_workgroup, cli->server_domain ? cli->server_domain : workgroup);
113
 
 
114
 
        /* Fetch a workgroup list. */
115
 
        cli_NetServerEnum(cli, unix_workgroup,
116
 
                          local_type|SV_TYPE_DOMAIN_ENUM, 
117
 
                          callback, NULL);
118
 
        
119
 
        /* Now fetch a server list. */
120
 
        if (servers) {
121
 
                fstrcpy(unix_workgroup, workgroup);
122
 
                cli_NetServerEnum(cli, unix_workgroup, 
123
 
                                  local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
124
 
                                  callback, NULL);
125
 
        }
126
 
        
127
 
        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
 
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
 
 
143
 
        START_PROFILE(sync_browse_lists);
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
 
        if (ismyip(ip)) {
147
 
done:
148
 
                END_PROFILE(sync_browse_lists);
149
 
                return;
150
 
        }
151
 
 
152
 
        s = SMB_MALLOC_P(struct sync_record);
153
 
        if (!s) goto done;
154
 
 
155
 
        ZERO_STRUCTP(s);
156
 
        
157
 
        unstrcpy(s->workgroup, work->work_group);
158
 
        unstrcpy(s->server, name);
159
 
        s->ip = ip;
160
 
 
161
 
        slprintf(s->fname, sizeof(pstring)-1,
162
 
                 "%s/sync.%d", lp_lockdir(), counter++);
163
 
        all_string_sub(s->fname,"//", "/", 0);
164
 
        
165
 
        DLIST_ADD(syncs, s);
166
 
 
167
 
        /* the parent forks and returns, leaving the child to do the
168
 
           actual sync and call END_PROFILE*/
169
 
        CatchChild();
170
 
        if ((s->pid = sys_fork())) return;
171
 
 
172
 
        BlockSignals( False, SIGTERM );
173
 
 
174
 
        DEBUG(2,("Initiating browse sync for %s to %s(%s)\n",
175
 
                 work->work_group, name, inet_ntoa(ip)));
176
 
 
177
 
        fp = x_fopen(s->fname,O_WRONLY|O_CREAT|O_TRUNC, 0644);
178
 
        if (!fp) {
179
 
                END_PROFILE(sync_browse_lists);
180
 
                _exit(1);       
181
 
        }
182
 
 
183
 
        sync_child(name, nm_type, work->work_group, ip, local, servers,
184
 
                   s->fname);
185
 
 
186
 
        x_fclose(fp);
187
 
        END_PROFILE(sync_browse_lists);
188
 
        _exit(0);
189
 
}
190
 
 
191
 
/**********************************************************************
192
 
 Handle one line from a completed sync file.
193
 
 **********************************************************************/
194
 
 
195
 
static void complete_one(struct sync_record *s, 
196
 
                         char *sname, uint32 stype, char *comment)
197
 
{
198
 
        struct work_record *work;
199
 
        struct server_record *servrec;
200
 
 
201
 
        stype &= ~SV_TYPE_LOCAL_LIST_ONLY;
202
 
 
203
 
        if (stype & SV_TYPE_DOMAIN_ENUM) {
204
 
                /* See if we can find the workgroup on this subnet. */
205
 
                if((work=find_workgroup_on_subnet(unicast_subnet, sname))) {
206
 
                        /* We already know about this workgroup -
207
 
                           update the ttl. */
208
 
                        update_workgroup_ttl(work,lp_max_ttl());
209
 
                } else {
210
 
                        /* Create the workgroup on the subnet. */
211
 
                        work = create_workgroup_on_subnet(unicast_subnet, 
212
 
                                                          sname, lp_max_ttl());
213
 
                        if (work) {
214
 
                                /* remember who the master is */
215
 
                                unstrcpy(work->local_master_browser_name, comment);
216
 
                        }
217
 
                }
218
 
                return;
219
 
        } 
220
 
 
221
 
        work = find_workgroup_on_subnet(unicast_subnet, s->workgroup);
222
 
        if (!work) {
223
 
                DEBUG(3,("workgroup %s doesn't exist on unicast subnet?\n",
224
 
                         s->workgroup));
225
 
                return;
226
 
        }
227
 
 
228
 
        if ((servrec = find_server_in_workgroup( work, sname))) {
229
 
                /* Check that this is not a locally known
230
 
                   server - if so ignore the entry. */
231
 
                if(!(servrec->serv.type & SV_TYPE_LOCAL_LIST_ONLY)) {
232
 
                        /* We already know about this server - update
233
 
                           the ttl. */
234
 
                        update_server_ttl(servrec, lp_max_ttl());
235
 
                        /* Update the type. */
236
 
                        servrec->serv.type = stype;
237
 
                }
238
 
                return;
239
 
        } 
240
 
 
241
 
        /* Create the server in the workgroup. */ 
242
 
        create_server_on_workgroup(work, sname,stype, lp_max_ttl(), comment);
243
 
}
244
 
                
245
 
/**********************************************************************
246
 
 Read the completed sync info.
247
 
**********************************************************************/
248
 
 
249
 
static void complete_sync(struct sync_record *s)
250
 
{
251
 
        XFILE *f;
252
 
        unstring server, type_str;
253
 
        unsigned type;
254
 
        pstring comment;
255
 
        pstring line;
256
 
        const char *ptr;
257
 
        int count=0;
258
 
 
259
 
        f = x_fopen(s->fname,O_RDONLY, 0);
260
 
 
261
 
        if (!f)
262
 
                return;
263
 
        
264
 
        while (!x_feof(f)) {
265
 
                
266
 
                if (!fgets_slash(line,sizeof(pstring),f))
267
 
                        continue;
268
 
                
269
 
                ptr = line;
270
 
 
271
 
                if (!next_token(&ptr,server,NULL,sizeof(server)) ||
272
 
                    !next_token(&ptr,type_str,NULL, sizeof(type_str)) ||
273
 
                    !next_token(&ptr,comment,NULL, sizeof(comment))) {
274
 
                        continue;
275
 
                }
276
 
 
277
 
                sscanf(type_str, "%X", &type);
278
 
 
279
 
                complete_one(s, server, type, comment);
280
 
 
281
 
                count++;
282
 
        }
283
 
 
284
 
        x_fclose(f);
285
 
 
286
 
        unlink(s->fname);
287
 
 
288
 
        DEBUG(2,("sync with %s(%s) for workgroup %s completed (%d records)\n",
289
 
                 s->server, inet_ntoa(s->ip), s->workgroup, count));
290
 
}
291
 
 
292
 
/**********************************************************************
293
 
 Check for completion of any of the child processes.
294
 
**********************************************************************/
295
 
 
296
 
void sync_check_completion(void)
297
 
{
298
 
        struct sync_record *s, *next;
299
 
 
300
 
        for (s=syncs;s;s=next) {
301
 
                next = s->next;
302
 
                if (!process_exists_by_pid(s->pid)) {
303
 
                        /* it has completed - grab the info */
304
 
                        complete_sync(s);
305
 
                        DLIST_REMOVE(syncs, s);
306
 
                        ZERO_STRUCTP(s);
307
 
                        SAFE_FREE(s);
308
 
                }
309
 
        }
310
 
}