diff options
-rw-r--r-- | source3/lib/wins_srv.c | 261 | ||||
-rw-r--r-- | source3/libsmb/namequery.c | 111 | ||||
-rw-r--r-- | source3/nmbd/nmbd_nameregister.c | 298 | ||||
-rw-r--r-- | source3/nmbd/nmbd_packets.c | 97 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_wins.c | 21 | ||||
-rw-r--r-- | source3/nsswitch/wins.c | 29 | ||||
-rw-r--r-- | source3/utils/nmblookup.c | 4 | ||||
-rw-r--r-- | source3/web/diagnose.c | 2 |
8 files changed, 557 insertions, 266 deletions
diff --git a/source3/lib/wins_srv.c b/source3/lib/wins_srv.c index c31e7505f0..95b25b96b2 100644 --- a/source3/lib/wins_srv.c +++ b/source3/lib/wins_srv.c @@ -1,6 +1,6 @@ /* Unix SMB/CIFS implementation. - Samba utility functions + Samba wins server helper functions Copyright (C) Andrew Tridgell 1992-2002 Copyright (C) Christopher R. Hertel 2000 @@ -21,6 +21,41 @@ #include "includes.h" +/* + this is pretty much a complete rewrite of the earlier code. The main + aim of the rewrite is to add support for having multiple wins server + lists, so Samba can register with multiple groups of wins servers + and each group has a failover list of wins servers. + + Central to the way it all works is the idea of a wins server + 'tag'. A wins tag is a label for a group of wins servers. For + example if you use + + wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61 + + then you would have two groups of wins servers, one tagged with the + name 'fred' and the other with the name 'mary'. I would usually + recommend using interface names instead of 'fred' and 'mary' but + they can be any alpha string. + + Now, how does it all work. Well, nmbd needs to register each of its + IPs with each of its names once with each group of wins servers. So + it tries registering with the first one mentioned in the list, then + if that fails it marks that WINS server dead and moves onto the next + one. + + In the client code things are a bit different. As each of the groups + of wins servers is a separate name space we need to try each of the + groups until we either succeed or we run out of wins servers to + try. If we get a negative response from a wins server then that + means the name doesn't exist in that group, so we give up on that + group and move to the next group. If we don't get a response at all + then maybe the wins server is down, in which case we need to + failover to the next one for that group. + + confused yet? (tridge) +*/ + /* how long a server is marked dead for */ #define DEATH_TIME 600 @@ -33,10 +68,17 @@ static struct wins_dead { } *dead_servers; +/* an internal convenience structure for an IP with a short string tag + attached */ +struct tagged_ip { + fstring tag; + struct in_addr ip; +}; + /* see if an ip is on the dead list */ -static int wins_is_dead(struct in_addr ip) +BOOL wins_srv_is_dead(struct in_addr ip) { struct wins_dead *d; for (d=dead_servers; d; d=d->next) { @@ -46,12 +88,12 @@ static int wins_is_dead(struct in_addr ip) DEBUG(4,("Reviving wins server %s\n", inet_ntoa(ip))); DLIST_REMOVE(dead_servers, d); free(d); - return 0; + return False; } - return 1; + return True; } } - return 0; + return False; } /* @@ -61,7 +103,7 @@ void wins_srv_died(struct in_addr ip) { struct wins_dead *d; - if (is_zero_ip(ip) || wins_is_dead(ip)) { + if (is_zero_ip(ip) || wins_srv_is_dead(ip)) { return; } @@ -79,11 +121,16 @@ void wins_srv_died(struct in_addr ip) /* return the total number of wins servers, dead or not */ -unsigned long wins_srv_count(void) +unsigned wins_srv_count(void) { char **list; int count = 0; + if (lp_wins_support()) { + /* simple - just talk to ourselves */ + return 1; + } + list = lp_wins_server_list(); for (count=0; list && list[count]; count++) /* nop */ ; @@ -92,31 +139,213 @@ unsigned long wins_srv_count(void) } /* + parse an IP string that might be in tagged format + the result is a tagged_ip structure containing the tag + and the ip in in_addr format. If there is no tag then + use the tag '*' +*/ +static void parse_ip(struct tagged_ip *ip, const char *str) +{ + char *s = strchr(str, ':'); + if (!s) { + fstrcpy(ip->tag, "*"); + ip->ip = *interpret_addr2(str); + return; + } + + ip->ip = *interpret_addr2(s+1); + fstrcpy(ip->tag, str); + s = strchr(ip->tag, ':'); + if (s) *s = 0; +} + + +/* return the IP of the currently active wins server, or the zero IP otherwise */ struct in_addr wins_srv_ip(void) { char **list; - struct in_addr ip; int i; + struct tagged_ip t_ip; + + /* if we are a wins server then we always just talk to ourselves */ + if (lp_wins_support()) { + extern struct in_addr loopback_ip; + return loopback_ip; + } list = lp_wins_server_list(); if (!list || !list[0]) { - zero_ip(&ip); - return ip; + zero_ip(&t_ip.ip); + return t_ip.ip; } /* find the first live one */ for (i=0; list[i]; i++) { - ip = *interpret_addr2(list[i]); - if (!wins_is_dead(ip)) { - DEBUG(6,("Current wins server is %s\n", inet_ntoa(ip))); - return ip; + parse_ip(&t_ip, list[i]); + if (!wins_srv_is_dead(t_ip.ip)) { + DEBUG(6,("Current wins server is %s\n", inet_ntoa(t_ip.ip))); + return t_ip.ip; } } /* damn, they are all dead. Keep trying the primary until they revive */ - ip = *interpret_addr2(list[0]); + parse_ip(&t_ip, list[0]); + + return t_ip.ip; +} + + +/* + return the list of wins server tags. A 'tag' is used to distinguish + wins server as either belonging to the same name space or a separate + name space. Usually you would setup your 'wins server' option to + list one or more wins server per interface and use the interface + name as your tag, but you are free to use any tag you like. +*/ +char **wins_srv_tags(void) +{ + char **ret = NULL; + int count=0, i, j; + char **list; + + if (lp_wins_support()) { + /* give the caller something to chew on. This makes + the rest of the logic simpler (ie. less special cases) */ + ret = (char **)malloc(sizeof(char *)*2); + if (!ret) return NULL; + ret[0] = strdup("*"); + ret[1] = NULL; + return ret; + } + + list = lp_wins_server_list(); + if (!list) return NULL; + + /* yes, this is O(n^2) but n is very small */ + for (i=0;list[i];i++) { + struct tagged_ip t_ip; + + parse_ip(&t_ip, list[i]); + + /* see if we already have it */ + for (j=0;j<count;j++) { + if (strcmp(ret[j], t_ip.tag) == 0) { + break; + } + } + + if (j != count) { + /* we already have it. Move along */ + continue; + } + + /* add it to the list */ + ret = (char **)Realloc(ret, (count+1) * sizeof(char *)); + ret[count] = strdup(t_ip.tag); + if (!ret[count]) break; + count++; + } + + if (count) { + /* make sure we null terminate */ + ret[count] = NULL; + } + + return ret; +} + +/* free a list of wins server tags given by wins_srv_tags */ +void wins_srv_tags_free(char **list) +{ + int i; + if (!list) return; + for (i=0; list[i]; i++) { + free(list[i]); + } + free(list); +} - return ip; + +/* + return the IP of the currently active wins server for the given tag, + or the zero IP otherwise +*/ +struct in_addr wins_srv_ip_tag(const char *tag) +{ + char **list; + int i; + struct tagged_ip t_ip; + + /* if we are a wins server then we always just talk to ourselves */ + if (lp_wins_support()) { + extern struct in_addr loopback_ip; + return loopback_ip; + } + + list = lp_wins_server_list(); + if (!list || !list[0]) { + struct in_addr ip; + zero_ip(&ip); + return ip; + } + + /* find the first live one for this tag */ + for (i=0; list[i]; i++) { + parse_ip(&t_ip, list[i]); + if (strcmp(tag, t_ip.tag) != 0) { + /* not for the right tag. Move along */ + continue; + } + if (!wins_srv_is_dead(t_ip.ip)) { + DEBUG(6,("Current wins server for tag '%s' is %s\n", tag, inet_ntoa(t_ip.ip))); + return t_ip.ip; + } + } + + /* they're all dead - try the first one until they revive */ + for (i=0; list[i]; i++) { + parse_ip(&t_ip, list[i]); + if (strcmp(tag, t_ip.tag) != 0) { + continue; + } + return t_ip.ip; + } + + /* this can't happen?? */ + zero_ip(&t_ip.ip); + return t_ip.ip; +} + + +/* + return a count of the number of IPs for a particular tag, including + dead ones +*/ +unsigned wins_srv_count_tag(const char *tag) +{ + char **list; + int i, count=0; + + /* if we are a wins server then we always just talk to ourselves */ + if (lp_wins_support()) { + return 1; + } + + list = lp_wins_server_list(); + if (!list || !list[0]) { + return 0; + } + + /* find the first live one for this tag */ + for (i=0; list[i]; i++) { + struct tagged_ip t_ip; + parse_ip(&t_ip, list[i]); + if (strcmp(tag, t_ip.tag) == 0) { + count++; + } + } + + return count; } diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index c85c8c48df..2cdcd49b91 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -302,10 +302,12 @@ BOOL name_register(int fd, const char *name, int name_type, Do a netbios name query to find someones IP. Returns an array of IP addresses or NULL if none. *count will be set to the number of addresses returned. + *timed_out is set if we failed by timing out ****************************************************************************/ struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse, - struct in_addr to_ip, int *count, int *flags) + struct in_addr to_ip, int *count, int *flags, + BOOL *timed_out) { BOOL found=False; int i, retries = 3; @@ -315,6 +317,10 @@ struct in_addr *name_query(int fd,const char *name,int name_type, struct packet_struct *p2; struct nmb_packet *nmb = &p.packet.nmb; struct in_addr *ip_list = NULL; + + if (timed_out) { + *timed_out = False; + } memset((char *)&p,'\0',sizeof(p)); (*count) = 0; @@ -465,10 +471,8 @@ struct in_addr *name_query(int fd,const char *name,int name_type, } } - /* Reach here if we've timed out waiting for replies.. */ - if (!bcast && !found) { - /* Timed out wating for WINS server to respond. Mark it dead. */ - wins_srv_died( to_ip ); + if (timed_out) { + *timed_out = True; } return ip_list; @@ -619,7 +623,7 @@ BOOL name_resolve_bcast(const char *name, int name_type, /* Done this way to fix compiler error on IRIX 5.x */ sendto_ip = *iface_n_bcast(i); *return_ip_list = name_query(sock, name, name_type, True, - True, sendto_ip, return_count, &flags); + True, sendto_ip, return_count, &flags, NULL); if(*return_ip_list != NULL) { close(sock); return True; @@ -637,59 +641,80 @@ BOOL name_resolve_bcast(const char *name, int name_type, static BOOL resolve_wins(const char *name, int name_type, struct in_addr **return_iplist, int *return_count) { - int sock; - struct in_addr wins_ip; - BOOL wins_ismyip; + int sock, t, i; + char **wins_tags; *return_iplist = NULL; *return_count = 0; - /* - * "wins" means do a unicast lookup to the WINS server. - * Ignore if there is no WINS server specified or if the - * WINS server is one of our interfaces (if we're being - * called from within nmbd - we can't do this call as we - * would then block). - */ - DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type)); - if (lp_wins_support()) { - /* - * We're providing WINS support. Call ourselves so - * long as we're not nmbd. - */ - extern struct in_addr loopback_ip; - wins_ip = loopback_ip; - wins_ismyip = True; - } else if( wins_srv_count() < 1 ) { + if (wins_srv_count() < 1) { DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n")); return False; - } else { - wins_ip = wins_srv_ip(); - wins_ismyip = ismyip(wins_ip); } - DEBUG(3, ("resolve_wins: WINS server == <%s>\n", inet_ntoa(wins_ip)) ); - if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) { - int flags; - sock = open_socket_in( SOCK_DGRAM, 0, 3, - interpret_addr(lp_socket_address()), - True ); - if (sock != -1) { - *return_iplist = name_query( sock, name, - name_type, False, - True, wins_ip, - return_count, &flags); - if(*return_iplist != NULL) { - close(sock); - return True; + /* we try a lookup on each of the WINS tags in turn */ + wins_tags = wins_srv_tags(); + + if (!wins_tags) { + /* huh? no tags?? give up in disgust */ + return False; + } + + /* in the worst case we will try every wins server with every + tag! */ + for (t=0; wins_tags && wins_tags[t]; t++) { + for (i=0; i<wins_srv_count_tag(wins_tags[t]); i++) { + struct in_addr wins_ip; + int flags; + BOOL timed_out; + + wins_ip = wins_srv_ip_tag(wins_tags[t]); + + if (global_in_nmbd && ismyip(wins_ip)) { + /* yikes! we'll loop forever */ + continue; + } + + /* skip any that have been unresponsive lately */ + if (wins_srv_is_dead(wins_ip)) { + continue; + } + + DEBUG(3,("resolve_wins: using WINS server %s and tag '%s'\n", inet_ntoa(wins_ip), wins_tags[t])); + + sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True); + if (sock == -1) { + continue; + } + + *return_iplist = name_query(sock,name,name_type, False, + True, wins_ip, return_count, &flags, + &timed_out); + if (*return_iplist != NULL) { + goto success; } close(sock); + + if (timed_out) { + /* Timed out wating for WINS server to respond. Mark it dead. */ + wins_srv_died(wins_ip); + } else { + /* The name definately isn't in this + group of WINS servers. goto the next group */ + break; + } } } + wins_srv_tags_free(wins_tags); return False; + +success: + wins_srv_tags_free(wins_tags); + close(sock); + return True; } /******************************************************** diff --git a/source3/nmbd/nmbd_nameregister.c b/source3/nmbd/nmbd_nameregister.c index fc16db9e49..91b6f8b190 100644 --- a/source3/nmbd/nmbd_nameregister.c +++ b/source3/nmbd/nmbd_nameregister.c @@ -155,131 +155,193 @@ name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->su remove_response_record(subrec, rrec); } + +/**************************************************************************** + Deal with a timeout of a WINS registration request +****************************************************************************/ +static void wins_registration_timeout(struct subnet_record *subrec, + struct response_record *rrec) +{ + struct userdata_struct *userdata = rrec->userdata; + + DEBUG(2,("register_name_timeout_response: WINS server at address %s is not responding.\n", + inet_ntoa(rrec->packet->ip))); + + /* mark it temporarily dead */ + wins_srv_died(rrec->packet->ip); + + /* if we have some userdata then use that to work out what + wins server to try next */ + if (userdata) { + const char *tag = (const char *)userdata->data; + struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; + struct nmb_name *nmbname = &sent_nmb->question.question_name; + + /* and try the next wins server in our failover list */ + rrec->packet->ip = wins_srv_ip_tag(tag); + + /* also update the UNICODE subnet IPs */ + subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->ip; + + DEBUG(6,("Retrying register of name %s with WINS server %s using tag '%s'\n", + nmb_namestr(nmbname), inet_ntoa(rrec->packet->ip), tag)); + } + + /* Keep trying to contact the WINS server periodically. This allows + us to work correctly if the WINS server is down temporarily when + we come up. */ + + /* Reset the number of attempts to zero and double the interval between + retries. Max out at 5 minutes. */ + rrec->repeat_count = 3; + rrec->repeat_interval *= 2; + if(rrec->repeat_interval > (5 * 60)) + rrec->repeat_interval = (5 * 60); + rrec->repeat_time = time(NULL) + rrec->repeat_interval; + rrec->in_expiration_processing = False; + + DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n", + (int)rrec->repeat_interval)); + + /* notice that we don't remove the response record. This keeps + us trying to register with each of our failover wins + servers until we succeed */ +} + + /**************************************************************************** Deal with a timeout when registering one of our names. ****************************************************************************/ static void register_name_timeout_response(struct subnet_record *subrec, - struct response_record *rrec) + struct response_record *rrec) { - /* - * If we are registering unicast, then NOT getting a response is an - * error - we do not have the name. If we are registering broadcast, - * then we don't expect to get a response. - */ + /* + * If we are registering unicast, then NOT getting a response is an + * error - we do not have the name. If we are registering broadcast, + * then we don't expect to get a response. + */ + + struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; + BOOL bcast = sent_nmb->header.nm_flags.bcast; + BOOL success = False; + struct nmb_name *question_name = &sent_nmb->question.question_name; + uint16 nb_flags = 0; + int ttl = 0; + struct in_addr registered_ip; + + if (bcast) { + if(rrec->num_msgs == 0) { + /* Not receiving a message is success for broadcast registration. */ + success = True; + + /* Pull the success values from the original request packet. */ + nb_flags = get_nb_flags(sent_nmb->additional->rdata); + ttl = sent_nmb->additional->ttl; + putip(®istered_ip,&sent_nmb->additional->rdata[2]); + } + } else { + /* Unicast - if no responses then it's an error. */ + if(rrec->num_msgs == 0) { + wins_registration_timeout(subrec, rrec); + return; + } - struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; - BOOL bcast = sent_nmb->header.nm_flags.bcast; - BOOL success = False; - struct nmb_name *question_name = &sent_nmb->question.question_name; - uint16 nb_flags = 0; - int ttl = 0; - struct in_addr registered_ip; + /* we got responses, but timed out?? bizarre. Treat it as failure. */ + } - if(bcast) - { - if(rrec->num_msgs == 0) - { - /* Not receiving a message is success for broadcast registration. */ - success = True; + DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n", + success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name)); + if(success) { + /* Enter the registered name into the subnet name database before calling + the success function. */ + standard_success_register(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip); + if( rrec->success_fn) + (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip); + } else { + if( rrec->fail_fn) + (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name); + /* Remove the name. */ + standard_fail_register( subrec, rrec, question_name); + } - /* Pull the success values from the original request packet. */ - nb_flags = get_nb_flags(sent_nmb->additional->rdata); - ttl = sent_nmb->additional->ttl; - putip(®istered_ip,&sent_nmb->additional->rdata[2]); - } - } - else - { - /* Unicast - if no responses then it's an error. */ - if(rrec->num_msgs == 0) - { - DEBUG(2,("register_name_timeout_response: WINS server at address %s is not \ -responding.\n", inet_ntoa(rrec->packet->ip))); - - /* mark it temporarily dead */ - wins_srv_died(rrec->packet->ip); - - /* and try the next wins server in our failover list */ - rrec->packet->ip = wins_srv_ip(); - - /* also update the UNICODE subnet IPs */ - subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->ip; - - /* Keep trying to contact the WINS server periodically. This allows - us to work correctly if the WINS server is down temporarily when - we come up. */ - - /* Reset the number of attempts to zero and double the interval between - retries. Max out at 5 minutes. */ - rrec->repeat_count = 3; - rrec->repeat_interval *= 2; - if(rrec->repeat_interval > (5 * 60)) - rrec->repeat_interval = (5 * 60); - rrec->repeat_time = time(NULL) + rrec->repeat_interval; - rrec->in_expiration_processing = False; - - DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n", - (int)rrec->repeat_interval)); - return; /* Don't remove the response record. */ - } - } + /* Ensure we don't retry. */ + remove_response_record(subrec, rrec); +} - DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n", - success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name)); - if(success) - { - /* Enter the registered name into the subnet name database before calling - the success function. */ - standard_success_register(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip); - if( rrec->success_fn) - (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip); - } - else - { - if( rrec->fail_fn) - (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name); - /* Remove the name. */ - standard_fail_register( subrec, rrec, question_name); - } - /* Ensure we don't retry. */ - remove_response_record(subrec, rrec); +/**************************************************************************** +initiate one multi-homed name registration packet +****************************************************************************/ +static void multihomed_register_one(struct nmb_name *nmbname, + uint16 nb_flags, + register_name_success_function success_fn, + register_name_fail_function fail_fn, + struct in_addr ip, + const char *tag) +{ + struct userdata_struct *userdata; + struct in_addr wins_ip = wins_srv_ip_tag(tag); + + userdata = (struct userdata_struct *)malloc(sizeof(*userdata) + strlen(tag) + 1); + if (!userdata) { + DEBUG(0,("Failed to allocate userdata structure!\n")); + return; + } + ZERO_STRUCTP(userdata); + userdata->userdata_len = strlen(tag) + 1; + strlcpy(userdata->data, tag, userdata->userdata_len); + + DEBUG(6,("Registering name %s with WINS server %s using tag '%s'\n", + nmb_namestr(nmbname), inet_ntoa(wins_ip), tag)); + + if (queue_register_multihomed_name(unicast_subnet, + register_name_response, + register_name_timeout_response, + success_fn, + fail_fn, + userdata, + nmbname, + nb_flags, + ip, + wins_ip) == NULL) { + DEBUG(0,("multihomed_register_one: Failed to send packet trying to register name %s IP %s\n", + nmb_namestr(nmbname), inet_ntoa(ip))); + } } /**************************************************************************** Try and register one of our names on the unicast subnet - multihomed. ****************************************************************************/ - static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags, register_name_success_function success_fn, register_name_fail_function fail_fn) { - /* - If we are adding a group name, we just send multiple - register name packets to the WINS server (this is an - internet group name. - - If we are adding a unique name, We need first to add - our names to the unicast subnet namelist. This is - because when a WINS server receives a multihomed - registration request, the first thing it does is to - send a name query to the registering machine, to see - if it has put the name in it's local namelist. - We need the name there so the query response code in - nmbd_incomingrequests.c will find it. - - We are adding this name prematurely (we don't really - have it yet), but as this is on the unicast subnet - only we will get away with this (only the WINS server - will ever query names from us on this subnet). - */ - + /* + If we are adding a group name, we just send multiple + register name packets to the WINS server (this is an + internet group name. + + If we are adding a unique name, We need first to add + our names to the unicast subnet namelist. This is + because when a WINS server receives a multihomed + registration request, the first thing it does is to + send a name query to the registering machine, to see + if it has put the name in it's local namelist. + We need the name there so the query response code in + nmbd_incomingrequests.c will find it. + + We are adding this name prematurely (we don't really + have it yet), but as this is on the unicast subnet + only we will get away with this (only the WINS server + will ever query names from us on this subnet). + */ int num_ips=0; - int i; + int i, t; struct in_addr *ip_list = NULL; struct subnet_record *subrec; - + char **wins_tags; + for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) ) num_ips++; @@ -288,7 +350,7 @@ static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags, return True; } - for( subrec = FIRST_SUBNET, i = 0; + for (subrec = FIRST_SUBNET, i = 0; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec), i++ ) { ip_list[i] = subrec->myip; @@ -298,26 +360,20 @@ static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags, nb_flags, lp_max_ttl(), SELF_NAME, num_ips, ip_list); - /* Now try and register the name, num_ips times. On the last time use - the given success and fail functions. */ - - for (i = 0; i < num_ips; i++) { - if (queue_register_multihomed_name( unicast_subnet, - register_name_response, - register_name_timeout_response, - (i == num_ips - 1) ? success_fn : NULL, - (i == num_ips - 1) ? fail_fn : NULL, - NULL, - nmbname, - nb_flags, - ip_list[i]) == NULL) { - DEBUG(0,("multihomed_register_name: Failed to send packet trying to \ -register name %s IP %s\n", nmb_namestr(nmbname), inet_ntoa(ip_list[i]) )); - - SAFE_FREE(ip_list); - return True; + /* get the list of wins tags - we try to register for each of them */ + wins_tags = wins_srv_tags(); + + /* Now try and register the name, num_ips times for each wins tag. */ + for (t=0; wins_tags[t]; t++) { + for (i = 0; i < num_ips; i++) { + multihomed_register_one(nmbname, nb_flags, + success_fn, fail_fn, + ip_list[i], + wins_tags[t]); } } + + wins_srv_tags_free(wins_tags); SAFE_FREE(ip_list); diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c index b5741caae0..f0c8b755c9 100644 --- a/source3/nmbd/nmbd_packets.c +++ b/source3/nmbd/nmbd_packets.c @@ -519,64 +519,61 @@ struct response_record *queue_register_name( struct subnet_record *subrec, } /**************************************************************************** - Queue a multihomed register name packet to the broadcast address of a subnet. + Queue a multihomed register name packet to a given WINS server IP ****************************************************************************/ struct response_record *queue_register_multihomed_name( struct subnet_record *subrec, - response_function resp_fn, - timeout_response_function timeout_fn, - register_name_success_function success_fn, - register_name_fail_function fail_fn, - struct userdata_struct *userdata, - struct nmb_name *nmbname, - uint16 nb_flags, - struct in_addr register_ip) + response_function resp_fn, + timeout_response_function timeout_fn, + register_name_success_function success_fn, + register_name_fail_function fail_fn, + struct userdata_struct *userdata, + struct nmb_name *nmbname, + uint16 nb_flags, + struct in_addr register_ip, + struct in_addr wins_ip) { - struct packet_struct *p; - struct response_record *rrec; - BOOL ret; - - /* Sanity check. */ - if(subrec != unicast_subnet) - { - DEBUG(0,("queue_register_multihomed_name: should only be done on \ + struct packet_struct *p; + struct response_record *rrec; + BOOL ret; + + /* Sanity check. */ + if(subrec != unicast_subnet) { + DEBUG(0,("queue_register_multihomed_name: should only be done on \ unicast subnet. subnet is %s\n.", subrec->subnet_name )); - return NULL; - } + return NULL; + } - if(assert_check_subnet(subrec)) - return NULL; + if(assert_check_subnet(subrec)) + return NULL; - if(( p = create_and_init_netbios_packet(nmbname, False, True, - subrec->bcast_ip)) == NULL) - return NULL; - - if (nb_flags & NB_GROUP) - ret = initiate_name_register_packet( p, nb_flags, ®ister_ip); - else - ret = initiate_multihomed_name_register_packet( p, nb_flags, ®ister_ip); - - if(ret == False) - { - p->locked = False; - free_packet(p); - return NULL; - } + if ((p = create_and_init_netbios_packet(nmbname, False, True, wins_ip)) == NULL) + return NULL; + + if (nb_flags & NB_GROUP) + ret = initiate_name_register_packet( p, nb_flags, ®ister_ip); + else + ret = initiate_multihomed_name_register_packet(p, nb_flags, ®ister_ip); + + if (ret == False) { + p->locked = False; + free_packet(p); + return NULL; + } - if((rrec = make_response_record(subrec, /* subnet record. */ - p, /* packet we sent. */ - resp_fn, /* function to call on response. */ - timeout_fn, /* function to call on timeout. */ - (success_function)success_fn, /* function to call on operation success. */ - (fail_function)fail_fn, /* function to call on operation fail. */ - userdata)) == NULL) - { - p->locked = False; - free_packet(p); - return NULL; - } - - return rrec; + if ((rrec = make_response_record(subrec, /* subnet record. */ + p, /* packet we sent. */ + resp_fn, /* function to call on response. */ + timeout_fn, /* function to call on timeout. */ + (success_function)success_fn, /* function to call on operation success. */ + (fail_function)fail_fn, /* function to call on operation fail. */ + userdata)) == NULL) { + p->locked = False; + free_packet(p); + return NULL; + } + + return rrec; } /**************************************************************************** diff --git a/source3/nsswitch/winbindd_wins.c b/source3/nsswitch/winbindd_wins.c index a8b4566ba0..75d04349e6 100644 --- a/source3/nsswitch/winbindd_wins.c +++ b/source3/nsswitch/winbindd_wins.c @@ -92,20 +92,14 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count) *count = 0; - fd = wins_lookup_open_socket_in(); - if (fd == -1) - return NULL; - - p = wins_srv_ip(); - if( !is_zero_ip(p) ) { - ret = name_query(fd,name,0x20,False,True, p, count, &flags); - goto out; + /* always try with wins first */ + if (resolve_wins(name,0x20,&ret,count)) { + return ret; } - if (lp_wins_support()) { - /* we are our own WINS server */ - ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count, &flags); - goto out; + fd = wins_lookup_open_socket_in(); + if (fd == -1) { + return NULL; } /* uggh, we have to broadcast to each interface in turn */ @@ -113,12 +107,11 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count) j >= 0; j--) { struct in_addr *bcast = iface_n_bcast(j); - ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags); + ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags, NULL); if (ret) break; } out: - close(fd); return ret; } diff --git a/source3/nsswitch/wins.c b/source3/nsswitch/wins.c index 2ecdbf1c51..8b629f1132 100644 --- a/source3/nsswitch/wins.c +++ b/source3/nsswitch/wins.c @@ -115,7 +115,7 @@ static struct node_status *lookup_byaddr_backend(char *addr, int *count) static struct in_addr *lookup_byname_backend(const char *name, int *count) { - int fd; + int fd = -1; struct in_addr *ret = NULL; struct in_addr p; int j, flags = 0; @@ -126,33 +126,24 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count) *count = 0; - fd = wins_lookup_open_socket_in(); - if (fd == -1) - return NULL; - - p = wins_srv_ip(); - if( !is_zero_ip(p) ) { - ret = name_query(fd,name,0x20,False,True, p, count, &flags); - goto out; + /* always try with wins first */ + if (resolve_wins(name,0x20,&ret,count)) { + return ret; } - if (lp_wins_support()) { - /* we are our own WINS server */ - ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count, &flags); - goto out; + fd = wins_lookup_open_socket_in(); + if (fd == -1) { + return NULL; } /* uggh, we have to broadcast to each interface in turn */ - for (j=iface_count() - 1; - j >= 0; - j--) { + for (j=iface_count() - 1;j >= 0;j--) { struct in_addr *bcast = iface_n_bcast(j); - ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags); + ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags, NULL); if (ret) break; } - out: - +out: close(fd); return ret; } diff --git a/source3/utils/nmblookup.c b/source3/utils/nmblookup.c index 2373beb0c9..8e4f5aab03 100644 --- a/source3/utils/nmblookup.c +++ b/source3/utils/nmblookup.c @@ -159,7 +159,7 @@ static BOOL query_one(char *lookup, unsigned int lookup_type) d_printf("querying %s on %s\n", lookup, inet_ntoa(bcast_addr)); ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast, use_bcast?True:recursion_desired, - bcast_addr,&count, &flags); + bcast_addr,&count, &flags, NULL); } else { struct in_addr *bcast; for (j=iface_count() - 1; @@ -171,7 +171,7 @@ static BOOL query_one(char *lookup, unsigned int lookup_type) ip_list = name_query(ServerFD,lookup,lookup_type, use_bcast, use_bcast?True:recursion_desired, - *bcast,&count, &flags); + *bcast,&count, &flags, NULL); } } diff --git a/source3/web/diagnose.c b/source3/web/diagnose.c index fa550c61b6..e822474aab 100644 --- a/source3/web/diagnose.c +++ b/source3/web/diagnose.c @@ -34,7 +34,7 @@ BOOL nmbd_running(void) interpret_addr("127.0.0.1"), True)) != -1) { if ((ip_list = name_query(fd, "__SAMBA__", 0, True, True, loopback_ip, - &count, &flags)) != NULL) { + &count, &flags, NULL)) != NULL) { SAFE_FREE(ip_list); close(fd); return True; |