diff options
author | Samba Release Account <samba-bugs@samba.org> | 1997-03-09 14:58:22 +0000 |
---|---|---|
committer | Samba Release Account <samba-bugs@samba.org> | 1997-03-09 14:58:22 +0000 |
commit | b581d0324098f12a5bcb1941e698339a84e44a93 (patch) | |
tree | e6582f6847cc0df3377b7d722f4d3f8f2b573659 /source3/nameelect.c | |
parent | 3046a0d7c29ad6a5bdafe763c90aa521ac8aa93a (diff) | |
download | samba-b581d0324098f12a5bcb1941e698339a84e44a93.tar.gz samba-b581d0324098f12a5bcb1941e698339a84e44a93.tar.bz2 samba-b581d0324098f12a5bcb1941e698339a84e44a93.zip |
1) updated ipc.c NetUserGetInfo - load \\%L\%U instead of \\%L\HOMES
because the share must be browseable by a w95 client
2) send_mailslot_reply - unique or group datagram argument added.
3) netlogon.c - rewrote response packet to do the right thing for w95.
4) server.c reply_nt1() - added OEMDomainstring to the end.
5) (deep breath) reworked the nmbd-browsing code a little bit.
i discovered two months ago that becoming a primary domain controller
(and domain master browser) is done independently of becoming a
backup domain controller (logon server) is done independently of
becoming a local master browser.
therefore, three sets of state-machines (instead of just one) are in
place - each of which is responsible for taking samba through the
required stages to become: a logon server; a domain master browser;
and a local master browser.
each of these three things can occur independently on each interface,
_including_ the wins pseudo-interface. the only slight caveat is that
the wins pseudo-interface, by virtue of _not_ being a broadcast
interface, does _not_ register as a local master browser with the wins
server, as this doesn't make sense.
lkcl
(This used to be commit 88c6a00c3c1b430307f512986185b5ed7aea7181)
Diffstat (limited to 'source3/nameelect.c')
-rw-r--r-- | source3/nameelect.c | 379 |
1 files changed, 255 insertions, 124 deletions
diff --git a/source3/nameelect.c b/source3/nameelect.c index 9a15c0b112..9254e44712 100644 --- a/source3/nameelect.c +++ b/source3/nameelect.c @@ -51,6 +51,7 @@ extern struct subnet_record *subnetlist; extern uint16 nb_type; /* samba's NetBIOS name type */ + /******************************************************************* occasionally check to see if the master browser is around ******************************************************************/ @@ -167,7 +168,8 @@ void send_election(struct subnet_record *d, char *group,uint32 criterion, strupper(p); p = skip_string(p,1); - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM, + outbuf,PTR_DIFF(p,outbuf), name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip)); } @@ -183,26 +185,39 @@ void send_election(struct subnet_record *d, char *group,uint32 criterion, void name_unregister_work(struct subnet_record *d, char *name, int name_type) { struct work_record *work; + int remove_type_local = 0; + int remove_type_domain = 0; + int remove_type_logon = 0; remove_netbios_name(d,name,name_type,SELF,ipzero); if (!(work = find_workgroupstruct(d, name, False))) return; - if (ms_browser_name(name, name_type) || - (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 && - (name_type == 0x1d || name_type == 0x1b))) + /* work out what to unbecome, from the name type being removed */ + + if (ms_browser_name(name, name_type)) + { + remove_type_local |= SV_TYPE_MASTER_BROWSER; + } + if (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 && + name_type == 0x1d) + { + remove_type_local |= SV_TYPE_MASTER_BROWSER; + } + if (AM_DOMMST(work) && strequal(name, lp_workgroup()) == 0 && + name_type == 0x1b) { - int remove_type = 0; - - if (ms_browser_name(name, name_type)) - remove_type = SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER; - if (name_type == 0x1d) - remove_type = SV_TYPE_MASTER_BROWSER; - if (name_type == 0x1b) - remove_type = SV_TYPE_DOMAIN_MASTER; - - become_nonmaster(d, work, remove_type); + remove_type_domain |= SV_TYPE_DOMAIN_MASTER; } + if (AM_DOMMEM(work) && strequal(name, lp_workgroup()) == 0 && + name_type == 0x1c) + { + remove_type_logon|= SV_TYPE_DOMAIN_MEMBER; + } + + if (remove_type_local ) unbecome_local_master (d, work, remove_type_local ); + if (remove_type_domain) unbecome_domain_master(d, work, remove_type_domain); + if (remove_type_logon ) unbecome_logon_server (d, work, remove_type_logon ); } @@ -227,12 +242,28 @@ void name_register_work(struct subnet_record *d, char *name, int name_type, if (work) { - if (work->state != MST_NONE) + if (work->mst_state != MST_POTENTIAL) { - /* samba is in the process of working towards master browser-ness. + /* samba is working towards local master browser-ness. initiate the next stage. */ - become_master(d, work); + become_local_master(d, work); + return; + } + if (work->dom_state != DOMAIN_NONE) + { + /* samba is working towards domain master browser-ness. + initiate the next stage. + */ + become_domain_master(d, work); + return; + } + if (work->log_state != LOGON_NONE) + { + /* samba is working towards domain master browser-ness. + initiate the next stage. + */ + become_logon_server(d, work); return; } } @@ -241,29 +272,28 @@ void name_register_work(struct subnet_record *d, char *name, int name_type, /******************************************************************* - become the master browser. + become the local master browser. this is done in stages. note that this could take a while, particularly on a broadcast subnet, as we have to wait for the implicit registration of each name to be accepted. - as each name is successfully registered, become_master() is + as each name is successfully registered, become_local_master() is called again, in order to initiate the next stage. see dead_netbios_entry() - deals with implicit name registration and response_name_reg() - deals with explicit registration with a WINS server. - stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1. - stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d) - stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b) - stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...) + stage 1: was MST_POTENTIAL - go to MST_POTENTIAL and register ^1^2__MSBROWSE__^2^1. + stage 2: was MST_BACK - go to MST_MSB and register WORKGROUP(0x1d) + stage 3: was MST_MSB - go to MST_BROWSER and stay there XXXX note: this code still does not cope with the distinction between different types of nodes, particularly between M and P nodes. that comes later. ******************************************************************/ -void become_master(struct subnet_record *d, struct work_record *work) +void become_local_master(struct subnet_record *d, struct work_record *work) { /* domain type must be limited to domain enum + server type. it must not have SV_TYPE_SERVER or anything else with SERVER in it, else @@ -272,17 +302,17 @@ void become_master(struct subnet_record *d, struct work_record *work) */ uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT; - if (!work) return; + if (!work || !d) return; DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n", - work->work_group,inet_ntoa(d->bcast_ip),work->state)); + work->work_group,inet_ntoa(d->bcast_ip),work->mst_state)); - switch (work->state) + switch (work->mst_state) { - case MST_NONE: /* while we were nothing but a server... */ + case MST_POTENTIAL: /* while we were nothing but a server... */ { DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n")); - work->state = MST_WON; /* ... an election win was successful */ + work->mst_state = MST_BACK; /* ... an election win was successful */ work->ElectionCriterion |= 0x5; @@ -294,12 +324,13 @@ void become_master(struct subnet_record *d, struct work_record *work) add_my_name_entry(d,MSBROWSE ,0x01,nb_type|NB_ACTIVE|NB_GROUP); /* DON'T do anything else after calling add_my_name_entry() */ - return; + break; } - case MST_WON: /* while nothing had happened except we won an election... */ + + case MST_BACK: /* while nothing had happened except we won an election... */ { DEBUG(3,("go to second stage: register as master browser\n")); - work->state = MST_MSB; /* ... registering MSBROWSE was successful */ + work->mst_state = MST_MSB; /* ... registering MSBROWSE was successful */ /* add server entry on successful registration of MSBROWSE */ add_server_entry(d,work,work->work_group,domain_type,0,myname,True); @@ -308,12 +339,13 @@ void become_master(struct subnet_record *d, struct work_record *work) add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE); /* DON'T do anything else after calling add_my_name_entry() */ - return; + break; } + case MST_MSB: /* while we were still only registered MSBROWSE state... */ { DEBUG(3,("2nd stage complete: registered as master browser\n")); - work->state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */ + work->mst_state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */ /* update our server status */ work->ServerType |= SV_TYPE_MASTER_BROWSER; @@ -322,31 +354,70 @@ void become_master(struct subnet_record *d, struct work_record *work) if (work->serverlist == NULL) /* no servers! */ { /* ask all servers on our local net to announce to us */ + /* XXXX OOPS! add_server_entry will always add one entry - our own. */ announce_request(work, d->bcast_ip); } break; - } + } - case MST_BROWSER: - { + case MST_BROWSER: + { /* don't have to do anything: just report success */ DEBUG(3,("3rd stage: become master browser!\n")); break; - } + } + } +} - case MST_DOMAIN_NONE: - { + +/******************************************************************* + become the domain master browser. + + this is done in stages. note that this could take a while, + particularly on a broadcast subnet, as we have to wait for + the implicit registration of each name to be accepted. + + as each name is successfully registered, become_domain_master() is + called again, in order to initiate the next stage. see + dead_netbios_entry() - deals with implicit name registration + and response_name_reg() - deals with explicit registration + with a WINS server. + + stage 1: was DOMAIN_NONE - go to DOMAIN_MST + + XXXX note: this code still does not cope with the distinction + between different types of nodes, particularly between M and P + nodes. that comes later. + + ******************************************************************/ +void become_domain_master(struct subnet_record *d, struct work_record *work) +{ + /* domain type must be limited to domain enum + server type. it must + not have SV_TYPE_SERVER or anything else with SERVER in it, else + clients get confused and start thinking this entry is a server + not a workgroup + */ + + if (!work || !d) return; + + DEBUG(2,("Becoming domain master for %s %s (currently at stage %d)\n", + work->work_group,inet_ntoa(d->bcast_ip),work->dom_state)); + + switch (work->dom_state) + { + case DOMAIN_NONE: /* while we were nothing but a server... */ + { if (lp_domain_master()) { - work->state = MST_DOMAIN_MEM; /* ... become domain member */ - DEBUG(3,("domain first stage: register as domain member\n")); + DEBUG(3,("go to first stage: register <1b> name\n")); + work->dom_state = DOMAIN_WAIT; - /* add domain member name */ - add_my_name_entry(d,work->work_group,0x1e,nb_type|NB_ACTIVE|NB_GROUP); + /* XXXX the 0x1b is domain master browser name */ + add_my_name_entry(d, lp_workgroup(),0x1b,nb_type|NB_ACTIVE|NB_GROUP); - /* DON'T do anything else after calling add_my_name_entry() */ - return; + /* DON'T do anything else after calling add_my_name_entry() */ + break; } else { @@ -354,26 +425,23 @@ void become_master(struct subnet_record *d, struct work_record *work) } break; - } + } - case MST_DOMAIN_MEM: + case DOMAIN_WAIT: { if (lp_domain_master()) { - work->state = MST_DOMAIN_TST; /* ... possibly become domain master */ - DEBUG(3,("domain second stage: register as domain master\n")); - - if (lp_domain_logons()) - { - work->ServerType |= SV_TYPE_DOMAIN_MEMBER; - add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True); - } + work->dom_state = DOMAIN_MST; /* ... become domain master */ + DEBUG(3,("domain first stage: register as domain member\n")); + + /* update our server status */ + work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER; + add_server_entry(d,work,myname,work->ServerType,0, + lp_serverstring(),True); - /* add domain master name */ - add_my_name_entry(d,work->work_group,0x1b,nb_type|NB_ACTIVE ); + DEBUG(4,("samba is now a domain master\n")); - /* DON'T do anything else after calling add_my_name_entry() */ - return; + break; } else { @@ -381,108 +449,173 @@ void become_master(struct subnet_record *d, struct work_record *work) } break; + } + + case DOMAIN_MST: + { + /* don't have to do anything: just report success */ + DEBUG(3,("domain second stage: there isn't one!\n")); + break; } + } +} + - case MST_DOMAIN_TST: /* while we were still a master browser... */ +/******************************************************************* + become a logon server. + ******************************************************************/ +void become_logon_server(struct subnet_record *d, struct work_record *work) +{ + if (!work || !d) return; + + DEBUG(2,("Becoming logon server for %s %s (currently at stage %d)\n", + work->work_group,inet_ntoa(d->bcast_ip),work->log_state)); + + switch (work->log_state) + { + case LOGON_NONE: /* while we were nothing but a server... */ { - /* update our server status */ - if (lp_domain_master()) + if (lp_domain_logons()) { - struct subnet_record *d1; - uint32 update_type = 0; - - DEBUG(3,("domain third stage: samba is now a domain master.\n")); - work->state = MST_DOMAIN; /* ... registering WORKGROUP(1b) succeeded */ + DEBUG(3,("go to first stage: register <1c> name\n")); + work->log_state = LOGON_WAIT; - update_type |= DFLT_SERVER_TYPE | SV_TYPE_DOMAIN_MASTER | - SV_TYPE_POTENTIAL_BROWSER; + /* XXXX the 0x1c is apparently something to do with domain logons */ + add_my_name_entry(d, lp_workgroup(),0x1c,nb_type|NB_ACTIVE|NB_GROUP); - work->ServerType |= update_type; - add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True); + /* DON'T do anything else after calling add_my_name_entry() */ + break; + } + { + DEBUG(4,("samba not configured as a logon master.\n")); + } + + break; + } - for (d1 = subnetlist; d1; d1 = d1->next) - { - struct work_record *w; - if (ip_equal(d1->bcast_ip, d->bcast_ip)) continue; + case LOGON_WAIT: + { + if (lp_domain_logons()) + { + work->log_state = LOGON_SRV; /* ... become logon server */ + DEBUG(3,("logon second stage: register \n")); + + /* update our server status */ + work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER; + add_server_entry(d,work,myname,work->ServerType,0, + lp_serverstring(),True); - for (w = d1->workgrouplist; w; w = w->next) - { - struct server_record *s = find_server(w, myname); - if (strequal(w->work_group, work->work_group)) - { - w->ServerType |= update_type; - } - if (s) - { - s->serv.type |= update_type; - DEBUG(4,("found server %s on %s: update to %8x\n", - s->serv.name, inet_ntoa(d1->bcast_ip), - s->serv.type)); - } - } - } + /* DON'T do anything else after calling add_my_name_entry() */ + break; + } + else + { + DEBUG(4,("samba not configured as a logon server.\n")); } break; - } + } - case MST_DOMAIN: - { - /* don't have to do anything: just report success */ - DEBUG(3,("fifth stage: there isn't one yet!\n")); + case LOGON_SRV: + { + DEBUG(3,("logon third stage: there isn't one!\n")); break; - } + } + } } /******************************************************************* - unbecome the master browser. initates removal of necessary netbios + unbecome the local master browser. initates removal of necessary netbios names, and tells the world that we are no longer a master browser. + + XXXX this _should_ be used to demote to a backup master browser, without + going straight to non-master browser. another time. + ******************************************************************/ -void become_nonmaster(struct subnet_record *d, struct work_record *work, +void unbecome_local_master(struct subnet_record *d, struct work_record *work, int remove_type) { int new_server_type = work->ServerType; - DEBUG(2,("Becoming non-master for %s\n",work->work_group)); - - /* can only remove master or domain types with this function */ - remove_type &= SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER; - - /* unbecome a master browser; unbecome a domain master, too :-( */ - if (remove_type & SV_TYPE_MASTER_BROWSER) - remove_type |= SV_TYPE_DOMAIN_MASTER; + /* can only remove master types with this function */ + remove_type &= SV_TYPE_MASTER_BROWSER; new_server_type &= ~remove_type; - if (!(new_server_type & (SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER))) + if (remove_type) { + DEBUG(2,("Becoming local non-master for %s\n",work->work_group)); + /* no longer a master browser of any sort */ work->ServerType |= SV_TYPE_POTENTIAL_BROWSER; work->ElectionCriterion &= ~0x4; - work->state = MST_NONE; + work->mst_state = MST_POTENTIAL; /* announce ourselves as no longer active as a master browser. */ announce_server(d, work, work->work_group, myname, 0, 0); remove_name_entry(d,MSBROWSE ,0x01); + remove_name_entry(d,work->work_group,0x1d); } +} + + +/******************************************************************* + unbecome the domain master browser. initates removal of necessary netbios + names, and tells the world that we are no longer a domain browser. + ******************************************************************/ +void unbecome_domain_master(struct subnet_record *d, struct work_record *work, + int remove_type) +{ + int new_server_type = work->ServerType; + + DEBUG(2,("Becoming domain non-master for %s\n",work->work_group)); - work->ServerType = new_server_type; + /* can only remove master or domain types with this function */ + remove_type &= SV_TYPE_DOMAIN_MASTER; - if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER)) + new_server_type &= ~remove_type; + + if (remove_type) { - if (work->state == MST_DOMAIN) - work->state = MST_BROWSER; + /* no longer a domain master browser of any sort */ + + work->dom_state = DOMAIN_NONE; + + /* announce ourselves as no longer active as a master browser. */ + announce_server(d, work, work->work_group, myname, 0, 0); remove_name_entry(d,work->work_group,0x1b); } +} + + +/******************************************************************* + unbecome the logon server. initates removal of necessary netbios + names, and tells the world that we are no longer a logon server. + ******************************************************************/ +void unbecome_logon_server(struct subnet_record *d, struct work_record *work, + int remove_type) +{ + int new_server_type = work->ServerType; + + DEBUG(2,("Becoming logon non-server for %s\n",work->work_group)); + + /* can only remove master or domain types with this function */ + remove_type &= SV_TYPE_DOMAIN_MEMBER; - if (!(work->ServerType & SV_TYPE_MASTER_BROWSER)) + new_server_type &= ~remove_type; + + if (remove_type) { - if (work->state >= MST_BROWSER) - work->state = MST_NONE; - remove_name_entry(d,work->work_group,0x1d); + /* no longer a master browser of any sort */ + + work->log_state = LOGON_NONE; + + /* announce ourselves as no longer active as a master browser. */ + announce_server(d, work, work->work_group, myname, 0, 0); + remove_name_entry(d,work->work_group,0x1c); } } @@ -518,9 +651,9 @@ void run_elections(time_t t) work->work_group,inet_ntoa(d->bcast_ip))); work->RunningElection = False; - work->state = MST_NONE; + work->mst_state = MST_POTENTIAL; - become_master(d, work); + become_local_master(d, work); } } } @@ -598,7 +731,7 @@ void process_election(struct packet_struct *p,char *buf) if (!work->RunningElection) { work->needelection = True; work->ElectionCount=0; - work->state = MST_NONE; + work->mst_state = MST_POTENTIAL; } } else { work->needelection = False; @@ -608,9 +741,7 @@ void process_election(struct packet_struct *p,char *buf) DEBUG(3,(">>> Lost election on %s %s <<<\n", work->work_group,inet_ntoa(d->bcast_ip))); if (AM_MASTER(work)) - become_nonmaster(d, work, - SV_TYPE_MASTER_BROWSER| - SV_TYPE_DOMAIN_MASTER); + unbecome_local_master(d, work, SV_TYPE_MASTER_BROWSER); } } } |