xref: /illumos-gate/usr/src/lib/libsmbfs/smb/nb.c (revision 42d15982)
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 
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
smb_ctx_setnbflags(struct smb_ctx * ctx,int ns_ena,int bc_ena)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
smb_ctx_setwins(struct smb_ctx * ctx,const char * wins1,const char * wins2)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
smb_ctx_setscope(struct smb_ctx * ctx,const char * scope)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
nb_ctx_create(struct nb_ctx ** ctxpp)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 	*ctxpp = ctx;
118 	return (0);
119 }
120 
121 void
nb_ctx_done(struct nb_ctx * ctx)122 nb_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 
132 void
nb_ctx_setnbflags(struct nb_ctx * nb,int ns_ena,int bc_ena)133 nb_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 
143 int
nb_ctx_setwins(struct nb_ctx * ctx,const char * wins1,const char * wins2)144 nb_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  */
184 int
nb_ctx_setns(struct nb_ctx * ctx,const char * addr)185 nb_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 
201 int
nb_ctx_setscope(struct nb_ctx * ctx,const char * scope)202 nb_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  */
225 int
nb_ctx_resolve(struct nb_ctx * ctx)226 nb_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  */
240 int
nb_ctx_readrcsection(struct rcfile * rcfile,struct nb_ctx * ctx,const char * sname,int level)241 nb_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 */
295 static 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 
304 static 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
312 static 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 
321 static 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 
330 const char *
331 nb_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