xref: /illumos-gate/usr/src/lib/libsmbfs/smb/nb.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2009 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 
60 void nb_ctx_setnbflags(struct nb_ctx *, int ns_ena, int bc_ena);
61 int 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  */
68 int
69 smb_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  */
83 int
84 smb_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  */
97 int
98 smb_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 
108 int
109 nb_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 	ctx->nb_flags = NBCF_NS_ENABLE | NBCF_BC_ENABLE;
118 	*ctxpp = ctx;
119 	return (0);
120 }
121 
122 void
123 nb_ctx_done(struct nb_ctx *ctx)
124 {
125 	if (ctx == NULL)
126 		return;
127 	if (ctx->nb_scope)
128 		free(ctx->nb_scope);
129 	if (ctx)
130 		free(ctx);
131 }
132 
133 void
134 nb_ctx_setnbflags(struct nb_ctx *nb, int ns_ena, int bc_ena)
135 {
136 	nb->nb_flags &= ~(NBCF_NS_ENABLE | NBCF_BC_ENABLE);
137 	if (ns_ena) {
138 		nb->nb_flags = NBCF_NS_ENABLE;
139 		if (bc_ena)
140 			nb->nb_flags = NBCF_BC_ENABLE;
141 	}
142 }
143 
144 int
145 nb_ctx_setwins(struct nb_ctx *ctx, const char *wins1, const char *wins2)
146 {
147 	struct in_addr ina;
148 	int error;
149 
150 	if (wins1 == NULL) {
151 		ctx->nb_wins1 = 0;
152 		ctx->nb_wins2 = 0;
153 		return (0);
154 	}
155 
156 	error = nb_resolvehost_in(wins1, &ina);
157 	if (error) {
158 		smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
159 		    error, wins1);
160 		return (error);
161 	}
162 	ctx->nb_wins1 = ina.s_addr;
163 
164 	if (wins2 == NULL)
165 		ctx->nb_wins2 = 0;
166 	else {
167 		error = nb_resolvehost_in(wins2, &ina);
168 		if (error) {
169 			smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
170 			    error, wins2);
171 			return (error);
172 		}
173 		ctx->nb_wins2 = ina.s_addr;
174 	}
175 	return (0);
176 }
177 
178 /*
179  * This is called by "smbutil lookup" to handle the
180  * "-w wins_server" option.  Let the semantics of
181  * this option be: Use specified WINS server only.
182  * If specified server is the broadcast address,
183  * set broadcast mode (and no WINS servers).
184  */
185 int
186 nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
187 {
188 	int error;
189 
190 	error = nb_ctx_setwins(ctx, addr, NULL);
191 	if (error)
192 		return (error);
193 
194 	/* Deal with explicit request for broadcast. */
195 	if (ctx->nb_wins1 == INADDR_BROADCAST) {
196 		ctx->nb_wins1 = 0;
197 		ctx->nb_flags |= NBCF_BC_ENABLE;
198 	}
199 	return (0);
200 }
201 
202 int
203 nb_ctx_setscope(struct nb_ctx *ctx, const char *scope)
204 {
205 	size_t slen = strlen(scope);
206 
207 	if (slen >= 128) {
208 		smb_error(dgettext(TEXT_DOMAIN,
209 		    "scope '%s' is too long"), 0, scope);
210 		return (ENAMETOOLONG);
211 	}
212 	if (ctx->nb_scope)
213 		free(ctx->nb_scope);
214 	ctx->nb_scope = malloc(slen + 1);
215 	if (ctx->nb_scope == NULL)
216 		return (ENOMEM);
217 	nls_str_upper(ctx->nb_scope, scope);
218 	return (0);
219 }
220 
221 /*
222  * Now get the WINS server IP addresses directly
223  * when reading the RC files, so no longer need to
224  * lookup any names here.
225  */
226 int
227 nb_ctx_resolve(struct nb_ctx *ctx)
228 {
229 	ctx->nb_flags |= NBCF_RESOLVED;
230 	return (0);
231 }
232 
233 /*
234  * used level values:
235  * 0 - default
236  * 1 - server
237  *
238  * All of these are normally system-wide settings;
239  * the checks are in rc_parse() in rcfile.c.
240  */
241 int
242 nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
243 	const char *sname, int level)
244 {
245 	char *wins1, *wins2;
246 	int error;
247 	int nbns_enable;
248 	int nbns_broadcast;
249 
250 	if (level > 1)
251 		return (EINVAL);
252 
253 	/* External callers pass NULL to get the default. */
254 	if (rcfile == NULL)
255 		rcfile = smb_rc;
256 
257 #ifdef NOT_DEFINED
258 	rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo);
259 	rc_getstringptr(rcfile, sname, "nbscope", &p);
260 	if (p)
261 		nb_ctx_setscope(ctx, p);
262 #endif
263 	/*
264 	 * Get "wins1", "wins2" config strings.
265 	 * Also support legacy "nbns".
266 	 */
267 	rc_getstringptr(rcfile, sname, "wins1", &wins1);
268 	if (wins1 == NULL)
269 		rc_getstringptr(rcfile, sname, "nbns", &wins1);
270 	rc_getstringptr(rcfile, sname, "wins2", &wins2);
271 
272 	if (wins1 != NULL) {
273 		error = nb_ctx_setwins(ctx, wins1, wins2);
274 		if (error) {
275 			smb_error(dgettext(TEXT_DOMAIN,
276 			    "invalid address specified in the section %s"),
277 			    0, sname);
278 			return (error);
279 		}
280 	}
281 
282 	/*
283 	 * Want to use nb_ctx_setnbflags here, but
284 	 * have to get both boolean values first,
285 	 * either from settings or defaults.
286 	 */
287 	nbns_enable = nbns_broadcast = -1; /* not set */
288 	rc_getbool(rcfile, sname, "nbns_enable", &nbns_enable);
289 	rc_getbool(rcfile, sname, "nbns_broadcast", &nbns_broadcast);
290 	if (nbns_enable >= 0 || nbns_broadcast >= 0) {
291 		if (nbns_enable < 0)
292 			nbns_enable = 1; /* default */
293 		if (nbns_broadcast < 0)
294 			nbns_broadcast = 1; /* default */
295 		nb_ctx_setnbflags(ctx, nbns_enable, nbns_broadcast);
296 	}
297 	return (0);
298 }
299 
300 #ifdef I18N	/* never defined, permits xgettext(1) to pick out strings */
301 static const char *nb_err_rcode[] = {
302 	gettext("bad request/response format"),
303 	gettext("NBNS server failure"),
304 	gettext("no such name"),
305 	gettext("unsupported request"),
306 	gettext("request rejected"),
307 	gettext("name already registered)"
308 };
309 
310 static const char *nb_err[] = {
311 	gettext("host not found"),
312 	gettext("too many redirects"),
313 	gettext("invalid response"),
314 	gettext("NETBIOS name too long"),
315 	gettext("no interface to broadcast on and no NBNS server specified")
316 };
317 #else
318 static const char *nb_err_rcode[] = {
319 	"bad request/response format",
320 	"NBNS server failure",
321 	"no such name",
322 	"unsupported request",
323 	"request rejected",
324 	"name already registered"
325 };
326 
327 static const char *nb_err[] = {
328 	"host not found",
329 	"too many redirects",
330 	"invalid response",
331 	"NETBIOS name too long",
332 	"no interface to broadcast on and no NBNS server specified"
333 };
334 #endif
335 
336 const char *
337 nb_strerror(int error)
338 {
339 	if (error == 0)
340 		return (NULL);
341 	if (error <= NBERR_ACTIVE)
342 		return (nb_err_rcode[error - 1]);
343 	else if (error >= NBERR_HOSTNOTFOUND && error < NBERR_MAX)
344 		return (nb_err[error - NBERR_HOSTNOTFOUND]);
345 	else
346 		return (NULL);
347 }
348