Line data Source code
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 3 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, see <http://www.gnu.org/licenses/>.
20 :
21 : */
22 :
23 : #include "includes.h"
24 : #include "nmbd/nmbd.h"
25 :
26 : /****************************************************************************
27 : Deal with a response packet when releasing one of our names.
28 : ****************************************************************************/
29 :
30 0 : static void release_name_response(struct subnet_record *subrec,
31 : struct response_record *rrec, struct packet_struct *p)
32 : {
33 : /*
34 : * If we are releasing broadcast, then getting a response is an
35 : * error. If we are releasing unicast, then we expect to get a response.
36 : */
37 0 : struct nmb_packet *nmb = &p->packet.nmb;
38 0 : bool bcast = nmb->header.nm_flags.bcast;
39 0 : bool success = True;
40 0 : struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
41 0 : struct nmb_name *answer_name = &nmb->answers->rr_name;
42 : struct in_addr released_ip;
43 :
44 : /* Sanity check. Ensure that the answer name in the incoming packet is the
45 : same as the requested name in the outgoing packet. */
46 0 : if (!nmb_name_equal(question_name, answer_name)) {
47 0 : DEBUG(0,("release_name_response: Answer name %s differs from question name %s.\n",
48 : nmb_namestr(answer_name), nmb_namestr(question_name)));
49 0 : return;
50 : }
51 :
52 0 : if (bcast) {
53 : /* Someone sent a response to a bcast release? ignore it. */
54 0 : return;
55 : }
56 :
57 : /* Unicast - check to see if the response allows us to release the name. */
58 0 : if (nmb->header.rcode != 0) {
59 : /* Error code - we were told not to release the name ! What now ! */
60 0 : success = False;
61 :
62 0 : DEBUG(0,("release_name_response: WINS server at IP %s rejected our \
63 : name release of name %s with error code %d.\n",
64 : inet_ntoa(p->ip),
65 : nmb_namestr(answer_name), nmb->header.rcode));
66 0 : } else if (nmb->header.opcode == NMB_WACK_OPCODE) {
67 : /* WINS server is telling us to wait. Pretend we didn't get
68 : the response but don't send out any more release requests. */
69 :
70 0 : DEBUG(5,("release_name_response: WACK from WINS server %s in releasing \
71 : name %s on subnet %s.\n",
72 : inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name));
73 :
74 0 : rrec->repeat_count = 0;
75 : /* How long we should wait for. */
76 0 : rrec->repeat_time = p->timestamp + nmb->answers->ttl;
77 0 : rrec->num_msgs--;
78 0 : return;
79 : }
80 :
81 0 : DEBUG(5,("release_name_response: %s in releasing name %s on subnet %s.\n",
82 : success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name));
83 0 : if (success) {
84 0 : putip((char*)&released_ip ,&nmb->answers->rdata[2]);
85 :
86 0 : if(rrec->success_fn)
87 0 : (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, released_ip);
88 0 : standard_success_release( subrec, rrec->userdata, answer_name, released_ip);
89 : } else {
90 : /* We have no standard_fail_release - maybe we should add one ? */
91 0 : if (rrec->fail_fn) {
92 0 : (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, answer_name);
93 : }
94 : }
95 :
96 0 : remove_response_record(subrec, rrec);
97 : }
98 :
99 : /****************************************************************************
100 : Deal with a timeout when releasing one of our names.
101 : ****************************************************************************/
102 :
103 4 : static void release_name_timeout_response(struct subnet_record *subrec,
104 : struct response_record *rrec)
105 : {
106 : /* a release is *always* considered to be successful when it
107 : times out. This doesn't cause problems as if a WINS server
108 : doesn't respond and someone else wants the name then the
109 : normal WACK/name query from the WINS server will cope */
110 4 : struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
111 4 : bool bcast = sent_nmb->header.nm_flags.bcast;
112 4 : struct nmb_name *question_name = &sent_nmb->question.question_name;
113 : struct in_addr released_ip;
114 :
115 : /* Get the ip address we were trying to release. */
116 4 : putip((char*)&released_ip ,&sent_nmb->additional->rdata[2]);
117 :
118 4 : if (!bcast) {
119 : /* mark the WINS server temporarily dead */
120 0 : wins_srv_died(rrec->packet->ip, released_ip);
121 : }
122 :
123 4 : DEBUG(5,("release_name_timeout_response: success in releasing name %s on subnet %s.\n",
124 : nmb_namestr(question_name), subrec->subnet_name));
125 :
126 4 : if (rrec->success_fn) {
127 4 : (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, released_ip);
128 : }
129 :
130 4 : standard_success_release( subrec, rrec->userdata, question_name, released_ip);
131 4 : remove_response_record(subrec, rrec);
132 4 : }
133 :
134 :
135 : /*
136 : when releasing a name with WINS we need to send the release to each of
137 : the WINS groups
138 : */
139 0 : static void wins_release_name(struct name_record *namerec,
140 : release_name_success_function success_fn,
141 : release_name_fail_function fail_fn,
142 : struct userdata_struct *userdata)
143 : {
144 : int t, i;
145 : char **wins_tags;
146 :
147 : /* get the list of wins tags - we try to release for each of them */
148 0 : wins_tags = wins_srv_tags();
149 :
150 0 : for (t=0;wins_tags && wins_tags[t]; t++) {
151 0 : for (i = 0; i < namerec->data.num_ips; i++) {
152 0 : struct in_addr wins_ip = wins_srv_ip_tag(wins_tags[t], namerec->data.ip[i]);
153 :
154 0 : bool last_one = ((i==namerec->data.num_ips - 1) && !wins_tags[t+1]);
155 0 : if (queue_release_name(unicast_subnet,
156 : release_name_response,
157 : release_name_timeout_response,
158 : last_one?success_fn : NULL,
159 : last_one? fail_fn : NULL,
160 : last_one? userdata : NULL,
161 : &namerec->name,
162 0 : namerec->data.nb_flags,
163 0 : namerec->data.ip[i],
164 : wins_ip) == NULL) {
165 0 : DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n",
166 : nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) ));
167 : }
168 : }
169 : }
170 :
171 0 : wins_srv_tags_free(wins_tags);
172 0 : }
173 :
174 :
175 : /****************************************************************************
176 : Try and release one of our names.
177 : ****************************************************************************/
178 :
179 4 : void release_name(struct subnet_record *subrec, struct name_record *namerec,
180 : release_name_success_function success_fn,
181 : release_name_fail_function fail_fn,
182 : struct userdata_struct *userdata)
183 : {
184 : int i;
185 :
186 : /* Ensure it's a SELF name, and in the ACTIVE state. */
187 4 : if ((namerec->data.source != SELF_NAME) || !NAME_IS_ACTIVE(namerec)) {
188 0 : DEBUG(0,("release_name: Cannot release name %s from subnet %s. Source was %d \n",
189 : nmb_namestr(&namerec->name), subrec->subnet_name, namerec->data.source));
190 0 : return;
191 : }
192 :
193 : /* Set the name into the deregistering state. */
194 4 : namerec->data.nb_flags |= NB_DEREG;
195 :
196 : /* wins releases are a bit different */
197 4 : if (subrec == unicast_subnet) {
198 0 : wins_release_name(namerec, success_fn, fail_fn, userdata);
199 0 : return;
200 : }
201 :
202 : /*
203 : * Go through and release the name for all known ip addresses.
204 : * Only call the success/fail function on the last one (it should
205 : * only be done once).
206 : */
207 8 : for (i = 0; i < namerec->data.num_ips; i++) {
208 12 : if (queue_release_name(subrec,
209 : release_name_response,
210 : release_name_timeout_response,
211 4 : (i == (namerec->data.num_ips - 1)) ? success_fn : NULL,
212 4 : (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL,
213 4 : (i == (namerec->data.num_ips - 1)) ? userdata : NULL,
214 : &namerec->name,
215 4 : namerec->data.nb_flags,
216 4 : namerec->data.ip[i],
217 : subrec->bcast_ip) == NULL) {
218 0 : DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n",
219 : nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) ));
220 : }
221 : }
222 : }
|