xref: /illumos-gate/usr/src/lib/libsmbfs/smb/nb.c (revision 42d15982)
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 /*
36*42d15982SGordon Ross  * Copyright 2010 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 
608eb99b82SGordon 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 
638eb99b82SGordon Ross /*
648eb99b82SGordon Ross  * API for seting NetBIOS name lookup flags:
658eb99b82SGordon Ross  * NetBIOS name lookup enable,
668eb99b82SGordon Ross  * NetBIOS broadcast enable.
678eb99b82SGordon Ross  */
688eb99b82SGordon Ross int
smb_ctx_setnbflags(struct smb_ctx * ctx,int ns_ena,int bc_ena)698eb99b82SGordon Ross smb_ctx_setnbflags(struct smb_ctx *ctx, int ns_ena, int bc_ena)
708eb99b82SGordon Ross {
718eb99b82SGordon Ross 	struct nb_ctx *nb = ctx->ct_nb;
728eb99b82SGordon Ross 
738eb99b82SGordon Ross 	if (nb == NULL)
748eb99b82SGordon Ross 		return (EINVAL);
758eb99b82SGordon Ross 
768eb99b82SGordon Ross 	nb_ctx_setnbflags(nb, ns_ena, bc_ena);
778eb99b82SGordon Ross 	return (0);
788eb99b82SGordon Ross }
79613a2f6bSGordon Ross 
80613a2f6bSGordon Ross /*
81613a2f6bSGordon Ross  * API for library consumer to set wins1, wins2
82613a2f6bSGordon Ross  */
83613a2f6bSGordon Ross int
smb_ctx_setwins(struct smb_ctx * ctx,const char * wins1,const char * wins2)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
smb_ctx_setscope(struct smb_ctx * ctx,const char * scope)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
nb_ctx_create(struct nb_ctx ** ctxpp)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 	*ctxpp = ctx;
1184bff34e3Sthurlow 	return (0);
1194bff34e3Sthurlow }
1204bff34e3Sthurlow 
1214bff34e3Sthurlow void
nb_ctx_done(struct nb_ctx * ctx)1224bff34e3Sthurlow nb_ctx_done(struct nb_ctx *ctx)
1234bff34e3Sthurlow {
1244bff34e3Sthurlow 	if (ctx == NULL)
1254bff34e3Sthurlow 		return;
1264bff34e3Sthurlow 	if (ctx->nb_scope)
1274bff34e3Sthurlow 		free(ctx->nb_scope);
1284bff34e3Sthurlow 	if (ctx)
1294bff34e3Sthurlow 		free(ctx);
1304bff34e3Sthurlow }
1314bff34e3Sthurlow 
1328eb99b82SGordon Ross void
nb_ctx_setnbflags(struct nb_ctx * nb,int ns_ena,int bc_ena)1338eb99b82SGordon Ross nb_ctx_setnbflags(struct nb_ctx *nb, int ns_ena, int bc_ena)
1348eb99b82SGordon Ross {
1358eb99b82SGordon Ross 	nb->nb_flags &= ~(NBCF_NS_ENABLE | NBCF_BC_ENABLE);
1368eb99b82SGordon Ross 	if (ns_ena) {
137*42d15982SGordon Ross 		nb->nb_flags |= NBCF_NS_ENABLE;
1388eb99b82SGordon Ross 		if (bc_ena)
139*42d15982SGordon Ross 			nb->nb_flags |= NBCF_BC_ENABLE;
1408eb99b82SGordon Ross 	}
1418eb99b82SGordon Ross }
1428eb99b82SGordon Ross 
143613a2f6bSGordon Ross int
nb_ctx_setwins(struct nb_ctx * ctx,const char * wins1,const char * wins2)144613a2f6bSGordon Ross nb_ctx_setwins(struct nb_ctx *ctx, const char *wins1, const char *wins2)
1454bff34e3Sthurlow {
1464bff34e3Sthurlow 	struct in_addr ina;
1474bff34e3Sthurlow 	int error;
1484bff34e3Sthurlow 
149613a2f6bSGordon Ross 	if (wins1 == NULL) {
150613a2f6bSGordon Ross 		ctx->nb_wins1 = 0;
151613a2f6bSGordon Ross 		ctx->nb_wins2 = 0;
152613a2f6bSGordon Ross 		return (0);
153613a2f6bSGordon Ross 	}
1544bff34e3Sthurlow 
155613a2f6bSGordon Ross 	error = nb_resolvehost_in(wins1, &ina);
156613a2f6bSGordon Ross 	if (error) {
157613a2f6bSGordon Ross 		smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
158613a2f6bSGordon Ross 		    error, wins1);
159613a2f6bSGordon Ross 		return (error);
160613a2f6bSGordon Ross 	}
161613a2f6bSGordon Ross 	ctx->nb_wins1 = ina.s_addr;
162613a2f6bSGordon Ross 
163613a2f6bSGordon Ross 	if (wins2 == NULL)
164613a2f6bSGordon Ross 		ctx->nb_wins2 = 0;
165613a2f6bSGordon Ross 	else {
166613a2f6bSGordon Ross 		error = nb_resolvehost_in(wins2, &ina);
1674bff34e3Sthurlow 		if (error) {
1684bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
169613a2f6bSGordon Ross 			    error, wins2);
1704bff34e3Sthurlow 			return (error);
1714bff34e3Sthurlow 		}
172613a2f6bSGordon Ross 		ctx->nb_wins2 = ina.s_addr;
1734bff34e3Sthurlow 	}
1744bff34e3Sthurlow 	return (0);
1754bff34e3Sthurlow }
1764bff34e3Sthurlow 
1774bff34e3Sthurlow /*
1784bff34e3Sthurlow  * This is called by "smbutil lookup" to handle the
1794bff34e3Sthurlow  * "-w wins_server" option.  Let the semantics of
1804bff34e3Sthurlow  * this option be: Use specified WINS server only.
1814bff34e3Sthurlow  * If specified server is the broadcast address,
1824bff34e3Sthurlow  * set broadcast mode (and no WINS servers).
1834bff34e3Sthurlow  */
1844bff34e3Sthurlow int
nb_ctx_setns(struct nb_ctx * ctx,const char * addr)1854bff34e3Sthurlow nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
1864bff34e3Sthurlow {
1874bff34e3Sthurlow 	int error;
1884bff34e3Sthurlow 
189613a2f6bSGordon Ross 	error = nb_ctx_setwins(ctx, addr, NULL);
1904bff34e3Sthurlow 	if (error)
1914bff34e3Sthurlow 		return (error);
1924bff34e3Sthurlow 
1934bff34e3Sthurlow 	/* Deal with explicit request for broadcast. */
1944bff34e3Sthurlow 	if (ctx->nb_wins1 == INADDR_BROADCAST) {
1954bff34e3Sthurlow 		ctx->nb_wins1 = 0;
1964bff34e3Sthurlow 		ctx->nb_flags |= NBCF_BC_ENABLE;
1974bff34e3Sthurlow 	}
1984bff34e3Sthurlow 	return (0);
1994bff34e3Sthurlow }
2004bff34e3Sthurlow 
2014bff34e3Sthurlow int
nb_ctx_setscope(struct nb_ctx * ctx,const char * scope)2024bff34e3Sthurlow nb_ctx_setscope(struct nb_ctx *ctx, const char *scope)
2034bff34e3Sthurlow {
2044bff34e3Sthurlow 	size_t slen = strlen(scope);
2054bff34e3Sthurlow 
2064bff34e3Sthurlow 	if (slen >= 128) {
2074bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
2084bff34e3Sthurlow 		    "scope '%s' is too long"), 0, scope);
2094bff34e3Sthurlow 		return (ENAMETOOLONG);
2104bff34e3Sthurlow 	}
2114bff34e3Sthurlow 	if (ctx->nb_scope)
2124bff34e3Sthurlow 		free(ctx->nb_scope);
2134bff34e3Sthurlow 	ctx->nb_scope = malloc(slen + 1);
2144bff34e3Sthurlow 	if (ctx->nb_scope == NULL)
2154bff34e3Sthurlow 		return (ENOMEM);
2164bff34e3Sthurlow 	nls_str_upper(ctx->nb_scope, scope);
2174bff34e3Sthurlow 	return (0);
2184bff34e3Sthurlow }
2194bff34e3Sthurlow 
2204bff34e3Sthurlow /*
2214bff34e3Sthurlow  * Now get the WINS server IP addresses directly
2224bff34e3Sthurlow  * when reading the RC files, so no longer need to
2234bff34e3Sthurlow  * lookup any names here.
2244bff34e3Sthurlow  */
2254bff34e3Sthurlow int
nb_ctx_resolve(struct nb_ctx * ctx)2264bff34e3Sthurlow nb_ctx_resolve(struct nb_ctx *ctx)
2274bff34e3Sthurlow {
2284bff34e3Sthurlow 	ctx->nb_flags |= NBCF_RESOLVED;
2294bff34e3Sthurlow 	return (0);
2304bff34e3Sthurlow }
2314bff34e3Sthurlow 
2324bff34e3Sthurlow /*
2334bff34e3Sthurlow  * used level values:
2344bff34e3Sthurlow  * 0 - default
2354bff34e3Sthurlow  * 1 - server
2364bff34e3Sthurlow  *
2374bff34e3Sthurlow  * All of these are normally system-wide settings;
2384bff34e3Sthurlow  * the checks are in rc_parse() in rcfile.c.
2394bff34e3Sthurlow  */
2404bff34e3Sthurlow int
nb_ctx_readrcsection(struct rcfile * rcfile,struct nb_ctx * ctx,const char * sname,int level)2414bff34e3Sthurlow nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
2424bff34e3Sthurlow 	const char *sname, int level)
2434bff34e3Sthurlow {
244613a2f6bSGordon Ross 	char *wins1, *wins2;
2454bff34e3Sthurlow 	int error;
2464bff34e3Sthurlow 	int nbns_enable;
2474bff34e3Sthurlow 	int nbns_broadcast;
2484bff34e3Sthurlow 
2494bff34e3Sthurlow 	if (level > 1)
2504bff34e3Sthurlow 		return (EINVAL);
251613a2f6bSGordon Ross 
252613a2f6bSGordon Ross 	/* External callers pass NULL to get the default. */
253613a2f6bSGordon Ross 	if (rcfile == NULL)
254613a2f6bSGordon Ross 		rcfile = smb_rc;
255613a2f6bSGordon Ross 
2564bff34e3Sthurlow #ifdef NOT_DEFINED
2574bff34e3Sthurlow 	rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo);
2584bff34e3Sthurlow 	rc_getstringptr(rcfile, sname, "nbscope", &p);
2594bff34e3Sthurlow 	if (p)
2604bff34e3Sthurlow 		nb_ctx_setscope(ctx, p);
2614bff34e3Sthurlow #endif
262613a2f6bSGordon Ross 	/*
263613a2f6bSGordon Ross 	 * Get "wins1", "wins2" config strings.
264613a2f6bSGordon Ross 	 * Also support legacy "nbns".
265613a2f6bSGordon Ross 	 */
266613a2f6bSGordon Ross 	rc_getstringptr(rcfile, sname, "wins1", &wins1);
267613a2f6bSGordon Ross 	if (wins1 == NULL)
268613a2f6bSGordon Ross 		rc_getstringptr(rcfile, sname, "nbns", &wins1);
269613a2f6bSGordon Ross 	rc_getstringptr(rcfile, sname, "wins2", &wins2);
270613a2f6bSGordon Ross 
271613a2f6bSGordon Ross 	if (wins1 != NULL) {
272613a2f6bSGordon Ross 		error = nb_ctx_setwins(ctx, wins1, wins2);
2734bff34e3Sthurlow 		if (error) {
2744bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
2754bff34e3Sthurlow 			    "invalid address specified in the section %s"),
2764bff34e3Sthurlow 			    0, sname);
2774bff34e3Sthurlow 			return (error);
2784bff34e3Sthurlow 		}
2794bff34e3Sthurlow 	}
2808eb99b82SGordon Ross 
2818eb99b82SGordon Ross 	/*
2828eb99b82SGordon Ross 	 * Want to use nb_ctx_setnbflags here, but
2838eb99b82SGordon Ross 	 * have to get both boolean values first,
2848eb99b82SGordon Ross 	 * either from settings or defaults.
2858eb99b82SGordon Ross 	 */
286*42d15982SGordon Ross 	nbns_enable = nbns_broadcast = 1; /* defaults */
2878eb99b82SGordon Ross 	rc_getbool(rcfile, sname, "nbns_enable", &nbns_enable);
2888eb99b82SGordon Ross 	rc_getbool(rcfile, sname, "nbns_broadcast", &nbns_broadcast);
289*42d15982SGordon Ross 	nb_ctx_setnbflags(ctx, nbns_enable, nbns_broadcast);
290*42d15982SGordon Ross 
2914bff34e3Sthurlow 	return (0);
2924bff34e3Sthurlow }
2934bff34e3Sthurlow 
2944bff34e3Sthurlow #ifdef I18N	/* never defined, permits xgettext(1) to pick out strings */
2954bff34e3Sthurlow static const char *nb_err_rcode[] = {
2964bff34e3Sthurlow 	gettext("bad request/response format"),
2974bff34e3Sthurlow 	gettext("NBNS server failure"),
2984bff34e3Sthurlow 	gettext("no such name"),
2994bff34e3Sthurlow 	gettext("unsupported request"),
3004bff34e3Sthurlow 	gettext("request rejected"),
3014bff34e3Sthurlow 	gettext("name already registered)"
3024bff34e3Sthurlow };
3034bff34e3Sthurlow 
3044bff34e3Sthurlow static const char *nb_err[] = {
3054bff34e3Sthurlow 	gettext("host not found"),
3064bff34e3Sthurlow 	gettext("too many redirects"),
3074bff34e3Sthurlow 	gettext("invalid response"),
3084bff34e3Sthurlow 	gettext("NETBIOS name too long"),
3094bff34e3Sthurlow 	gettext("no interface to broadcast on and no NBNS server specified")
3104bff34e3Sthurlow };
3114bff34e3Sthurlow #else
3124bff34e3Sthurlow static const char *nb_err_rcode[] = {
3134bff34e3Sthurlow 	"bad request/response format",
3144bff34e3Sthurlow 	"NBNS server failure",
3154bff34e3Sthurlow 	"no such name",
3164bff34e3Sthurlow 	"unsupported request",
3174bff34e3Sthurlow 	"request rejected",
3184bff34e3Sthurlow 	"name already registered"
3194bff34e3Sthurlow };
3204bff34e3Sthurlow 
3214bff34e3Sthurlow static const char *nb_err[] = {
3224bff34e3Sthurlow 	"host not found",
3234bff34e3Sthurlow 	"too many redirects",
3244bff34e3Sthurlow 	"invalid response",
3254bff34e3Sthurlow 	"NETBIOS name too long",
3264bff34e3Sthurlow 	"no interface to broadcast on and no NBNS server specified"
3274bff34e3Sthurlow };
3284bff34e3Sthurlow #endif
3294bff34e3Sthurlow 
3304bff34e3Sthurlow const char *
3314bff34e3Sthurlow nb_strerror(int error)
3324bff34e3Sthurlow {
3334bff34e3Sthurlow 	if (error == 0)
3344bff34e3Sthurlow 		return (NULL);
3354bff34e3Sthurlow 	if (error <= NBERR_ACTIVE)
3364bff34e3Sthurlow 		return (nb_err_rcode[error - 1]);
3374bff34e3Sthurlow 	else if (error >= NBERR_HOSTNOTFOUND && error < NBERR_MAX)
3384bff34e3Sthurlow 		return (nb_err[error - NBERR_HOSTNOTFOUND]);
3394bff34e3Sthurlow 	else
3404bff34e3Sthurlow 		return (NULL);
3414bff34e3Sthurlow }
342