xref: /titanic_51/usr/src/lib/libsmbfs/smb/nb.c (revision 5a7763bf3e9db4cfe6cb523b096cb74af71e3793)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 #include <sys/param.h>
38 #include <sys/socket.h>
39 
40 #include <ctype.h>
41 #include <netdb.h>
42 #include <errno.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <strings.h>
46 #include <stdio.h>
47 #include <unistd.h>
48 #include <libintl.h>
49 
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 
53 #include <netsmb/netbios.h>
54 #include <netsmb/smb_lib.h>
55 #include <netsmb/nb_lib.h>
56 
57 #include <cflib.h>
58 
59 int
60 nb_ctx_create(struct nb_ctx **ctxpp)
61 {
62 	struct nb_ctx *ctx;
63 
64 	ctx = malloc(sizeof (struct nb_ctx));
65 	if (ctx == NULL)
66 		return (ENOMEM);
67 	bzero(ctx, sizeof (struct nb_ctx));
68 	ctx->nb_flags = NBCF_NS_ENABLE | NBCF_BC_ENABLE;
69 	*ctxpp = ctx;
70 	return (0);
71 }
72 
73 void
74 nb_ctx_done(struct nb_ctx *ctx)
75 {
76 	if (ctx == NULL)
77 		return;
78 	if (ctx->nb_scope)
79 		free(ctx->nb_scope);
80 	if (ctx)
81 		free(ctx);
82 }
83 
84 static int
85 nb_ctx_setwins(in_addr_t *ina_p, const char *str)
86 {
87 	struct in_addr ina;
88 	struct sockaddr *sap;
89 	int error;
90 
91 	if (str == NULL || str[0] == 0)
92 		return (EINVAL);
93 
94 	if (inet_aton(str, &ina)) {
95 		*ina_p = ina.s_addr;
96 	} else {
97 		error = nb_resolvehost_in(str, &sap);
98 		if (error) {
99 			smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
100 			    error, str);
101 			return (error);
102 		}
103 		if (sap->sa_family != AF_INET) {
104 			smb_error(dgettext(TEXT_DOMAIN,
105 			    "unsupported address family %d"), 0,
106 			    sap->sa_family);
107 			return (EINVAL);
108 		}
109 		/*LINTED*/
110 		*ina_p = ((struct sockaddr_in *)sap)->sin_addr.s_addr;
111 		free(sap);
112 	}
113 
114 	return (0);
115 }
116 
117 /*
118  * This is called by "smbutil lookup" to handle the
119  * "-w wins_server" option.  Let the semantics of
120  * this option be: Use specified WINS server only.
121  * If specified server is the broadcast address,
122  * set broadcast mode (and no WINS servers).
123  */
124 int
125 nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
126 {
127 	int error;
128 
129 	error = nb_ctx_setwins(&ctx->nb_wins1, addr);
130 	if (error)
131 		return (error);
132 	ctx->nb_wins2 = 0;
133 
134 	/* Deal with explicit request for broadcast. */
135 	if (ctx->nb_wins1 == INADDR_BROADCAST) {
136 		ctx->nb_wins1 = 0;
137 		ctx->nb_flags |= NBCF_BC_ENABLE;
138 	}
139 	return (0);
140 }
141 
142 int
143 nb_ctx_setscope(struct nb_ctx *ctx, const char *scope)
144 {
145 	size_t slen = strlen(scope);
146 
147 	if (slen >= 128) {
148 		smb_error(dgettext(TEXT_DOMAIN,
149 		    "scope '%s' is too long"), 0, scope);
150 		return (ENAMETOOLONG);
151 	}
152 	if (ctx->nb_scope)
153 		free(ctx->nb_scope);
154 	ctx->nb_scope = malloc(slen + 1);
155 	if (ctx->nb_scope == NULL)
156 		return (ENOMEM);
157 	nls_str_upper(ctx->nb_scope, scope);
158 	return (0);
159 }
160 
161 /*
162  * Now get the WINS server IP addresses directly
163  * when reading the RC files, so no longer need to
164  * lookup any names here.
165  */
166 int
167 nb_ctx_resolve(struct nb_ctx *ctx)
168 {
169 	ctx->nb_flags |= NBCF_RESOLVED;
170 	return (0);
171 }
172 
173 /*
174  * used level values:
175  * 0 - default
176  * 1 - server
177  *
178  * All of these are normally system-wide settings;
179  * the checks are in rc_parse() in rcfile.c.
180  */
181 int
182 nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
183 	const char *sname, int level)
184 {
185 	char *p;
186 	int error;
187 	int nbns_enable;
188 	int nbns_broadcast;
189 
190 	if (level > 1)
191 		return (EINVAL);
192 #ifdef NOT_DEFINED
193 	rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo);
194 	rc_getstringptr(rcfile, sname, "nbscope", &p);
195 	if (p)
196 		nb_ctx_setscope(ctx, p);
197 #endif
198 	/* "nbns" will be "wins1" some day, and we'll have a "wins2" also */
199 	rc_getstringptr(rcfile, sname, "nbns", &p);
200 	if (p) {
201 		error = nb_ctx_setwins(&ctx->nb_wins1, p);
202 		if (error) {
203 			smb_error(dgettext(TEXT_DOMAIN,
204 			    "invalid address specified in the section %s"),
205 			    0, sname);
206 			return (error);
207 		}
208 	}
209 	error = rc_getbool(rcfile, sname, "nbns_enable", &nbns_enable);
210 	if (error == 0 && nbns_enable == 0)
211 		ctx->nb_flags &= ~NBCF_NS_ENABLE;
212 	error = rc_getbool(rcfile, sname, "nbns_broadcast", &nbns_broadcast);
213 	if (error == 0 && nbns_broadcast == 0)
214 		ctx->nb_flags &= ~NBCF_BC_ENABLE;
215 	return (0);
216 }
217 
218 #ifdef I18N	/* never defined, permits xgettext(1) to pick out strings */
219 static const char *nb_err_rcode[] = {
220 	gettext("bad request/response format"),
221 	gettext("NBNS server failure"),
222 	gettext("no such name"),
223 	gettext("unsupported request"),
224 	gettext("request rejected"),
225 	gettext("name already registered)"
226 };
227 
228 static const char *nb_err[] = {
229 	gettext("host not found"),
230 	gettext("too many redirects"),
231 	gettext("invalid response"),
232 	gettext("NETBIOS name too long"),
233 	gettext("no interface to broadcast on and no NBNS server specified")
234 };
235 #else
236 static const char *nb_err_rcode[] = {
237 	"bad request/response format",
238 	"NBNS server failure",
239 	"no such name",
240 	"unsupported request",
241 	"request rejected",
242 	"name already registered"
243 };
244 
245 static const char *nb_err[] = {
246 	"host not found",
247 	"too many redirects",
248 	"invalid response",
249 	"NETBIOS name too long",
250 	"no interface to broadcast on and no NBNS server specified"
251 };
252 #endif
253 
254 const char *
255 nb_strerror(int error)
256 {
257 	if (error == 0)
258 		return (NULL);
259 	if (error <= NBERR_ACTIVE)
260 		return (nb_err_rcode[error - 1]);
261 	else if (error >= NBERR_HOSTNOTFOUND && error < NBERR_MAX)
262 		return (nb_err[error - NBERR_HOSTNOTFOUND]);
263 	else
264 		return (NULL);
265 }
266