2 Unix SMB/CIFS implementation.
4 "secure" wins server WACK processing
6 Copyright (C) Andrew Tridgell 2005
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "nbt_server/nbt_server.h"
25 #include "nbt_server/winsdb.h"
26 #include "system/time.h"
29 struct wins_server
*winssrv
;
30 struct nbt_name_socket
*nbtsock
;
31 struct nbt_name_packet
*request_packet
;
32 struct winsdb_record
*rec
;
33 const char *src_address
;
35 const char **owner_addresses
;
36 const char *reg_address
;
37 struct nbt_name_query query
;
42 deny a registration request
44 static void wins_wack_deny(struct wack_state
*state
)
46 nbtd_name_registration_reply(state
->nbtsock
, state
->request_packet
,
47 state
->src_address
, state
->src_port
, NBT_RCODE_ACT
);
48 DEBUG(4,("WINS: denied name registration request for %s from %s\n",
49 nbt_name_string(state
, state
->rec
->name
), state
->src_address
));
54 allow a registration request
56 static void wins_wack_allow(struct wack_state
*state
)
59 time_t now
= time(NULL
);
60 struct winsdb_record
*rec
= state
->rec
;
62 nbtd_name_registration_reply(state
->nbtsock
, state
->request_packet
,
63 state
->src_address
, state
->src_port
, NBT_RCODE_OK
);
65 rec
->addresses
= str_list_add(rec
->addresses
, state
->reg_address
);
66 if (rec
->addresses
== NULL
) goto failed
;
68 ttl
= wins_server_ttl(state
->winssrv
, state
->request_packet
->additional
[0].ttl
);
69 if (now
+ ttl
> rec
->expire_time
) {
70 rec
->expire_time
= now
+ ttl
;
72 rec
->registered_by
= state
->src_address
;
74 winsdb_modify(state
->winssrv
, rec
);
76 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
77 nbt_name_string(state
, rec
->name
), state
->reg_address
));
84 called when a name query to a current owner completes
86 static void wins_wack_handler(struct nbt_name_request
*req
)
88 struct wack_state
*state
= talloc_get_type(req
->async
.private, struct wack_state
);
91 struct winsdb_record
*rec
= state
->rec
;
93 status
= nbt_name_query_recv(req
, state
, &state
->query
);
95 /* if we timed out then try the next owner address, if any */
96 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
97 state
->owner_addresses
++;
98 if (state
->owner_addresses
[0] == NULL
) {
99 wins_wack_allow(state
);
102 state
->query
.in
.dest_addr
= state
->owner_addresses
[0];
104 req
= nbt_name_query_send(state
->nbtsock
, &state
->query
);
105 if (req
== NULL
) goto failed
;
107 req
->async
.fn
= wins_wack_handler
;
108 req
->async
.private = state
;
112 /* if the owner denies it holds the name, then allow
114 if (!NT_STATUS_IS_OK(status
)) {
115 wins_wack_allow(state
);
119 /* if the owner still wants the name and doesn't reply
120 with the address trying to be registered, then deny
122 if (!str_list_check(state
->query
.out
.reply_addrs
, state
->reg_address
)) {
123 wins_wack_deny(state
);
127 /* we are going to allow the registration, but first remove any addresses
128 from the record that aren't in the reply from the client */
129 for (i
=0;rec
->addresses
[i
];) {
130 if (!str_list_check(state
->query
.out
.reply_addrs
, rec
->addresses
[i
])) {
131 str_list_remove(rec
->addresses
, rec
->addresses
[i
]);
137 wins_wack_allow(state
);
146 a client has asked to register a unique name that someone else owns. We
147 need to ask each of the current owners if they still want it. If they do
148 then reject the registration, otherwise allow it
150 void wins_register_wack(struct nbt_name_socket
*nbtsock
,
151 struct nbt_name_packet
*packet
,
152 struct winsdb_record
*rec
,
153 const char *src_address
, int src_port
)
155 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private,
156 struct nbtd_interface
);
157 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
158 struct wack_state
*state
;
159 struct nbt_name_request
*req
;
162 state
= talloc(nbtsock
, struct wack_state
);
163 if (state
== NULL
) goto failed
;
165 /* package up the state variables for this wack request */
166 state
->winssrv
= winssrv
;
167 state
->nbtsock
= nbtsock
;
168 state
->request_packet
= talloc_steal(state
, packet
);
169 state
->rec
= talloc_steal(state
, rec
);
170 state
->src_port
= src_port
;
171 state
->owner_addresses
= rec
->addresses
;
172 state
->reg_address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
173 state
->src_address
= talloc_strdup(state
, src_address
);
174 if (state
->src_address
== NULL
) goto failed
;
176 /* setup a name query to the first address */
177 state
->query
.in
.name
= *rec
->name
;
178 state
->query
.in
.dest_addr
= state
->owner_addresses
[0];
179 state
->query
.in
.broadcast
= False
;
180 state
->query
.in
.wins_lookup
= True
;
181 state
->query
.in
.timeout
= 1;
182 state
->query
.in
.retries
= 2;
184 /* the LOGON type is a nasty hack */
185 if (rec
->name
->type
== NBT_NAME_LOGON
) {
186 wins_wack_allow(state
);
190 /* send a WACK to the client, specifying the maximum time it could
191 take to check with the owner, plus some slack */
192 ttl
= 5 + 4 * str_list_length(rec
->addresses
);
193 nbtd_wack_reply(nbtsock
, packet
, src_address
, src_port
, ttl
);
195 req
= nbt_name_query_send(nbtsock
, &state
->query
);
196 if (req
== NULL
) goto failed
;
198 req
->async
.fn
= wins_wack_handler
;
199 req
->async
.private = state
;
204 nbtd_name_registration_reply(nbtsock
, packet
, src_address
, src_port
, NBT_RCODE_SVR
);