xref: /titanic_44/usr/src/lib/libsmbfs/smb/nb.c (revision 8eb99b82e59bb5d07c7922dc1d9524a6bb97ebf4)
14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000, 2001 Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $Id: nb.c,v 1.1.1.2 2001/07/06 22:38:42 conrad Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
35613a2f6bSGordon Ross /*
36613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37613a2f6bSGordon Ross  * Use is subject to license terms.
38613a2f6bSGordon Ross  */
394bff34e3Sthurlow 
404bff34e3Sthurlow #include <sys/param.h>
414bff34e3Sthurlow #include <sys/socket.h>
424bff34e3Sthurlow 
434bff34e3Sthurlow #include <errno.h>
44613a2f6bSGordon Ross #include <stdio.h>
454bff34e3Sthurlow #include <stdlib.h>
464bff34e3Sthurlow #include <string.h>
474bff34e3Sthurlow #include <strings.h>
484bff34e3Sthurlow #include <unistd.h>
494bff34e3Sthurlow #include <libintl.h>
50613a2f6bSGordon Ross #include <netdb.h>
514bff34e3Sthurlow 
524bff34e3Sthurlow #include <netinet/in.h>
534bff34e3Sthurlow #include <arpa/inet.h>
544bff34e3Sthurlow 
55613a2f6bSGordon Ross #include <cflib.h>
564bff34e3Sthurlow #include <netsmb/netbios.h>
574bff34e3Sthurlow #include <netsmb/smb_lib.h>
584bff34e3Sthurlow #include <netsmb/nb_lib.h>
594bff34e3Sthurlow 
60*8eb99b82SGordon Ross void nb_ctx_setnbflags(struct nb_ctx *, int ns_ena, int bc_ena);
61613a2f6bSGordon Ross int nb_ctx_setwins(struct nb_ctx *, const char *, const char *);
62613a2f6bSGordon Ross 
63*8eb99b82SGordon Ross /*
64*8eb99b82SGordon Ross  * API for seting NetBIOS name lookup flags:
65*8eb99b82SGordon Ross  * NetBIOS name lookup enable,
66*8eb99b82SGordon Ross  * NetBIOS broadcast enable.
67*8eb99b82SGordon Ross  */
68*8eb99b82SGordon Ross int
69*8eb99b82SGordon Ross smb_ctx_setnbflags(struct smb_ctx *ctx, int ns_ena, int bc_ena)
70*8eb99b82SGordon Ross {
71*8eb99b82SGordon Ross 	struct nb_ctx *nb = ctx->ct_nb;
72*8eb99b82SGordon Ross 
73*8eb99b82SGordon Ross 	if (nb == NULL)
74*8eb99b82SGordon Ross 		return (EINVAL);
75*8eb99b82SGordon Ross 
76*8eb99b82SGordon Ross 	nb_ctx_setnbflags(nb, ns_ena, bc_ena);
77*8eb99b82SGordon Ross 	return (0);
78*8eb99b82SGordon Ross }
79613a2f6bSGordon Ross 
80613a2f6bSGordon Ross /*
81613a2f6bSGordon Ross  * API for library consumer to set wins1, wins2
82613a2f6bSGordon Ross  */
83613a2f6bSGordon Ross int
84613a2f6bSGordon Ross smb_ctx_setwins(struct smb_ctx *ctx, const char *wins1, const char *wins2)
85613a2f6bSGordon Ross {
86613a2f6bSGordon Ross 	struct nb_ctx *nb = ctx->ct_nb;
87613a2f6bSGordon Ross 
88613a2f6bSGordon Ross 	if (nb == NULL)
89613a2f6bSGordon Ross 		return (EINVAL);
90613a2f6bSGordon Ross 
91613a2f6bSGordon Ross 	return (nb_ctx_setwins(nb, wins1, wins2));
92613a2f6bSGordon Ross }
93613a2f6bSGordon Ross 
94613a2f6bSGordon Ross /*
95613a2f6bSGordon Ross  * API for library consumer to set NB scope.
96613a2f6bSGordon Ross  */
97613a2f6bSGordon Ross int
98613a2f6bSGordon Ross smb_ctx_setscope(struct smb_ctx *ctx, const char *scope)
99613a2f6bSGordon Ross {
100613a2f6bSGordon Ross 	struct nb_ctx *nb = ctx->ct_nb;
101613a2f6bSGordon Ross 
102613a2f6bSGordon Ross 	if (nb == NULL)
103613a2f6bSGordon Ross 		return (EINVAL);
104613a2f6bSGordon Ross 
105613a2f6bSGordon Ross 	return (nb_ctx_setscope(nb, scope));
106613a2f6bSGordon Ross }
1074bff34e3Sthurlow 
1084bff34e3Sthurlow int
1094bff34e3Sthurlow nb_ctx_create(struct nb_ctx **ctxpp)
1104bff34e3Sthurlow {
1114bff34e3Sthurlow 	struct nb_ctx *ctx;
1124bff34e3Sthurlow 
1134bff34e3Sthurlow 	ctx = malloc(sizeof (struct nb_ctx));
1144bff34e3Sthurlow 	if (ctx == NULL)
1154bff34e3Sthurlow 		return (ENOMEM);
1164bff34e3Sthurlow 	bzero(ctx, sizeof (struct nb_ctx));
1174bff34e3Sthurlow 	ctx->nb_flags = NBCF_NS_ENABLE | NBCF_BC_ENABLE;
1184bff34e3Sthurlow 	*ctxpp = ctx;
1194bff34e3Sthurlow 	return (0);
1204bff34e3Sthurlow }
1214bff34e3Sthurlow 
1224bff34e3Sthurlow void
1234bff34e3Sthurlow nb_ctx_done(struct nb_ctx *ctx)
1244bff34e3Sthurlow {
1254bff34e3Sthurlow 	if (ctx == NULL)
1264bff34e3Sthurlow 		return;
1274bff34e3Sthurlow 	if (ctx->nb_scope)
1284bff34e3Sthurlow 		free(ctx->nb_scope);
1294bff34e3Sthurlow 	if (ctx)
1304bff34e3Sthurlow 		free(ctx);
1314bff34e3Sthurlow }
1324bff34e3Sthurlow 
133*8eb99b82SGordon Ross void
134*8eb99b82SGordon Ross nb_ctx_setnbflags(struct nb_ctx *nb, int ns_ena, int bc_ena)
135*8eb99b82SGordon Ross {
136*8eb99b82SGordon Ross 	nb->nb_flags &= ~(NBCF_NS_ENABLE | NBCF_BC_ENABLE);
137*8eb99b82SGordon Ross 	if (ns_ena) {
138*8eb99b82SGordon Ross 		nb->nb_flags = NBCF_NS_ENABLE;
139*8eb99b82SGordon Ross 		if (bc_ena)
140*8eb99b82SGordon Ross 			nb->nb_flags = NBCF_BC_ENABLE;
141*8eb99b82SGordon Ross 	}
142*8eb99b82SGordon Ross }
143*8eb99b82SGordon Ross 
144613a2f6bSGordon Ross int
145613a2f6bSGordon Ross nb_ctx_setwins(struct nb_ctx *ctx, const char *wins1, const char *wins2)
1464bff34e3Sthurlow {
1474bff34e3Sthurlow 	struct in_addr ina;
1484bff34e3Sthurlow 	int error;
1494bff34e3Sthurlow 
150613a2f6bSGordon Ross 	if (wins1 == NULL) {
151613a2f6bSGordon Ross 		ctx->nb_wins1 = 0;
152613a2f6bSGordon Ross 		ctx->nb_wins2 = 0;
153613a2f6bSGordon Ross 		return (0);
154613a2f6bSGordon Ross 	}
1554bff34e3Sthurlow 
156613a2f6bSGordon Ross 	error = nb_resolvehost_in(wins1, &ina);
1574bff34e3Sthurlow 	if (error) {
1584bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
159613a2f6bSGordon Ross 		    error, wins1);
1604bff34e3Sthurlow 		return (error);
1614bff34e3Sthurlow 	}
162613a2f6bSGordon Ross 	ctx->nb_wins1 = ina.s_addr;
1634bff34e3Sthurlow 
164613a2f6bSGordon Ross 	if (wins2 == NULL)
165613a2f6bSGordon Ross 		ctx->nb_wins2 = 0;
166613a2f6bSGordon Ross 	else {
167613a2f6bSGordon Ross 		error = nb_resolvehost_in(wins2, &ina);
168613a2f6bSGordon Ross 		if (error) {
169613a2f6bSGordon Ross 			smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
170613a2f6bSGordon Ross 			    error, wins2);
171613a2f6bSGordon Ross 			return (error);
172613a2f6bSGordon Ross 		}
173613a2f6bSGordon Ross 		ctx->nb_wins2 = ina.s_addr;
174613a2f6bSGordon Ross 	}
1754bff34e3Sthurlow 	return (0);
1764bff34e3Sthurlow }
1774bff34e3Sthurlow 
1784bff34e3Sthurlow /*
1794bff34e3Sthurlow  * This is called by "smbutil lookup" to handle the
1804bff34e3Sthurlow  * "-w wins_server" option.  Let the semantics of
1814bff34e3Sthurlow  * this option be: Use specified WINS server only.
1824bff34e3Sthurlow  * If specified server is the broadcast address,
1834bff34e3Sthurlow  * set broadcast mode (and no WINS servers).
1844bff34e3Sthurlow  */
1854bff34e3Sthurlow int
1864bff34e3Sthurlow nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
1874bff34e3Sthurlow {
1884bff34e3Sthurlow 	int error;
1894bff34e3Sthurlow 
190613a2f6bSGordon Ross 	error = nb_ctx_setwins(ctx, addr, NULL);
1914bff34e3Sthurlow 	if (error)
1924bff34e3Sthurlow 		return (error);
1934bff34e3Sthurlow 
1944bff34e3Sthurlow 	/* Deal with explicit request for broadcast. */
1954bff34e3Sthurlow 	if (ctx->nb_wins1 == INADDR_BROADCAST) {
1964bff34e3Sthurlow 		ctx->nb_wins1 = 0;
1974bff34e3Sthurlow 		ctx->nb_flags |= NBCF_BC_ENABLE;
1984bff34e3Sthurlow 	}
1994bff34e3Sthurlow 	return (0);
2004bff34e3Sthurlow }
2014bff34e3Sthurlow 
2024bff34e3Sthurlow int
2034bff34e3Sthurlow nb_ctx_setscope(struct nb_ctx *ctx, const char *scope)
2044bff34e3Sthurlow {
2054bff34e3Sthurlow 	size_t slen = strlen(scope);
2064bff34e3Sthurlow 
2074bff34e3Sthurlow 	if (slen >= 128) {
2084bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
2094bff34e3Sthurlow 		    "scope '%s' is too long"), 0, scope);
2104bff34e3Sthurlow 		return (ENAMETOOLONG);
2114bff34e3Sthurlow 	}
2124bff34e3Sthurlow 	if (ctx->nb_scope)
2134bff34e3Sthurlow 		free(ctx->nb_scope);
2144bff34e3Sthurlow 	ctx->nb_scope = malloc(slen + 1);
2154bff34e3Sthurlow 	if (ctx->nb_scope == NULL)
2164bff34e3Sthurlow 		return (ENOMEM);
2174bff34e3Sthurlow 	nls_str_upper(ctx->nb_scope, scope);
2184bff34e3Sthurlow 	return (0);
2194bff34e3Sthurlow }
2204bff34e3Sthurlow 
2214bff34e3Sthurlow /*
2224bff34e3Sthurlow  * Now get the WINS server IP addresses directly
2234bff34e3Sthurlow  * when reading the RC files, so no longer need to
2244bff34e3Sthurlow  * lookup any names here.
2254bff34e3Sthurlow  */
2264bff34e3Sthurlow int
2274bff34e3Sthurlow nb_ctx_resolve(struct nb_ctx *ctx)
2284bff34e3Sthurlow {
2294bff34e3Sthurlow 	ctx->nb_flags |= NBCF_RESOLVED;
2304bff34e3Sthurlow 	return (0);
2314bff34e3Sthurlow }
2324bff34e3Sthurlow 
2334bff34e3Sthurlow /*
2344bff34e3Sthurlow  * used level values:
2354bff34e3Sthurlow  * 0 - default
2364bff34e3Sthurlow  * 1 - server
2374bff34e3Sthurlow  *
2384bff34e3Sthurlow  * All of these are normally system-wide settings;
2394bff34e3Sthurlow  * the checks are in rc_parse() in rcfile.c.
2404bff34e3Sthurlow  */
2414bff34e3Sthurlow int
2424bff34e3Sthurlow nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
2434bff34e3Sthurlow 	const char *sname, int level)
2444bff34e3Sthurlow {
245613a2f6bSGordon Ross 	char *wins1, *wins2;
2464bff34e3Sthurlow 	int error;
2474bff34e3Sthurlow 	int nbns_enable;
2484bff34e3Sthurlow 	int nbns_broadcast;
2494bff34e3Sthurlow 
2504bff34e3Sthurlow 	if (level > 1)
2514bff34e3Sthurlow 		return (EINVAL);
252613a2f6bSGordon Ross 
253613a2f6bSGordon Ross 	/* External callers pass NULL to get the default. */
254613a2f6bSGordon Ross 	if (rcfile == NULL)
255613a2f6bSGordon Ross 		rcfile = smb_rc;
256613a2f6bSGordon Ross 
2574bff34e3Sthurlow #ifdef NOT_DEFINED
2584bff34e3Sthurlow 	rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo);
2594bff34e3Sthurlow 	rc_getstringptr(rcfile, sname, "nbscope", &p);
2604bff34e3Sthurlow 	if (p)
2614bff34e3Sthurlow 		nb_ctx_setscope(ctx, p);
2624bff34e3Sthurlow #endif
263613a2f6bSGordon Ross 	/*
264613a2f6bSGordon Ross 	 * Get "wins1", "wins2" config strings.
265613a2f6bSGordon Ross 	 * Also support legacy "nbns".
266613a2f6bSGordon Ross 	 */
267613a2f6bSGordon Ross 	rc_getstringptr(rcfile, sname, "wins1", &wins1);
268613a2f6bSGordon Ross 	if (wins1 == NULL)
269613a2f6bSGordon Ross 		rc_getstringptr(rcfile, sname, "nbns", &wins1);
270613a2f6bSGordon Ross 	rc_getstringptr(rcfile, sname, "wins2", &wins2);
271613a2f6bSGordon Ross 
272613a2f6bSGordon Ross 	if (wins1 != NULL) {
273613a2f6bSGordon Ross 		error = nb_ctx_setwins(ctx, wins1, wins2);
2744bff34e3Sthurlow 		if (error) {
2754bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
2764bff34e3Sthurlow 			    "invalid address specified in the section %s"),
2774bff34e3Sthurlow 			    0, sname);
2784bff34e3Sthurlow 			return (error);
2794bff34e3Sthurlow 		}
2804bff34e3Sthurlow 	}
281*8eb99b82SGordon Ross 
282*8eb99b82SGordon Ross 	/*
283*8eb99b82SGordon Ross 	 * Want to use nb_ctx_setnbflags here, but
284*8eb99b82SGordon Ross 	 * have to get both boolean values first,
285*8eb99b82SGordon Ross 	 * either from settings or defaults.
286*8eb99b82SGordon Ross 	 */
287*8eb99b82SGordon Ross 	nbns_enable = nbns_broadcast = -1; /* not set */
288*8eb99b82SGordon Ross 	rc_getbool(rcfile, sname, "nbns_enable", &nbns_enable);
289*8eb99b82SGordon Ross 	rc_getbool(rcfile, sname, "nbns_broadcast", &nbns_broadcast);
290*8eb99b82SGordon Ross 	if (nbns_enable >= 0 || nbns_broadcast >= 0) {
291*8eb99b82SGordon Ross 		if (nbns_enable < 0)
292*8eb99b82SGordon Ross 			nbns_enable = 1; /* default */
293*8eb99b82SGordon Ross 		if (nbns_broadcast < 0)
294*8eb99b82SGordon Ross 			nbns_broadcast = 1; /* default */
295*8eb99b82SGordon Ross 		nb_ctx_setnbflags(ctx, nbns_enable, nbns_broadcast);
296*8eb99b82SGordon Ross 	}
2974bff34e3Sthurlow 	return (0);
2984bff34e3Sthurlow }
2994bff34e3Sthurlow 
3004bff34e3Sthurlow #ifdef I18N	/* never defined, permits xgettext(1) to pick out strings */
3014bff34e3Sthurlow static const char *nb_err_rcode[] = {
3024bff34e3Sthurlow 	gettext("bad request/response format"),
3034bff34e3Sthurlow 	gettext("NBNS server failure"),
3044bff34e3Sthurlow 	gettext("no such name"),
3054bff34e3Sthurlow 	gettext("unsupported request"),
3064bff34e3Sthurlow 	gettext("request rejected"),
3074bff34e3Sthurlow 	gettext("name already registered)"
3084bff34e3Sthurlow };
3094bff34e3Sthurlow 
3104bff34e3Sthurlow static const char *nb_err[] = {
3114bff34e3Sthurlow 	gettext("host not found"),
3124bff34e3Sthurlow 	gettext("too many redirects"),
3134bff34e3Sthurlow 	gettext("invalid response"),
3144bff34e3Sthurlow 	gettext("NETBIOS name too long"),
3154bff34e3Sthurlow 	gettext("no interface to broadcast on and no NBNS server specified")
3164bff34e3Sthurlow };
3174bff34e3Sthurlow #else
3184bff34e3Sthurlow static const char *nb_err_rcode[] = {
3194bff34e3Sthurlow 	"bad request/response format",
3204bff34e3Sthurlow 	"NBNS server failure",
3214bff34e3Sthurlow 	"no such name",
3224bff34e3Sthurlow 	"unsupported request",
3234bff34e3Sthurlow 	"request rejected",
3244bff34e3Sthurlow 	"name already registered"
3254bff34e3Sthurlow };
3264bff34e3Sthurlow 
3274bff34e3Sthurlow static const char *nb_err[] = {
3284bff34e3Sthurlow 	"host not found",
3294bff34e3Sthurlow 	"too many redirects",
3304bff34e3Sthurlow 	"invalid response",
3314bff34e3Sthurlow 	"NETBIOS name too long",
3324bff34e3Sthurlow 	"no interface to broadcast on and no NBNS server specified"
3334bff34e3Sthurlow };
3344bff34e3Sthurlow #endif
3354bff34e3Sthurlow 
3364bff34e3Sthurlow const char *
3374bff34e3Sthurlow nb_strerror(int error)
3384bff34e3Sthurlow {
3394bff34e3Sthurlow 	if (error == 0)
3404bff34e3Sthurlow 		return (NULL);
3414bff34e3Sthurlow 	if (error <= NBERR_ACTIVE)
3424bff34e3Sthurlow 		return (nb_err_rcode[error - 1]);
3434bff34e3Sthurlow 	else if (error >= NBERR_HOSTNOTFOUND && error < NBERR_MAX)
3444bff34e3Sthurlow 		return (nb_err[error - NBERR_HOSTNOTFOUND]);
3454bff34e3Sthurlow 	else
3464bff34e3Sthurlow 		return (NULL);
3474bff34e3Sthurlow }
348