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