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