xref: /titanic_50/usr/src/lib/libsmbfs/smb/nb.c (revision dd9e16da4243358c2e9251a4ca5d50f56e0adc68)
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 int nb_ctx_setwins(struct nb_ctx *, const char *, const char *);
61 
62 
63 /*
64  * API for library consumer to set wins1, wins2
65  */
66 int
67 smb_ctx_setwins(struct smb_ctx *ctx, const char *wins1, const char *wins2)
68 {
69 	struct nb_ctx *nb = ctx->ct_nb;
70 
71 	if (nb == NULL)
72 		return (EINVAL);
73 
74 	return (nb_ctx_setwins(nb, wins1, wins2));
75 }
76 
77 /*
78  * API for library consumer to set NB scope.
79  */
80 int
81 smb_ctx_setscope(struct smb_ctx *ctx, const char *scope)
82 {
83 	struct nb_ctx *nb = ctx->ct_nb;
84 
85 	if (nb == NULL)
86 		return (EINVAL);
87 
88 	return (nb_ctx_setscope(nb, scope));
89 }
90 
91 int
92 nb_ctx_create(struct nb_ctx **ctxpp)
93 {
94 	struct nb_ctx *ctx;
95 
96 	ctx = malloc(sizeof (struct nb_ctx));
97 	if (ctx == NULL)
98 		return (ENOMEM);
99 	bzero(ctx, sizeof (struct nb_ctx));
100 	ctx->nb_flags = NBCF_NS_ENABLE | NBCF_BC_ENABLE;
101 	*ctxpp = ctx;
102 	return (0);
103 }
104 
105 void
106 nb_ctx_done(struct nb_ctx *ctx)
107 {
108 	if (ctx == NULL)
109 		return;
110 	if (ctx->nb_scope)
111 		free(ctx->nb_scope);
112 	if (ctx)
113 		free(ctx);
114 }
115 
116 int
117 nb_ctx_setwins(struct nb_ctx *ctx, const char *wins1, const char *wins2)
118 {
119 	struct in_addr ina;
120 	int error;
121 
122 	if (wins1 == NULL) {
123 		ctx->nb_wins1 = 0;
124 		ctx->nb_wins2 = 0;
125 		return (0);
126 	}
127 
128 	error = nb_resolvehost_in(wins1, &ina);
129 	if (error) {
130 		smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
131 		    error, wins1);
132 		return (error);
133 	}
134 	ctx->nb_wins1 = ina.s_addr;
135 
136 	if (wins2 == NULL)
137 		ctx->nb_wins2 = 0;
138 	else {
139 		error = nb_resolvehost_in(wins2, &ina);
140 		if (error) {
141 			smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
142 			    error, wins2);
143 			return (error);
144 		}
145 		ctx->nb_wins2 = ina.s_addr;
146 	}
147 	return (0);
148 }
149 
150 /*
151  * This is called by "smbutil lookup" to handle the
152  * "-w wins_server" option.  Let the semantics of
153  * this option be: Use specified WINS server only.
154  * If specified server is the broadcast address,
155  * set broadcast mode (and no WINS servers).
156  */
157 int
158 nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
159 {
160 	int error;
161 
162 	error = nb_ctx_setwins(ctx, addr, NULL);
163 	if (error)
164 		return (error);
165 
166 	/* Deal with explicit request for broadcast. */
167 	if (ctx->nb_wins1 == INADDR_BROADCAST) {
168 		ctx->nb_wins1 = 0;
169 		ctx->nb_flags |= NBCF_BC_ENABLE;
170 	}
171 	return (0);
172 }
173 
174 int
175 nb_ctx_setscope(struct nb_ctx *ctx, const char *scope)
176 {
177 	size_t slen = strlen(scope);
178 
179 	if (slen >= 128) {
180 		smb_error(dgettext(TEXT_DOMAIN,
181 		    "scope '%s' is too long"), 0, scope);
182 		return (ENAMETOOLONG);
183 	}
184 	if (ctx->nb_scope)
185 		free(ctx->nb_scope);
186 	ctx->nb_scope = malloc(slen + 1);
187 	if (ctx->nb_scope == NULL)
188 		return (ENOMEM);
189 	nls_str_upper(ctx->nb_scope, scope);
190 	return (0);
191 }
192 
193 /*
194  * Now get the WINS server IP addresses directly
195  * when reading the RC files, so no longer need to
196  * lookup any names here.
197  */
198 int
199 nb_ctx_resolve(struct nb_ctx *ctx)
200 {
201 	ctx->nb_flags |= NBCF_RESOLVED;
202 	return (0);
203 }
204 
205 /*
206  * used level values:
207  * 0 - default
208  * 1 - server
209  *
210  * All of these are normally system-wide settings;
211  * the checks are in rc_parse() in rcfile.c.
212  */
213 int
214 nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
215 	const char *sname, int level)
216 {
217 	char *wins1, *wins2;
218 	int error;
219 	int nbns_enable;
220 	int nbns_broadcast;
221 
222 	if (level > 1)
223 		return (EINVAL);
224 
225 	/* External callers pass NULL to get the default. */
226 	if (rcfile == NULL)
227 		rcfile = smb_rc;
228 
229 #ifdef NOT_DEFINED
230 	rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo);
231 	rc_getstringptr(rcfile, sname, "nbscope", &p);
232 	if (p)
233 		nb_ctx_setscope(ctx, p);
234 #endif
235 	/*
236 	 * Get "wins1", "wins2" config strings.
237 	 * Also support legacy "nbns".
238 	 */
239 	rc_getstringptr(rcfile, sname, "wins1", &wins1);
240 	if (wins1 == NULL)
241 		rc_getstringptr(rcfile, sname, "nbns", &wins1);
242 	rc_getstringptr(rcfile, sname, "wins2", &wins2);
243 
244 	if (wins1 != NULL) {
245 		error = nb_ctx_setwins(ctx, wins1, wins2);
246 		if (error) {
247 			smb_error(dgettext(TEXT_DOMAIN,
248 			    "invalid address specified in the section %s"),
249 			    0, sname);
250 			return (error);
251 		}
252 	}
253 	error = rc_getbool(rcfile, sname, "nbns_enable", &nbns_enable);
254 	if (error == 0 && nbns_enable == 0)
255 		ctx->nb_flags &= ~NBCF_NS_ENABLE;
256 	error = rc_getbool(rcfile, sname, "nbns_broadcast", &nbns_broadcast);
257 	if (error == 0 && nbns_broadcast == 0)
258 		ctx->nb_flags &= ~NBCF_BC_ENABLE;
259 	return (0);
260 }
261 
262 #ifdef I18N	/* never defined, permits xgettext(1) to pick out strings */
263 static const char *nb_err_rcode[] = {
264 	gettext("bad request/response format"),
265 	gettext("NBNS server failure"),
266 	gettext("no such name"),
267 	gettext("unsupported request"),
268 	gettext("request rejected"),
269 	gettext("name already registered)"
270 };
271 
272 static const char *nb_err[] = {
273 	gettext("host not found"),
274 	gettext("too many redirects"),
275 	gettext("invalid response"),
276 	gettext("NETBIOS name too long"),
277 	gettext("no interface to broadcast on and no NBNS server specified")
278 };
279 #else
280 static const char *nb_err_rcode[] = {
281 	"bad request/response format",
282 	"NBNS server failure",
283 	"no such name",
284 	"unsupported request",
285 	"request rejected",
286 	"name already registered"
287 };
288 
289 static const char *nb_err[] = {
290 	"host not found",
291 	"too many redirects",
292 	"invalid response",
293 	"NETBIOS name too long",
294 	"no interface to broadcast on and no NBNS server specified"
295 };
296 #endif
297 
298 const char *
299 nb_strerror(int error)
300 {
301 	if (error == 0)
302 		return (NULL);
303 	if (error <= NBERR_ACTIVE)
304 		return (nb_err_rcode[error - 1]);
305 	else if (error >= NBERR_HOSTNOTFOUND && error < NBERR_MAX)
306 		return (nb_err[error - NBERR_HOSTNOTFOUND]);
307 	else
308 		return (NULL);
309 }
310