1/* 2 Unix SMB/Netbios implementation. 3 Version 1.9. 4 NBT netbios routines and daemon - version 2 5 Copyright (C) Andrew Tridgell 1994-1998 6 Copyright (C) Luke Kenneth Casson Leighton 1994-1998 7 Copyright (C) Jeremy Allison 1994-1998 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 23*/ 24 25/* this file handles asynchronous browse synchronisation requests. The 26 requests are done by forking and putting the result in a file in the 27 locks directory. We do it this way because we don't want nmbd to be 28 blocked waiting for some server to respond on a TCP connection. This 29 also allows us to have more than 1 sync going at once (tridge) */ 30 31#include "includes.h" 32#include "smb.h" 33 34extern int DEBUGLEVEL; 35 36struct sync_record { 37 struct sync_record *next, *prev; 38 fstring workgroup; 39 fstring server; 40 pstring fname; 41 struct in_addr ip; 42 pid_t pid; 43}; 44 45/* a linked list of current sync connections */ 46static struct sync_record *syncs; 47 48static FILE *fp; 49 50/******************************************************************* 51 This is the NetServerEnum callback. 52 ******************************************************************/ 53static void callback(const char *sname, uint32 stype, const char *comment) 54{ 55 fprintf(fp,"\"%s\" %08X \"%s\"\n", sname, stype, comment); 56} 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******************************************************************/ 64static void sync_child(char *name, int nm_type, 65 char *workgroup, 66 struct in_addr ip, BOOL local, BOOL servers, 67 char *fname) 68{ 69 extern fstring local_machine; 70 static struct cli_state cli; 71 uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0; 72 struct nmb_name called, calling; 73 74 if (!cli_initialise(&cli) || !cli_connect(&cli, name, &ip)) { 75 fclose(fp); 76 return; 77 } 78 79 make_nmb_name(&calling, local_machine, 0x0); 80 make_nmb_name(&called , name, nm_type); 81 82 if (!cli_session_request(&cli, &calling, &called)) 83 { 84 cli_shutdown(&cli); 85 fclose(fp); 86 return; 87 } 88 89 if (!cli_negprot(&cli)) { 90 cli_shutdown(&cli); 91 return; 92 } 93 94 if (!cli_session_setup(&cli, "", "", 1, "", 0, workgroup)) { 95 cli_shutdown(&cli); 96 return; 97 } 98 99 if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) { 100 cli_shutdown(&cli); 101 return; 102 } 103 104 /* Fetch a workgroup list. */ 105 cli_NetServerEnum(&cli, cli.server_domain?cli.server_domain:workgroup, 106 local_type|SV_TYPE_DOMAIN_ENUM, 107 callback); 108 109 /* Now fetch a server list. */ 110 if (servers) { 111 cli_NetServerEnum(&cli, workgroup, 112 local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL, 113 callback); 114 } 115 116 cli_shutdown(&cli); 117} 118 119 120/******************************************************************* 121 initialise a browse sync with another browse server. Log in on the 122 remote server's SMB port to their IPC$ service, do a NetServerEnum 123 and record the results 124******************************************************************/ 125void sync_browse_lists(struct work_record *work, 126 char *name, int nm_type, 127 struct in_addr ip, BOOL local, BOOL servers) 128{ 129 struct sync_record *s; 130 static int counter; 131 132 /* Check we're not trying to sync with ourselves. This can 133 happen if we are a domain *and* a local master browser. */ 134 if (ismyip(ip)) { 135 return; 136 } 137 138 s = (struct sync_record *)malloc(sizeof(*s)); 139 if (!s) return; 140 141 ZERO_STRUCTP(s); 142 143 fstrcpy(s->workgroup, work->work_group); 144 fstrcpy(s->server, name); 145 s->ip = ip; 146 147 slprintf(s->fname, sizeof(pstring)-1, 148 "%s/sync.%d", lp_lockdir(), counter++); 149 all_string_sub(s->fname,"//", "/", 0); 150 151 DLIST_ADD(syncs, s); 152 153 /* the parent forks and returns, leaving the child to do the 154 actual sync */ 155 CatchChild(); 156 if ((s->pid = fork())) return; 157 158 BlockSignals( False, SIGTERM ); 159 160 DEBUG(2,("Initiating browse sync for %s to %s(%s)\n", 161 work->work_group, name, inet_ntoa(ip))); 162 163 fp = sys_fopen(s->fname,"w"); 164 if (!fp) _exit(1); 165 166 sync_child(name, nm_type, work->work_group, ip, local, servers, 167 s->fname); 168 169 fclose(fp); 170 _exit(0); 171} 172 173/********************************************************************** 174handle one line from a completed sync file 175 **********************************************************************/ 176static void complete_one(struct sync_record *s, 177 char *sname, uint32 stype, char *comment) 178{ 179 struct work_record *work; 180 struct server_record *servrec; 181 182 stype &= ~SV_TYPE_LOCAL_LIST_ONLY; 183 184 if (stype & SV_TYPE_DOMAIN_ENUM) { 185 /* See if we can find the workgroup on this subnet. */ 186 if((work=find_workgroup_on_subnet(unicast_subnet, sname))) { 187 /* We already know about this workgroup - 188 update the ttl. */ 189 update_workgroup_ttl(work,lp_max_ttl()); 190 } else { 191 /* Create the workgroup on the subnet. */ 192 work = create_workgroup_on_subnet(unicast_subnet, 193 sname, lp_max_ttl()); 194 if (work) { 195 /* remember who the master is */ 196 fstrcpy(work->local_master_browser_name, 197 comment); 198 } 199 } 200 return; 201 } 202 203 work = find_workgroup_on_subnet(unicast_subnet, s->workgroup); 204 if (!work) { 205 DEBUG(3,("workgroup %s doesn't exist on unicast subnet?\n", 206 s->workgroup)); 207 return; 208 } 209 210 if ((servrec = find_server_in_workgroup( work, sname))) { 211 /* Check that this is not a locally known 212 server - if so ignore the entry. */ 213 if(!(servrec->serv.type & SV_TYPE_LOCAL_LIST_ONLY)) { 214 /* We already know about this server - update 215 the ttl. */ 216 update_server_ttl(servrec, lp_max_ttl()); 217 /* Update the type. */ 218 servrec->serv.type = stype; 219 } 220 return; 221 } 222 223 /* Create the server in the workgroup. */ 224 create_server_on_workgroup(work, sname,stype, lp_max_ttl(), comment); 225} 226 227 228/********************************************************************** 229read the completed sync info 230 **********************************************************************/ 231static void complete_sync(struct sync_record *s) 232{ 233 FILE *f; 234 fstring server, type_str; 235 unsigned type; 236 pstring comment; 237 pstring line; 238 char *ptr; 239 int count=0; 240 241 f = sys_fopen(s->fname,"r"); 242 243 if (!f) return; 244 245 while (!feof(f)) { 246 247 if (!fgets_slash(line,sizeof(pstring),f)) continue; 248 249 ptr = line; 250 251 if (!next_token(&ptr,server,NULL,sizeof(server)) || 252 !next_token(&ptr,type_str,NULL, sizeof(type_str)) || 253 !next_token(&ptr,comment,NULL, sizeof(comment))) { 254 continue; 255 } 256 257 sscanf(type_str, "%X", &type); 258 259 complete_one(s, server, type, comment); 260 261 count++; 262 } 263 264 fclose(f); 265 266 unlink(s->fname); 267 268 DEBUG(2,("sync with %s(%s) for workgroup %s completed (%d records)\n", 269 s->server, inet_ntoa(s->ip), s->workgroup, count)); 270} 271 272/********************************************************************** 273check for completion of any of the child processes 274 **********************************************************************/ 275void sync_check_completion(void) 276{ 277 struct sync_record *s, *next; 278 279 for (s=syncs;s;s=next) { 280 next = s->next; 281 if (!process_exists(s->pid)) { 282 /* it has completed - grab the info */ 283 complete_sync(s); 284 DLIST_REMOVE(syncs, s); 285 ZERO_STRUCTP(s); 286 free(s); 287 } 288 } 289} 290