xref: /onnv-gate/usr/src/lib/libsmbfs/smb/nb.c (revision 12019:cfe7a7d0d7f0)
16007Sthurlow /*
26007Sthurlow  * Copyright (c) 2000, 2001 Boris Popov
36007Sthurlow  * All rights reserved.
46007Sthurlow  *
56007Sthurlow  * Redistribution and use in source and binary forms, with or without
66007Sthurlow  * modification, are permitted provided that the following conditions
76007Sthurlow  * are met:
86007Sthurlow  * 1. Redistributions of source code must retain the above copyright
96007Sthurlow  *    notice, this list of conditions and the following disclaimer.
106007Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
116007Sthurlow  *    notice, this list of conditions and the following disclaimer in the
126007Sthurlow  *    documentation and/or other materials provided with the distribution.
136007Sthurlow  * 3. All advertising materials mentioning features or use of this software
146007Sthurlow  *    must display the following acknowledgement:
156007Sthurlow  *    This product includes software developed by Boris Popov.
166007Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
176007Sthurlow  *    may be used to endorse or promote products derived from this software
186007Sthurlow  *    without specific prior written permission.
196007Sthurlow  *
206007Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
216007Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226007Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236007Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
246007Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256007Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266007Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276007Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286007Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296007Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306007Sthurlow  * SUCH DAMAGE.
316007Sthurlow  *
326007Sthurlow  * $Id: nb.c,v 1.1.1.2 2001/07/06 22:38:42 conrad Exp $
336007Sthurlow  */
346007Sthurlow 
3510023SGordon.Ross@Sun.COM /*
36*12019SGordon.Ross@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3710023SGordon.Ross@Sun.COM  * Use is subject to license terms.
3810023SGordon.Ross@Sun.COM  */
396007Sthurlow 
406007Sthurlow #include <sys/param.h>
416007Sthurlow #include <sys/socket.h>
426007Sthurlow 
436007Sthurlow #include <errno.h>
4410023SGordon.Ross@Sun.COM #include <stdio.h>
456007Sthurlow #include <stdlib.h>
466007Sthurlow #include <string.h>
476007Sthurlow #include <strings.h>
486007Sthurlow #include <unistd.h>
496007Sthurlow #include <libintl.h>
5010023SGordon.Ross@Sun.COM #include <netdb.h>
516007Sthurlow 
526007Sthurlow #include <netinet/in.h>
536007Sthurlow #include <arpa/inet.h>
546007Sthurlow 
5510023SGordon.Ross@Sun.COM #include <cflib.h>
566007Sthurlow #include <netsmb/netbios.h>
576007Sthurlow #include <netsmb/smb_lib.h>
586007Sthurlow #include <netsmb/nb_lib.h>
596007Sthurlow 
6010419SGordon.Ross@Sun.COM void nb_ctx_setnbflags(struct nb_ctx *, int ns_ena, int bc_ena);
6110023SGordon.Ross@Sun.COM int nb_ctx_setwins(struct nb_ctx *, const char *, const char *);
6210023SGordon.Ross@Sun.COM 
6310419SGordon.Ross@Sun.COM /*
6410419SGordon.Ross@Sun.COM  * API for seting NetBIOS name lookup flags:
6510419SGordon.Ross@Sun.COM  * NetBIOS name lookup enable,
6610419SGordon.Ross@Sun.COM  * NetBIOS broadcast enable.
6710419SGordon.Ross@Sun.COM  */
6810419SGordon.Ross@Sun.COM int
smb_ctx_setnbflags(struct smb_ctx * ctx,int ns_ena,int bc_ena)6910419SGordon.Ross@Sun.COM smb_ctx_setnbflags(struct smb_ctx *ctx, int ns_ena, int bc_ena)
7010419SGordon.Ross@Sun.COM {
7110419SGordon.Ross@Sun.COM 	struct nb_ctx *nb = ctx->ct_nb;
7210419SGordon.Ross@Sun.COM 
7310419SGordon.Ross@Sun.COM 	if (nb == NULL)
7410419SGordon.Ross@Sun.COM 		return (EINVAL);
7510419SGordon.Ross@Sun.COM 
7610419SGordon.Ross@Sun.COM 	nb_ctx_setnbflags(nb, ns_ena, bc_ena);
7710419SGordon.Ross@Sun.COM 	return (0);
7810419SGordon.Ross@Sun.COM }
7910023SGordon.Ross@Sun.COM 
8010023SGordon.Ross@Sun.COM /*
8110023SGordon.Ross@Sun.COM  * API for library consumer to set wins1, wins2
8210023SGordon.Ross@Sun.COM  */
8310023SGordon.Ross@Sun.COM int
smb_ctx_setwins(struct smb_ctx * ctx,const char * wins1,const char * wins2)8410023SGordon.Ross@Sun.COM smb_ctx_setwins(struct smb_ctx *ctx, const char *wins1, const char *wins2)
8510023SGordon.Ross@Sun.COM {
8610023SGordon.Ross@Sun.COM 	struct nb_ctx *nb = ctx->ct_nb;
8710023SGordon.Ross@Sun.COM 
8810023SGordon.Ross@Sun.COM 	if (nb == NULL)
8910023SGordon.Ross@Sun.COM 		return (EINVAL);
9010023SGordon.Ross@Sun.COM 
9110023SGordon.Ross@Sun.COM 	return (nb_ctx_setwins(nb, wins1, wins2));
9210023SGordon.Ross@Sun.COM }
9310023SGordon.Ross@Sun.COM 
9410023SGordon.Ross@Sun.COM /*
9510023SGordon.Ross@Sun.COM  * API for library consumer to set NB scope.
9610023SGordon.Ross@Sun.COM  */
9710023SGordon.Ross@Sun.COM int
smb_ctx_setscope(struct smb_ctx * ctx,const char * scope)9810023SGordon.Ross@Sun.COM smb_ctx_setscope(struct smb_ctx *ctx, const char *scope)
9910023SGordon.Ross@Sun.COM {
10010023SGordon.Ross@Sun.COM 	struct nb_ctx *nb = ctx->ct_nb;
10110023SGordon.Ross@Sun.COM 
10210023SGordon.Ross@Sun.COM 	if (nb == NULL)
10310023SGordon.Ross@Sun.COM 		return (EINVAL);
10410023SGordon.Ross@Sun.COM 
10510023SGordon.Ross@Sun.COM 	return (nb_ctx_setscope(nb, scope));
10610023SGordon.Ross@Sun.COM }
1076007Sthurlow 
1086007Sthurlow int
nb_ctx_create(struct nb_ctx ** ctxpp)1096007Sthurlow nb_ctx_create(struct nb_ctx **ctxpp)
1106007Sthurlow {
1116007Sthurlow 	struct nb_ctx *ctx;
1126007Sthurlow 
1136007Sthurlow 	ctx = malloc(sizeof (struct nb_ctx));
1146007Sthurlow 	if (ctx == NULL)
1156007Sthurlow 		return (ENOMEM);
1166007Sthurlow 	bzero(ctx, sizeof (struct nb_ctx));
1176007Sthurlow 	*ctxpp = ctx;
1186007Sthurlow 	return (0);
1196007Sthurlow }
1206007Sthurlow 
1216007Sthurlow void
nb_ctx_done(struct nb_ctx * ctx)1226007Sthurlow nb_ctx_done(struct nb_ctx *ctx)
1236007Sthurlow {
1246007Sthurlow 	if (ctx == NULL)
1256007Sthurlow 		return;
1266007Sthurlow 	if (ctx->nb_scope)
1276007Sthurlow 		free(ctx->nb_scope);
1286007Sthurlow 	if (ctx)
1296007Sthurlow 		free(ctx);
1306007Sthurlow }
1316007Sthurlow 
13210419SGordon.Ross@Sun.COM void
nb_ctx_setnbflags(struct nb_ctx * nb,int ns_ena,int bc_ena)13310419SGordon.Ross@Sun.COM nb_ctx_setnbflags(struct nb_ctx *nb, int ns_ena, int bc_ena)
13410419SGordon.Ross@Sun.COM {
13510419SGordon.Ross@Sun.COM 	nb->nb_flags &= ~(NBCF_NS_ENABLE | NBCF_BC_ENABLE);
13610419SGordon.Ross@Sun.COM 	if (ns_ena) {
137*12019SGordon.Ross@Sun.COM 		nb->nb_flags |= NBCF_NS_ENABLE;
13810419SGordon.Ross@Sun.COM 		if (bc_ena)
139*12019SGordon.Ross@Sun.COM 			nb->nb_flags |= NBCF_BC_ENABLE;
14010419SGordon.Ross@Sun.COM 	}
14110419SGordon.Ross@Sun.COM }
14210419SGordon.Ross@Sun.COM 
14310023SGordon.Ross@Sun.COM int
nb_ctx_setwins(struct nb_ctx * ctx,const char * wins1,const char * wins2)14410023SGordon.Ross@Sun.COM nb_ctx_setwins(struct nb_ctx *ctx, const char *wins1, const char *wins2)
1456007Sthurlow {
1466007Sthurlow 	struct in_addr ina;
1476007Sthurlow 	int error;
1486007Sthurlow 
14910023SGordon.Ross@Sun.COM 	if (wins1 == NULL) {
15010023SGordon.Ross@Sun.COM 		ctx->nb_wins1 = 0;
15110023SGordon.Ross@Sun.COM 		ctx->nb_wins2 = 0;
15210023SGordon.Ross@Sun.COM 		return (0);
15310023SGordon.Ross@Sun.COM 	}
1546007Sthurlow 
15510023SGordon.Ross@Sun.COM 	error = nb_resolvehost_in(wins1, &ina);
15610023SGordon.Ross@Sun.COM 	if (error) {
15710023SGordon.Ross@Sun.COM 		smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
15810023SGordon.Ross@Sun.COM 		    error, wins1);
15910023SGordon.Ross@Sun.COM 		return (error);
16010023SGordon.Ross@Sun.COM 	}
16110023SGordon.Ross@Sun.COM 	ctx->nb_wins1 = ina.s_addr;
16210023SGordon.Ross@Sun.COM 
16310023SGordon.Ross@Sun.COM 	if (wins2 == NULL)
16410023SGordon.Ross@Sun.COM 		ctx->nb_wins2 = 0;
16510023SGordon.Ross@Sun.COM 	else {
16610023SGordon.Ross@Sun.COM 		error = nb_resolvehost_in(wins2, &ina);
1676007Sthurlow 		if (error) {
1686007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
16910023SGordon.Ross@Sun.COM 			    error, wins2);
1706007Sthurlow 			return (error);
1716007Sthurlow 		}
17210023SGordon.Ross@Sun.COM 		ctx->nb_wins2 = ina.s_addr;
1736007Sthurlow 	}
1746007Sthurlow 	return (0);
1756007Sthurlow }
1766007Sthurlow 
1776007Sthurlow /*
1786007Sthurlow  * This is called by "smbutil lookup" to handle the
1796007Sthurlow  * "-w wins_server" option.  Let the semantics of
1806007Sthurlow  * this option be: Use specified WINS server only.
1816007Sthurlow  * If specified server is the broadcast address,
1826007Sthurlow  * set broadcast mode (and no WINS servers).
1836007Sthurlow  */
1846007Sthurlow int
nb_ctx_setns(struct nb_ctx * ctx,const char * addr)1856007Sthurlow nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
1866007Sthurlow {
1876007Sthurlow 	int error;
1886007Sthurlow 
18910023SGordon.Ross@Sun.COM 	error = nb_ctx_setwins(ctx, addr, NULL);
1906007Sthurlow 	if (error)
1916007Sthurlow 		return (error);
1926007Sthurlow 
1936007Sthurlow 	/* Deal with explicit request for broadcast. */
1946007Sthurlow 	if (ctx->nb_wins1 == INADDR_BROADCAST) {
1956007Sthurlow 		ctx->nb_wins1 = 0;
1966007Sthurlow 		ctx->nb_flags |= NBCF_BC_ENABLE;
1976007Sthurlow 	}
1986007Sthurlow 	return (0);
1996007Sthurlow }
2006007Sthurlow 
2016007Sthurlow int
nb_ctx_setscope(struct nb_ctx * ctx,const char * scope)2026007Sthurlow nb_ctx_setscope(struct nb_ctx *ctx, const char *scope)
2036007Sthurlow {
2046007Sthurlow 	size_t slen = strlen(scope);
2056007Sthurlow 
2066007Sthurlow 	if (slen >= 128) {
2076007Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
2086007Sthurlow 		    "scope '%s' is too long"), 0, scope);
2096007Sthurlow 		return (ENAMETOOLONG);
2106007Sthurlow 	}
2116007Sthurlow 	if (ctx->nb_scope)
2126007Sthurlow 		free(ctx->nb_scope);
2136007Sthurlow 	ctx->nb_scope = malloc(slen + 1);
2146007Sthurlow 	if (ctx->nb_scope == NULL)
2156007Sthurlow 		return (ENOMEM);
2166007Sthurlow 	nls_str_upper(ctx->nb_scope, scope);
2176007Sthurlow 	return (0);
2186007Sthurlow }
2196007Sthurlow 
2206007Sthurlow /*
2216007Sthurlow  * Now get the WINS server IP addresses directly
2226007Sthurlow  * when reading the RC files, so no longer need to
2236007Sthurlow  * lookup any names here.
2246007Sthurlow  */
2256007Sthurlow int
nb_ctx_resolve(struct nb_ctx * ctx)2266007Sthurlow nb_ctx_resolve(struct nb_ctx *ctx)
2276007Sthurlow {
2286007Sthurlow 	ctx->nb_flags |= NBCF_RESOLVED;
2296007Sthurlow 	return (0);
2306007Sthurlow }
2316007Sthurlow 
2326007Sthurlow /*
2336007Sthurlow  * used level values:
2346007Sthurlow  * 0 - default
2356007Sthurlow  * 1 - server
2366007Sthurlow  *
2376007Sthurlow  * All of these are normally system-wide settings;
2386007Sthurlow  * the checks are in rc_parse() in rcfile.c.
2396007Sthurlow  */
2406007Sthurlow int
nb_ctx_readrcsection(struct rcfile * rcfile,struct nb_ctx * ctx,const char * sname,int level)2416007Sthurlow nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
2426007Sthurlow 	const char *sname, int level)
2436007Sthurlow {
24410023SGordon.Ross@Sun.COM 	char *wins1, *wins2;
2456007Sthurlow 	int error;
2466007Sthurlow 	int nbns_enable;
2476007Sthurlow 	int nbns_broadcast;
2486007Sthurlow 
2496007Sthurlow 	if (level > 1)
2506007Sthurlow 		return (EINVAL);
25110023SGordon.Ross@Sun.COM 
25210023SGordon.Ross@Sun.COM 	/* External callers pass NULL to get the default. */
25310023SGordon.Ross@Sun.COM 	if (rcfile == NULL)
25410023SGordon.Ross@Sun.COM 		rcfile = smb_rc;
25510023SGordon.Ross@Sun.COM 
2566007Sthurlow #ifdef NOT_DEFINED
2576007Sthurlow 	rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo);
2586007Sthurlow 	rc_getstringptr(rcfile, sname, "nbscope", &p);
2596007Sthurlow 	if (p)
2606007Sthurlow 		nb_ctx_setscope(ctx, p);
2616007Sthurlow #endif
26210023SGordon.Ross@Sun.COM 	/*
26310023SGordon.Ross@Sun.COM 	 * Get "wins1", "wins2" config strings.
26410023SGordon.Ross@Sun.COM 	 * Also support legacy "nbns".
26510023SGordon.Ross@Sun.COM 	 */
26610023SGordon.Ross@Sun.COM 	rc_getstringptr(rcfile, sname, "wins1", &wins1);
26710023SGordon.Ross@Sun.COM 	if (wins1 == NULL)
26810023SGordon.Ross@Sun.COM 		rc_getstringptr(rcfile, sname, "nbns", &wins1);
26910023SGordon.Ross@Sun.COM 	rc_getstringptr(rcfile, sname, "wins2", &wins2);
27010023SGordon.Ross@Sun.COM 
27110023SGordon.Ross@Sun.COM 	if (wins1 != NULL) {
27210023SGordon.Ross@Sun.COM 		error = nb_ctx_setwins(ctx, wins1, wins2);
2736007Sthurlow 		if (error) {
2746007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
2756007Sthurlow 			    "invalid address specified in the section %s"),
2766007Sthurlow 			    0, sname);
2776007Sthurlow 			return (error);
2786007Sthurlow 		}
2796007Sthurlow 	}
28010419SGordon.Ross@Sun.COM 
28110419SGordon.Ross@Sun.COM 	/*
28210419SGordon.Ross@Sun.COM 	 * Want to use nb_ctx_setnbflags here, but
28310419SGordon.Ross@Sun.COM 	 * have to get both boolean values first,
28410419SGordon.Ross@Sun.COM 	 * either from settings or defaults.
28510419SGordon.Ross@Sun.COM 	 */
286*12019SGordon.Ross@Sun.COM 	nbns_enable = nbns_broadcast = 1; /* defaults */
28710419SGordon.Ross@Sun.COM 	rc_getbool(rcfile, sname, "nbns_enable", &nbns_enable);
28810419SGordon.Ross@Sun.COM 	rc_getbool(rcfile, sname, "nbns_broadcast", &nbns_broadcast);
289*12019SGordon.Ross@Sun.COM 	nb_ctx_setnbflags(ctx, nbns_enable, nbns_broadcast);
290*12019SGordon.Ross@Sun.COM 
2916007Sthurlow 	return (0);
2926007Sthurlow }
2936007Sthurlow 
2946007Sthurlow #ifdef I18N	/* never defined, permits xgettext(1) to pick out strings */
2956007Sthurlow static const char *nb_err_rcode[] = {
2966007Sthurlow 	gettext("bad request/response format"),
2976007Sthurlow 	gettext("NBNS server failure"),
2986007Sthurlow 	gettext("no such name"),
2996007Sthurlow 	gettext("unsupported request"),
3006007Sthurlow 	gettext("request rejected"),
3016007Sthurlow 	gettext("name already registered)"
3026007Sthurlow };
3036007Sthurlow 
3046007Sthurlow static const char *nb_err[] = {
3056007Sthurlow 	gettext("host not found"),
3066007Sthurlow 	gettext("too many redirects"),
3076007Sthurlow 	gettext("invalid response"),
3086007Sthurlow 	gettext("NETBIOS name too long"),
3096007Sthurlow 	gettext("no interface to broadcast on and no NBNS server specified")
3106007Sthurlow };
3116007Sthurlow #else
3126007Sthurlow static const char *nb_err_rcode[] = {
3136007Sthurlow 	"bad request/response format",
3146007Sthurlow 	"NBNS server failure",
3156007Sthurlow 	"no such name",
3166007Sthurlow 	"unsupported request",
3176007Sthurlow 	"request rejected",
3186007Sthurlow 	"name already registered"
3196007Sthurlow };
3206007Sthurlow 
3216007Sthurlow static const char *nb_err[] = {
3226007Sthurlow 	"host not found",
3236007Sthurlow 	"too many redirects",
3246007Sthurlow 	"invalid response",
3256007Sthurlow 	"NETBIOS name too long",
3266007Sthurlow 	"no interface to broadcast on and no NBNS server specified"
3276007Sthurlow };
3286007Sthurlow #endif
3296007Sthurlow 
3306007Sthurlow const char *
3316007Sthurlow nb_strerror(int error)
3326007Sthurlow {
3336007Sthurlow 	if (error == 0)
3346007Sthurlow 		return (NULL);
3356007Sthurlow 	if (error <= NBERR_ACTIVE)
3366007Sthurlow 		return (nb_err_rcode[error - 1]);
3376007Sthurlow 	else if (error >= NBERR_HOSTNOTFOUND && error < NBERR_MAX)
3386007Sthurlow 		return (nb_err[error - NBERR_HOSTNOTFOUND]);
3396007Sthurlow 	else
3406007Sthurlow 		return (NULL);
3416007Sthurlow }
342