xref: /illumos-gate/usr/src/lib/libsmbfs/smb/subr.c (revision 71269a2275bf5a143dad6461eee2710a344e7261)
1 /*
2  * Copyright (c) 2000, 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: subr.c,v 1.19 2005/02/09 00:23:45 lindak Exp $
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/errno.h>
40 #include <sys/syscall.h>
41 #include <sys/wait.h>
42 #include <sys/debug.h>
43 
44 #include <unistd.h>
45 #include <ctype.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <stdarg.h>
50 #include <errno.h>
51 #include <sysexits.h>
52 #include <libintl.h>
53 
54 #include <netsmb/netbios.h>
55 #include <netsmb/smb_lib.h>
56 #include <netsmb/nb_lib.h>
57 #include <cflib.h>
58 #include <err.h>
59 
60 uid_t real_uid, eff_uid;
61 
62 static int smblib_initialized;
63 
64 struct rcfile *smb_rc;
65 
66 int
67 smb_lib_init(void)
68 {
69 	int error;
70 
71 	if (smblib_initialized)
72 		return (0);
73 	if ((error = nls_setlocale("")) != 0) {
74 		fprintf(stdout, dgettext(TEXT_DOMAIN,
75 		    "%s: can't initialise locale\n"), __progname);
76 		return (error);
77 	}
78 	smblib_initialized++;
79 	return (0);
80 }
81 
82 /*
83  * Private version of strerror(3C) that
84  * knows our special error codes.
85  */
86 char *
87 smb_strerror(int err)
88 {
89 	char *msg;
90 
91 	switch (err) {
92 	case EBADRPC:
93 		msg = dgettext(TEXT_DOMAIN,
94 		    "remote call failed");
95 		break;
96 	case EAUTH:
97 		msg = dgettext(TEXT_DOMAIN,
98 		    "authentication failed");
99 		break;
100 	default:
101 		msg = strerror(err);
102 		break;
103 	}
104 
105 	return (msg);
106 }
107 
108 /*
109  * Print a (descriptive) error message
110  * error values:
111  *         0 - no specific error code available;
112  *  1..32767 - system error
113  */
114 void
115 smb_error(const char *fmt, int error, ...) {
116 	va_list ap;
117 	const char *cp;
118 	int errtype;
119 
120 	fprintf(stderr, "%s: ", __progname);
121 	va_start(ap, error);
122 	vfprintf(stderr, fmt, ap);
123 	va_end(ap);
124 	if (error == -1) {
125 		error = errno;
126 		errtype = SMB_SYS_ERROR;
127 	} else {
128 		errtype = error & SMB_ERRTYPE_MASK;
129 		error &= ~SMB_ERRTYPE_MASK;
130 	}
131 	switch (errtype) {
132 	    case SMB_SYS_ERROR:
133 		if (error)
134 			fprintf(stderr, ": syserr = %s\n", smb_strerror(error));
135 		else
136 			fprintf(stderr, "\n");
137 		break;
138 	    case SMB_RAP_ERROR:
139 		fprintf(stderr, ": raperr = %d (0x%04x)\n", error, error);
140 		break;
141 	    case SMB_NB_ERROR:
142 		cp = nb_strerror(error);
143 		if (cp == NULL)
144 			fprintf(stderr, ": nberr = unknown (0x%04x)\n", error);
145 		else
146 			fprintf(stderr, ": nberr = %s\n", cp);
147 		break;
148 	    default:
149 		fprintf(stderr, "\n");
150 	}
151 }
152 
153 char *
154 smb_printb(char *dest, int flags, const struct smb_bitname *bnp) {
155 	int first = 1;
156 
157 	strcpy(dest, "<");
158 	for (; bnp->bn_bit; bnp++) {
159 		if (flags & bnp->bn_bit) {
160 			strcat(dest, bnp->bn_name);
161 			first = 0;
162 		}
163 		if (!first && (flags & bnp[1].bn_bit))
164 			strcat(dest, "|");
165 	}
166 	strcat(dest, ">");
167 	return (dest);
168 }
169 
170 extern int home_nsmbrc;
171 
172 #ifdef DEBUG
173 #include "queue.h"
174 #include "rcfile_priv.h"
175 
176 struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname);
177 struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname);
178 
179 void
180 dump_props(char *where)
181 {
182 	struct rcsection *rsp = NULL;
183 	struct rckey *rkp = NULL;
184 
185 	printf("Settings %s\n", where);
186 	SLIST_FOREACH(rsp, &smb_rc->rf_sect, rs_next) {
187 		printf("section=%s\n", rsp->rs_name);
188 		fflush(stdout);
189 
190 		SLIST_FOREACH(rkp, &rsp->rs_keys, rk_next) {
191 			printf("  key=%s, value=%s\n",
192 			    rkp->rk_name, rkp->rk_value);
193 			fflush(stdout);
194 		}
195 	}
196 }
197 #endif
198 
199 /*
200  * first read ~/.smbrc, next try to merge SMB_CFG_FILE - if that fails
201  * because SMB_CFG_FILE doesn't exist, try to merge OLD_SMB_CFG_FILE
202  */
203 int
204 smb_open_rcfile(struct smb_ctx *ctx)
205 {
206 	char *home, *fn;
207 	int error, len;
208 
209 	smb_rc = NULL;
210 #ifdef DEPRECATED
211 	fn = SMB_CFG_FILE;
212 	error = rc_merge(fn, &smb_rc);
213 	if (error == ENOENT) {
214 		/*
215 		 * OK, try to read a config file in the old location.
216 		 */
217 		fn = OLD_SMB_CFG_FILE;
218 		error = rc_merge(fn, &smb_rc);
219 	}
220 #endif
221 	fn = "/usr/sbin/sharectl get smbfs";
222 	error = rc_merge_pipe(fn, &smb_rc);
223 	if (error != 0 && error != ENOENT)
224 		fprintf(stderr, dgettext(TEXT_DOMAIN,
225 		    "Can't open %s: %s\n"), fn, smb_strerror(errno));
226 #ifdef DEBUG
227 	dump_props("after reading global repository");
228 #endif
229 
230 	home = getenv("HOME");
231 	if (home == NULL && ctx && ctx->ct_home)
232 		home = ctx->ct_home;
233 	if (home) {
234 		len = strlen(home) + 20;
235 		fn = malloc(len);
236 		snprintf(fn, len, "%s/.nsmbrc", home);
237 		home_nsmbrc = 1;
238 		error = rc_merge(fn, &smb_rc);
239 		if (error != 0 && error != ENOENT) {
240 			fprintf(stderr, dgettext(TEXT_DOMAIN,
241 			    "Can't open %s: %s\n"), fn, smb_strerror(errno));
242 		}
243 		free(fn);
244 	}
245 	home_nsmbrc = 0;
246 #ifdef DEBUG
247 	dump_props("after reading user settings");
248 #endif
249 	if (smb_rc == NULL) {
250 		return (ENOENT);
251 	}
252 	return (0);
253 }
254 
255 void
256 smb_simplecrypt(char *dst, const char *src)
257 {
258 	int ch, pos;
259 
260 	*dst++ = '$';
261 	*dst++ = '$';
262 	*dst++ = '1';
263 	pos = 27;
264 	while (*src) {
265 		ch = *src++;
266 		if (isascii(ch))
267 			ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) :
268 			    islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch);
269 		ch ^= pos;
270 		pos += 13;
271 		sprintf(dst, "%02x", ch);
272 		dst += 2;
273 	}
274 	*dst = 0;
275 }
276 
277 int
278 smb_simpledecrypt(char *dst, const char *src)
279 {
280 	char *ep, hexval[3];
281 	int len, ch, pos;
282 
283 	if (strncmp(src, "$$1", 3) != 0)
284 		return (EINVAL);
285 	src += 3;
286 	len = strlen(src);
287 	if (len & 1)
288 		return (EINVAL);
289 	len /= 2;
290 	hexval[2] = 0;
291 	pos = 27;
292 	while (len--) {
293 		hexval[0] = *src++;
294 		hexval[1] = *src++;
295 		ch = strtoul(hexval, &ep, 16);
296 		if (*ep != 0)
297 			return (EINVAL);
298 		ch ^= pos;
299 		pos += 13;
300 		if (isascii(ch))
301 			ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) :
302 			    islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch);
303 		*dst++ = ch;
304 	}
305 	*dst = 0;
306 	return (0);
307 }
308 
309 
310 static int
311 safe_execv(char *args[])
312 {
313 	int	pid;
314 	int status;
315 
316 	pid = fork();
317 	if (pid == 0) {
318 		(void) execv(args[0], args);
319 		/* Changed from errx() to fprintf(stderr) -Pavan */
320 		fprintf(stderr, dgettext(TEXT_DOMAIN,
321 		    "%s: execv %s failed, %s\n"), __progname,
322 		    args[0], smb_strerror(errno));
323 	}
324 	if (pid == -1) {
325 		fprintf(stderr, dgettext(TEXT_DOMAIN, "%s: fork failed, %s\n"),
326 		    __progname, smb_strerror(errno));
327 		return (1);
328 	}
329 	if (wait4(pid, &status, 0, NULL) != pid) {
330 		fprintf(stderr, dgettext(TEXT_DOMAIN,
331 		    "%s: BUG executing %s command\n"), __progname, args[0]);
332 		return (1);
333 	} else if (!WIFEXITED(status)) {
334 		fprintf(stderr, dgettext(TEXT_DOMAIN,
335 		    "%s: %s command aborted by signal %d\n"),
336 		    __progname, args[0], WTERMSIG(status));
337 		return (1);
338 	} else if (WEXITSTATUS(status)) {
339 		fprintf(stderr, dgettext(TEXT_DOMAIN,
340 		    "%s: %s command failed, exit status %d: %s\n"),
341 		    __progname, args[0], WEXITSTATUS(status),
342 		    smb_strerror(WEXITSTATUS(status)));
343 		return (1);
344 	}
345 	return (0);
346 }
347 
348 
349 void
350 dropsuid()
351 {
352 	/* drop setuid root privs asap */
353 	eff_uid = geteuid();
354 	real_uid = getuid();
355 	seteuid(real_uid);
356 }
357 
358 
359 #define	KEXTLOAD_COMMAND	"/sbin/kextload"
360 #define	FS_KEXT_DIR		"/System/Library/Extensions/smbfs.kext"
361 #define	FULL_KEXTNAME		"com.apple.filesystems.smbfs"
362 
363 
364 int
365 loadsmbvfs()
366 {
367 	char *kextargs[] = {KEXTLOAD_COMMAND, FS_KEXT_DIR, NULL};
368 	int error = 0;
369 
370 	/*
371 	 * temporarily revert to root (required for kextload)
372 	 */
373 	seteuid(eff_uid);
374 	error = safe_execv(kextargs);
375 	seteuid(real_uid); /* and back to real user */
376 	return (error);
377 }
378 
379 #undef __progname
380 
381 char *__progname = NULL;
382 
383 char *
384 smb_getprogname()
385 {
386 	char *p;
387 
388 	if (__progname == NULL) {
389 		__progname = (char *)getexecname();
390 		if ((p = strrchr(__progname, '/')) != 0)
391 			__progname = p + 1;
392 	}
393 	return (__progname);
394 }
395