1/*
2 * Copyright (c) 2000, 2001 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *    This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: nb.c,v 1.1.1.2 2001/07/06 22:38:42 conrad Exp $
33 */
34
35/*
36 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
37 * Use is subject to license terms.
38 */
39
40#include <sys/param.h>
41#include <sys/socket.h>
42
43#include <errno.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <strings.h>
48#include <unistd.h>
49#include <libintl.h>
50#include <netdb.h>
51
52#include <netinet/in.h>
53#include <arpa/inet.h>
54
55#include <cflib.h>
56#include <netsmb/netbios.h>
57#include <netsmb/smb_lib.h>
58#include <netsmb/nb_lib.h>
59
60void nb_ctx_setnbflags(struct nb_ctx *, int ns_ena, int bc_ena);
61int nb_ctx_setwins(struct nb_ctx *, const char *, const char *);
62
63/*
64 * API for seting NetBIOS name lookup flags:
65 * NetBIOS name lookup enable,
66 * NetBIOS broadcast enable.
67 */
68int
69smb_ctx_setnbflags(struct smb_ctx *ctx, int ns_ena, int bc_ena)
70{
71	struct nb_ctx *nb = ctx->ct_nb;
72
73	if (nb == NULL)
74		return (EINVAL);
75
76	nb_ctx_setnbflags(nb, ns_ena, bc_ena);
77	return (0);
78}
79
80/*
81 * API for library consumer to set wins1, wins2
82 */
83int
84smb_ctx_setwins(struct smb_ctx *ctx, const char *wins1, const char *wins2)
85{
86	struct nb_ctx *nb = ctx->ct_nb;
87
88	if (nb == NULL)
89		return (EINVAL);
90
91	return (nb_ctx_setwins(nb, wins1, wins2));
92}
93
94/*
95 * API for library consumer to set NB scope.
96 */
97int
98smb_ctx_setscope(struct smb_ctx *ctx, const char *scope)
99{
100	struct nb_ctx *nb = ctx->ct_nb;
101
102	if (nb == NULL)
103		return (EINVAL);
104
105	return (nb_ctx_setscope(nb, scope));
106}
107
108int
109nb_ctx_create(struct nb_ctx **ctxpp)
110{
111	struct nb_ctx *ctx;
112
113	ctx = malloc(sizeof (struct nb_ctx));
114	if (ctx == NULL)
115		return (ENOMEM);
116	bzero(ctx, sizeof (struct nb_ctx));
117	*ctxpp = ctx;
118	return (0);
119}
120
121void
122nb_ctx_done(struct nb_ctx *ctx)
123{
124	if (ctx == NULL)
125		return;
126	if (ctx->nb_scope)
127		free(ctx->nb_scope);
128	if (ctx)
129		free(ctx);
130}
131
132void
133nb_ctx_setnbflags(struct nb_ctx *nb, int ns_ena, int bc_ena)
134{
135	nb->nb_flags &= ~(NBCF_NS_ENABLE | NBCF_BC_ENABLE);
136	if (ns_ena) {
137		nb->nb_flags |= NBCF_NS_ENABLE;
138		if (bc_ena)
139			nb->nb_flags |= NBCF_BC_ENABLE;
140	}
141}
142
143int
144nb_ctx_setwins(struct nb_ctx *ctx, const char *wins1, const char *wins2)
145{
146	struct in_addr ina;
147	int error;
148
149	if (wins1 == NULL) {
150		ctx->nb_wins1 = 0;
151		ctx->nb_wins2 = 0;
152		return (0);
153	}
154
155	error = nb_resolvehost_in(wins1, &ina);
156	if (error) {
157		smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
158		    error, wins1);
159		return (error);
160	}
161	ctx->nb_wins1 = ina.s_addr;
162
163	if (wins2 == NULL)
164		ctx->nb_wins2 = 0;
165	else {
166		error = nb_resolvehost_in(wins2, &ina);
167		if (error) {
168			smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
169			    error, wins2);
170			return (error);
171		}
172		ctx->nb_wins2 = ina.s_addr;
173	}
174	return (0);
175}
176
177/*
178 * This is called by "smbutil lookup" to handle the
179 * "-w wins_server" option.  Let the semantics of
180 * this option be: Use specified WINS server only.
181 * If specified server is the broadcast address,
182 * set broadcast mode (and no WINS servers).
183 */
184int
185nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
186{
187	int error;
188
189	error = nb_ctx_setwins(ctx, addr, NULL);
190	if (error)
191		return (error);
192
193	/* Deal with explicit request for broadcast. */
194	if (ctx->nb_wins1 == INADDR_BROADCAST) {
195		ctx->nb_wins1 = 0;
196		ctx->nb_flags |= NBCF_BC_ENABLE;
197	}
198	return (0);
199}
200
201int
202nb_ctx_setscope(struct nb_ctx *ctx, const char *scope)
203{
204	size_t slen = strlen(scope);
205
206	if (slen >= 128) {
207		smb_error(dgettext(TEXT_DOMAIN,
208		    "scope '%s' is too long"), 0, scope);
209		return (ENAMETOOLONG);
210	}
211	if (ctx->nb_scope)
212		free(ctx->nb_scope);
213	ctx->nb_scope = malloc(slen + 1);
214	if (ctx->nb_scope == NULL)
215		return (ENOMEM);
216	nls_str_upper(ctx->nb_scope, scope);
217	return (0);
218}
219
220/*
221 * Now get the WINS server IP addresses directly
222 * when reading the RC files, so no longer need to
223 * lookup any names here.
224 */
225int
226nb_ctx_resolve(struct nb_ctx *ctx)
227{
228	ctx->nb_flags |= NBCF_RESOLVED;
229	return (0);
230}
231
232/*
233 * used level values:
234 * 0 - default
235 * 1 - server
236 *
237 * All of these are normally system-wide settings;
238 * the checks are in rc_parse() in rcfile.c.
239 */
240int
241nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
242	const char *sname, int level)
243{
244	char *wins1, *wins2;
245	int error;
246	int nbns_enable;
247	int nbns_broadcast;
248
249	if (level > 1)
250		return (EINVAL);
251
252	/* External callers pass NULL to get the default. */
253	if (rcfile == NULL)
254		rcfile = smb_rc;
255
256#ifdef NOT_DEFINED
257	rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo);
258	rc_getstringptr(rcfile, sname, "nbscope", &p);
259	if (p)
260		nb_ctx_setscope(ctx, p);
261#endif
262	/*
263	 * Get "wins1", "wins2" config strings.
264	 * Also support legacy "nbns".
265	 */
266	rc_getstringptr(rcfile, sname, "wins1", &wins1);
267	if (wins1 == NULL)
268		rc_getstringptr(rcfile, sname, "nbns", &wins1);
269	rc_getstringptr(rcfile, sname, "wins2", &wins2);
270
271	if (wins1 != NULL) {
272		error = nb_ctx_setwins(ctx, wins1, wins2);
273		if (error) {
274			smb_error(dgettext(TEXT_DOMAIN,
275			    "invalid address specified in the section %s"),
276			    0, sname);
277			return (error);
278		}
279	}
280
281	/*
282	 * Want to use nb_ctx_setnbflags here, but
283	 * have to get both boolean values first,
284	 * either from settings or defaults.
285	 */
286	nbns_enable = nbns_broadcast = 1; /* defaults */
287	rc_getbool(rcfile, sname, "nbns_enable", &nbns_enable);
288	rc_getbool(rcfile, sname, "nbns_broadcast", &nbns_broadcast);
289	nb_ctx_setnbflags(ctx, nbns_enable, nbns_broadcast);
290
291	return (0);
292}
293
294#ifdef I18N	/* never defined, permits xgettext(1) to pick out strings */
295static const char *nb_err_rcode[] = {
296	gettext("bad request/response format"),
297	gettext("NBNS server failure"),
298	gettext("no such name"),
299	gettext("unsupported request"),
300	gettext("request rejected"),
301	gettext("name already registered)"
302};
303
304static const char *nb_err[] = {
305	gettext("host not found"),
306	gettext("too many redirects"),
307	gettext("invalid response"),
308	gettext("NETBIOS name too long"),
309	gettext("no interface to broadcast on and no NBNS server specified")
310};
311#else
312static const char *nb_err_rcode[] = {
313	"bad request/response format",
314	"NBNS server failure",
315	"no such name",
316	"unsupported request",
317	"request rejected",
318	"name already registered"
319};
320
321static const char *nb_err[] = {
322	"host not found",
323	"too many redirects",
324	"invalid response",
325	"NETBIOS name too long",
326	"no interface to broadcast on and no NBNS server specified"
327};
328#endif
329
330const char *
331nb_strerror(int error)
332{
333	if (error == 0)
334		return (NULL);
335	if (error <= NBERR_ACTIVE)
336		return (nb_err_rcode[error - 1]);
337	else if (error >= NBERR_HOSTNOTFOUND && error < NBERR_MAX)
338		return (nb_err[error - NBERR_HOSTNOTFOUND]);
339	else
340		return (NULL);
341}
342