diff options
Diffstat (limited to 'source3/namework.c')
-rw-r--r-- | source3/namework.c | 516 |
1 files changed, 189 insertions, 327 deletions
diff --git a/source3/namework.c b/source3/namework.c index f0fca0071e..7307ddce04 100644 --- a/source3/namework.c +++ b/source3/namework.c @@ -45,12 +45,6 @@ extern struct in_addr ipzero; extern int workgroup_count; /* total number of workgroups we know about */ -/* this is our browse cache database */ -extern struct browse_cache_record *browserlist; - -/* this is our domain/workgroup/server database */ -extern struct interface *local_interfaces; - /* this is our domain/workgroup/server database */ extern struct subnet_record *subnetlist; @@ -70,8 +64,6 @@ extern int updatecount; extern time_t StartupTime; -#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE" - #define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl()) @@ -106,6 +98,11 @@ tell a server to become a backup browser **************************************************************************/ void tell_become_backup(void) { + /* XXXX note: this function is currently unsuitable for use, as it + does not properly check that a server is in a fit state to become + a backup browser before asking it to be one. + */ + struct subnet_record *d; for (d = subnetlist; d; d = d->next) { @@ -155,234 +152,6 @@ void tell_become_backup(void) } } -/**************************************************************************** -find a server responsible for a workgroup, and sync browse lists -**************************************************************************/ -static void start_sync_browse_entry(struct browse_cache_record *b) -{ - struct subnet_record *d; - struct work_record *work; - - if (!(d = find_subnet(b->ip))) return; - - /* only sync if we are the master */ - if (AM_MASTER(work)) { - - /* first check whether the group we intend to sync with exists. if it - doesn't, the server must have died. o dear. */ - - /* see response_netbios_packet() or expire_netbios_response_entries() */ - queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_SYNC, - b->group,0x20,0,0, - False,False,b->ip); - } - - b->synced = True; -} - - -/**************************************************************************** -search through browser list for an entry to sync with -**************************************************************************/ -void do_browser_lists(void) -{ - struct browse_cache_record *b; - static time_t last = 0; - time_t t = time(NULL); - - if (t-last < 20) return; /* don't do too many of these at once! */ - /* XXXX equally this period should not be too long - the server may die in the intervening gap */ - - last = t; - - /* pick any entry in the list, preferably one whose time is up */ - for (b = browserlist; b && b->next; b = b->next) - { - if (b->sync_time < t && b->synced == False) break; - } - - if (b && !b->synced) - { - /* sync with the selected entry then remove some dead entries */ - start_sync_browse_entry(b); - expire_browse_cache(t - 60); - } - -} - - -/**************************************************************************** -find a server responsible for a workgroup, and sync browse lists -control ends up back here via response_name_query. -**************************************************************************/ -void sync_server(enum cmd_type cmd, char *serv_name, char *work_name, - int name_type, - struct in_addr ip) -{ - add_browser_entry(serv_name, name_type, work_name, 0, ip); - - if (cmd == NAME_QUERY_MST_SRV_CHK) - { - /* announce ourselves as a master browser to serv_name */ - do_announce_request(myname, serv_name, ANN_MasterAnnouncement, - 0x20, 0, ip); - } -} - - -/**************************************************************************** - add the default workgroup into my domain - **************************************************************************/ -void add_my_subnets(char *group) -{ - struct interface *i; - - /* add or find domain on our local subnet, in the default workgroup */ - - if (*group == '*') return; - - /* the coding choice is up to you, andrew: i can see why you don't want - global access to the local_interfaces structure: so it can't get - messed up! */ - for (i = local_interfaces; i; i = i->next) - { - add_subnet_entry(i->bcast,i->nmask,group, True, False); - } -} - - -/**************************************************************************** - send a backup list response. - **************************************************************************/ -static void send_backup_list(char *work_name, struct nmb_name *src_name, - int info_count, int token, int info, - int name_type, struct in_addr ip) -{ - struct subnet_record *d; - char outbuf[1024]; - char *p, *countptr, *nameptr; - int count = 0; - int i, j; - char *theirname = src_name->name; - - DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n", - work_name, inet_ntoa(ip), - myname,0x20,theirname,0x0)); - - if (name_type == 0x1d) - { - DEBUG(4,("master browsers: ")); - } - else if (name_type == 0x1b) - { - DEBUG(4,("domain controllers: ")); - } - else - { - DEBUG(0,("backup request for unknown type %0x\n", name_type)); - return; - } - - bzero(outbuf,sizeof(outbuf)); - p = outbuf; - - CVAL(p,0) = 10; /* backup list response */ - p++; - - countptr = p; /* count pointer */ - - SSVAL(p,1,token); /* sender's workgroup index representation */ - SSVAL(p,3,info); /* XXXX clueless: info, usually zero */ - p += 5; - - nameptr = p; - - for (d = subnetlist; d; d = d->next) - { - struct work_record *work; - - for (work = d->workgrouplist; work; work = work->next) - { - struct server_record *s; - - if (!strequal(work->work_group, work_name)) continue; - - for (s = work->serverlist; s; s = s->next) - { - BOOL found = False; - char *n; - - if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue; - - for (n = nameptr; n < p; n = skip_string(n, 1)) - { - if (strequal(n, s->serv.name)) found = True; - } - - if (found) continue; /* exclude names already added */ - - /* workgroup request: include all backup browsers in the list */ - /* domain request: include all domain members in the list */ - - if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) || - (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE))) - { - DEBUG(4, ("%s ", s->serv.name)); - - count++; - strcpy(p,s->serv.name); - strupper(p); - p = skip_string(p,1); - } - } - } - } - - if (count == 0) - { - DEBUG(4, ("none\n")); - return; - } - else - { - DEBUG(4, (" - count %d\n", count)); - } - - CVAL(countptr,0) = count; /* total number of backup browsers found */ - - { - int len = PTR_DIFF(p, outbuf); - - for (i = 0; i < len; i+= 16) - { - DEBUG(4, ("%3x char ", i)); - - for (j = 0; j < 16; j++) - { - unsigned char x = outbuf[i+j]; - if (x < 32 || x > 127) x = '.'; - - if (i+j >= len) break; - DEBUG(4, ("%c", x)); - } - - DEBUG(4, (" hex ", i)); - - for (j = 0; j < 16; j++) - { - if (i+j >= len) break; - DEBUG(4, (" %02x", outbuf[i+j])); - } - - DEBUG(4, ("\n")); - } - - } - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,theirname,0x20,0,ip,*iface_ip(ip)); -} - /******************************************************************* same context: scope. should check name_type as well, and makes sure @@ -471,7 +240,16 @@ static void process_announce(struct packet_struct *p,int command,char *buf) if (same_context(dgram)) return; - if (command == ANN_DomainAnnouncement) { + if (command == ANN_DomainAnnouncement) { + /* XXXX if we are a master browser for the workgroup work_name, + then there is a local subnet configuration problem. only + we should be sending out such domain announcements, because + as the master browser, that is our job. + + stop being a master browser, and force an election. this will + sort out the network problem. hopefully. + */ + work_name = name; } else { work_name = dgram->dest_name.name; @@ -501,6 +279,14 @@ static void process_announce(struct packet_struct *p,int command,char *buf) tell_become_backup(); #endif + /* XXXX over-kill: i don't think we should really be doing this, + but it doesn't do much harm other than to add extra network + traffic. to be more precise, we should (possibly) only + sync browse lists with a host that sends an + ANN_LocalMasterAnnouncement or an ANN_DomainAnnouncement. + possibly. + */ + /* get their browse list from them and add it to ours. */ add_browser_entry(serv_name,dgram->dest_name.name_type, work->work_group,30,ip); @@ -543,6 +329,12 @@ static void process_master_announce(struct packet_struct *p,char *buf) we receive a list of servers, and we attempt to locate them all on our local subnet, and sync browse lists with them on the workgroup they are said to be in. + + XXXX NOTE: this function is in overdrive. it should not really do + half of what it actually does (it should pick _one_ name from the + list received and sync with it at regular intervals, rather than + sync with them all only once!) + ******************************************************************/ static void process_rcv_backup_list(struct packet_struct *p,char *buf) { @@ -570,7 +362,7 @@ static void process_rcv_backup_list(struct packet_struct *p,char *buf) buf1, inet_ntoa(ip))); /* XXXX assume name is a DNS name NOT a netbios name. a more complete - approach is to use reply_name_query functionality to find the name */ + approach is to use reply_name_query functionality to find the name */ back_ip = *interpret_addr2(buf1); if (zero_ip(back_ip)) @@ -602,10 +394,143 @@ static void process_rcv_backup_list(struct packet_struct *p,char *buf) } } + +/**************************************************************************** + send a backup list response. + **************************************************************************/ +static void send_backup_list(char *work_name, struct nmb_name *src_name, + int info_count, int token, int info, + int name_type, struct in_addr ip) +{ + struct subnet_record *d; + char outbuf[1024]; + char *p, *countptr, *nameptr; + int count = 0; + int i, j; + char *theirname = src_name->name; + + DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n", + work_name, inet_ntoa(ip), + myname,0x20,theirname,0x0)); + + if (name_type == 0x1d) + { + DEBUG(4,("master browsers: ")); + } + else if (name_type == 0x1b) + { + DEBUG(4,("domain controllers: ")); + } + else + { + DEBUG(0,("backup request for unknown type %0x\n", name_type)); + return; + } + + bzero(outbuf,sizeof(outbuf)); + p = outbuf; + + CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */ + p++; + + countptr = p; /* count pointer */ + + SSVAL(p,1,token); /* sender's workgroup index representation */ + SSVAL(p,3,info); /* XXXX clueless: info, usually zero */ + p += 5; + + nameptr = p; + + for (d = subnetlist; d; d = d->next) + { + struct work_record *work; + + for (work = d->workgrouplist; work; work = work->next) + { + struct server_record *s; + + if (!strequal(work->work_group, work_name)) continue; + + for (s = work->serverlist; s; s = s->next) + { + BOOL found = False; + char *n; + + if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue; + + for (n = nameptr; n < p; n = skip_string(n, 1)) + { + if (strequal(n, s->serv.name)) found = True; + } + + if (found) continue; /* exclude names already added */ + + /* workgroup request: include all backup browsers in the list */ + /* domain request: include all domain members in the list */ + + if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) || + (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE))) + { + DEBUG(4, ("%s ", s->serv.name)); + + count++; + strcpy(p,s->serv.name); + strupper(p); + p = skip_string(p,1); + } + } + } + } + + if (count == 0) + { + DEBUG(4, ("none\n")); + return; + } + else + { + DEBUG(4, (" - count %d\n", count)); + } + + CVAL(countptr,0) = count; /* total number of backup browsers found */ + + { + int len = PTR_DIFF(p, outbuf); + + for (i = 0; i < len; i+= 16) + { + DEBUG(4, ("%3x char ", i)); + + for (j = 0; j < 16; j++) + { + unsigned char x = outbuf[i+j]; + if (x < 32 || x > 127) x = '.'; + + if (i+j >= len) break; + DEBUG(4, ("%c", x)); + } + + DEBUG(4, (" hex ", i)); + + for (j = 0; j < 16; j++) + { + if (i+j >= len) break; + DEBUG(4, (" %02x", outbuf[i+j])); + } + + DEBUG(4, ("\n")); + } + + } + send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + myname,theirname,0x20,0x0,ip,*iface_ip(ip)); +} + + /******************************************************************* process a send backup list request - A client send a backup list request to ask for a list of servers on + A client sends a backup list request to ask for a list of servers on the net that maintain server lists for a domain. A server is then chosen from this list to send NetServerEnum commands to to list available servers. @@ -618,7 +543,7 @@ static void process_send_backup_list(struct packet_struct *p,char *buf) { struct dgram_packet *dgram = &p->packet.dgram; struct in_addr ip = dgram->header.source_ip; - struct subnet_record *d; + struct subnet_record *d; struct work_record *work; int count = CVAL(buf,0); @@ -658,7 +583,7 @@ static void process_send_backup_list(struct packet_struct *p,char *buf) process a reset browser state diagnostic packet: - 0x1 - stop being a master browser + 0x1 - stop being a master browser and become a backup browser. 0x2 - discard browse lists, stop being a master browser, try again. 0x4 - stop being a master browser forever. no way. ain't gonna. @@ -688,6 +613,10 @@ static void process_reset_browser(struct packet_struct *p,char *buf) } } + /* XXXX documentation inconsistency: the above description does not + exactly tally with what is implemented for state & 0x2 + */ + /* totally delete all servers and start afresh */ if (state & 0x2) { @@ -730,12 +659,23 @@ static void process_announce_request(struct packet_struct *p,char *buf) if (strequal(dgram->source_name.name,myname)) return; + /* XXXX BUG or FEATURE?: need to ensure that we are a member of + this workgroup before announcing, particularly as we only + respond on local interfaces anyway. + + if (strequal(dgram->dest_name, lp_workgroup()) return; ??? + */ + if (!d) return; if (!d->my_interface) return; for (work = d->workgrouplist; work; work = work->next) { + /* XXXX BUG: the destination name type should also be checked, + not just the name. e.g if the name is WORKGROUP(0x1d) then + we should only respond if we own that name */ + if (strequal(dgram->dest_name.name,work->work_group)) { work->needannounce = True; @@ -745,89 +685,6 @@ static void process_announce_request(struct packet_struct *p,char *buf) /**************************************************************************** - process a domain logon packet - **************************************************************************/ -void process_logon_packet(struct packet_struct *p,char *buf,int len) -{ - struct dgram_packet *dgram = &p->packet.dgram; - struct in_addr ip = dgram->header.source_ip; - struct subnet_record *d = find_subnet(ip); - char *logname,*q; - char *reply_name; - BOOL add_slashes = False; - pstring outbuf; - int code,reply_code; - struct work_record *work; - - if (!d) return; - - if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False))) - return; - - if (!lp_domain_logons()) { - DEBUG(3,("No domain logons\n")); - return; - } - if (!listening_name(work, &dgram->dest_name)) - { - DEBUG(4,("Not listening to that domain\n")); - return; - } - - code = SVAL(buf,0); - switch (code) { - case 0: - { - char *machine = buf+2; - char *user = skip_string(machine,1); - logname = skip_string(user,1); - reply_code = 6; - reply_name = myname; - add_slashes = True; - DEBUG(3,("Domain login request from %s(%s) user=%s\n", - machine,inet_ntoa(p->ip),user)); - } - break; - case 7: - { - char *machine = buf+2; - logname = skip_string(machine,1); - reply_code = 7; - reply_name = lp_domain_controller(); - if (!*reply_name) { - DEBUG(3,("No domain controller configured\n")); - return; - } - DEBUG(3,("GETDC request from %s(%s)\n", - machine,inet_ntoa(p->ip))); - } - break; - default: - DEBUG(3,("Unknown domain request %d\n",code)); - return; - } - - bzero(outbuf,sizeof(outbuf)); - q = outbuf; - SSVAL(q,0,reply_code); - q += 2; - if (add_slashes) { - strcpy(q,"\\\\"); - q += 2; - } - StrnCpy(q,reply_name,16); - strupper(q); - q = skip_string(q,1); - SSVAL(q,0,0xFFFF); - q += 2; - - send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf), - myname,&dgram->source_name.name[0],0x20,0,p->ip, - *iface_ip(p->ip)); -} - - -/**************************************************************************** depending on what announce has been made, we are only going to accept certain types of name announce. XXXX untested code @@ -988,11 +845,16 @@ void process_dgram(struct packet_struct *p) if (len <= 0) return; - if (strequal(smb_buf(buf),"\\MAILSLOT\\BROWSE")) - { + /* datagram packet received for the browser mailslot */ + if (strequal(smb_buf(buf),BROWSE_MAILSLOT)) { process_browse_packet(p,buf2,len); - } else if (strequal(smb_buf(buf),"\\MAILSLOT\\NET\\NETLOGON")) { + return; + } + + /* datagram packet received for the domain log on mailslot */ + if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT)) { process_logon_packet(p,buf2,len); + return; } } |