187866Ssheldonh/*
287866Ssheldonh * Copyright (c) 2000, Boris Popov
387866Ssheldonh * All rights reserved.
487866Ssheldonh *
587866Ssheldonh * Redistribution and use in source and binary forms, with or without
687866Ssheldonh * modification, are permitted provided that the following conditions
787866Ssheldonh * are met:
887866Ssheldonh * 1. Redistributions of source code must retain the above copyright
987866Ssheldonh *    notice, this list of conditions and the following disclaimer.
1087866Ssheldonh * 2. Redistributions in binary form must reproduce the above copyright
1187866Ssheldonh *    notice, this list of conditions and the following disclaimer in the
1287866Ssheldonh *    documentation and/or other materials provided with the distribution.
1387866Ssheldonh * 3. All advertising materials mentioning features or use of this software
1487866Ssheldonh *    must display the following acknowledgement:
1587866Ssheldonh *    This product includes software developed by Boris Popov.
1687866Ssheldonh * 4. Neither the name of the author nor the names of any co-contributors
1787866Ssheldonh *    may be used to endorse or promote products derived from this software
1887866Ssheldonh *    without specific prior written permission.
1987866Ssheldonh *
2087866Ssheldonh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2187866Ssheldonh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2287866Ssheldonh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2387866Ssheldonh * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2487866Ssheldonh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2587866Ssheldonh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2687866Ssheldonh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2787866Ssheldonh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2887866Ssheldonh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2987866Ssheldonh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3087866Ssheldonh * SUCH DAMAGE.
3187866Ssheldonh *
3288282Ssheldonh * $Id: subr.c,v 1.12 2001/08/22 03:31:37 bp Exp $
3387866Ssheldonh */
3487866Ssheldonh
3587866Ssheldonh#include <sys/param.h>
3687866Ssheldonh#include <sys/types.h>
3787866Ssheldonh#include <sys/errno.h>
3887866Ssheldonh#include <sys/sysctl.h>
3987866Ssheldonh#include <sys/syscall.h>
4087866Ssheldonh#include <unistd.h>
4187866Ssheldonh#include <ctype.h>
4287866Ssheldonh#include <string.h>
4387866Ssheldonh#include <stdio.h>
4487866Ssheldonh#include <stdlib.h>
4587866Ssheldonh#include <stdarg.h>
4687866Ssheldonh#include <err.h>
4787866Ssheldonh
4887866Ssheldonh#include <netsmb/netbios.h>
4987866Ssheldonh#include <netsmb/smb_lib.h>
5087866Ssheldonh#include <netsmb/nb_lib.h>
5187866Ssheldonh#include <cflib.h>
5287866Ssheldonh
5388282Ssheldonh#ifdef APPLE
5488282Ssheldonh#include <sysexits.h>
5588282Ssheldonh#include <sys/wait.h>
5688282Ssheldonh#include <mach/mach.h>
5788282Ssheldonh#include <mach/mach_error.h>
5888282Ssheldonh
5988282Ssheldonhuid_t real_uid, eff_uid;
6088282Ssheldonh#endif
6188282Ssheldonh
6287866Ssheldonhextern char *__progname;
6387866Ssheldonh
6487866Ssheldonhstatic int smblib_initialized;
6587866Ssheldonh
6687866Ssheldonhstruct rcfile *smb_rc;
6787866Ssheldonh
6887866Ssheldonhint
6987866Ssheldonhsmb_lib_init(void)
7087866Ssheldonh{
7187866Ssheldonh	int error;
7287866Ssheldonh	int kv;
7387866Ssheldonh	size_t kvlen = sizeof(kv);
7487866Ssheldonh
7587866Ssheldonh	if (smblib_initialized)
7687866Ssheldonh		return 0;
7787866Ssheldonh#if __FreeBSD_version > 400000
7887866Ssheldonh	error = sysctlbyname("net.smb.version", &kv, &kvlen, NULL, 0);
7987866Ssheldonh	if (error) {
8087866Ssheldonh		warnx("%s: can't find kernel module\n", __FUNCTION__);
8187866Ssheldonh		return error;
8287866Ssheldonh	}
8387866Ssheldonh	if (NSMB_VERSION != kv) {
8487866Ssheldonh		warnx("%s: kernel module version(%d) don't match library(%d).\n", __FUNCTION__, kv, NSMB_VERSION);
8587866Ssheldonh		return EINVAL;
8687866Ssheldonh	}
8787866Ssheldonh#endif
8887866Ssheldonh	if ((error = nls_setlocale("")) != 0) {
8987866Ssheldonh		warnx("%s: can't initialise locale\n", __FUNCTION__);
9087866Ssheldonh		return error;
9187866Ssheldonh	}
9287866Ssheldonh	smblib_initialized++;
9387866Ssheldonh	return 0;
9487866Ssheldonh}
9587866Ssheldonh
9687866Ssheldonh/*
9787866Ssheldonh * Print a (descriptive) error message
9887866Ssheldonh * error values:
9987866Ssheldonh *  	   0 - no specific error code available;
10087866Ssheldonh *  1..32767 - system error
10187866Ssheldonh */
10287866Ssheldonhvoid
10387866Ssheldonhsmb_error(const char *fmt, int error,...) {
10487866Ssheldonh	va_list ap;
10587866Ssheldonh	const char *cp;
10687866Ssheldonh	int errtype = error & SMB_ERRTYPE_MASK;
10787866Ssheldonh
10887866Ssheldonh	fprintf(stderr, "%s: ", __progname);
10987866Ssheldonh	va_start(ap, error);
11087866Ssheldonh	vfprintf(stderr, fmt, ap);
11187866Ssheldonh	va_end(ap);
11287866Ssheldonh	if (error == -1)
11387866Ssheldonh		error = errno;
11487866Ssheldonh	else
11587866Ssheldonh		error &= ~SMB_ERRTYPE_MASK;
11687866Ssheldonh	switch (errtype) {
11787866Ssheldonh	    case SMB_SYS_ERROR:
11887866Ssheldonh		if (error)
11987866Ssheldonh			fprintf(stderr, ": syserr = %s\n", strerror(error));
12087866Ssheldonh		else
12187866Ssheldonh			fprintf(stderr, "\n");
12287866Ssheldonh		break;
12387866Ssheldonh	    case SMB_RAP_ERROR:
12487866Ssheldonh		fprintf(stderr, ": raperr = %d (0x%04x)\n", error, error);
12587866Ssheldonh		break;
12687866Ssheldonh	    case SMB_NB_ERROR:
12787866Ssheldonh		cp = nb_strerror(error);
12887866Ssheldonh		if (cp == NULL)
12987866Ssheldonh			fprintf(stderr, ": nberr = unknown (0x%04x)\n", error);
13087866Ssheldonh		else
13187866Ssheldonh			fprintf(stderr, ": nberr = %s\n", cp);
13287866Ssheldonh		break;
13387866Ssheldonh	    default:
13487866Ssheldonh		fprintf(stderr, "\n");
13587866Ssheldonh	}
13687866Ssheldonh}
13787866Ssheldonh
13887866Ssheldonhchar *
13987866Ssheldonhsmb_printb(char *dest, int flags, const struct smb_bitname *bnp) {
14087866Ssheldonh	int first = 1;
14187866Ssheldonh
14287866Ssheldonh	strcpy(dest, "<");
14387866Ssheldonh	for(; bnp->bn_bit; bnp++) {
14487866Ssheldonh		if (flags & bnp->bn_bit) {
14587866Ssheldonh			strcat(dest, bnp->bn_name);
14687866Ssheldonh			first = 0;
14787866Ssheldonh		}
14887866Ssheldonh		if (!first && (flags & bnp[1].bn_bit))
14987866Ssheldonh			strcat(dest, "|");
15087866Ssheldonh	}
15187866Ssheldonh	strcat(dest, ">");
15287866Ssheldonh	return dest;
15387866Ssheldonh}
15487866Ssheldonh
15587866Ssheldonh/*
15687866Ssheldonh * first read ~/.smbrc, next try to merge SMB_CFG_FILE
15787866Ssheldonh */
15887866Ssheldonhint
15987866Ssheldonhsmb_open_rcfile(void)
16087866Ssheldonh{
16187866Ssheldonh	char *home, *fn;
16287866Ssheldonh	int error;
16387866Ssheldonh
16487866Ssheldonh	home = getenv("HOME");
16587866Ssheldonh	if (home) {
16687866Ssheldonh		fn = malloc(strlen(home) + 20);
16787866Ssheldonh		sprintf(fn, "%s/.nsmbrc", home);
16887866Ssheldonh		error = rc_open(fn, "r", &smb_rc);
16987866Ssheldonh		free(fn);
17087866Ssheldonh	}
17187866Ssheldonh	error = rc_merge(SMB_CFG_FILE, &smb_rc);
17287866Ssheldonh	if (smb_rc == NULL) {
17387866Ssheldonh		printf("Warning: no cfg file(s) found.\n");
17487866Ssheldonh		return ENOENT;
17587866Ssheldonh	}
17687866Ssheldonh	return 0;
17787866Ssheldonh}
17887866Ssheldonh
17987866Ssheldonhvoid *
18087866Ssheldonhsmb_dumptree(void)
18187866Ssheldonh{
18287866Ssheldonh	size_t len;
18387866Ssheldonh	void *p;
18487866Ssheldonh	int error;
18587866Ssheldonh
18688282Ssheldonh#ifdef APPLE
18788282Ssheldonh	seteuid(eff_uid); /* restore setuid root briefly */
18888282Ssheldonh#endif
18987866Ssheldonh	error = sysctlbyname("net.smb.treedump", NULL, &len, NULL, 0);
19088282Ssheldonh#ifdef APPLE
19188282Ssheldonh	seteuid(real_uid); /* and back to real user */
19288282Ssheldonh#endif
19387866Ssheldonh	if (error)
19487866Ssheldonh		return NULL;
19587866Ssheldonh	p = malloc(len);
19687866Ssheldonh	if (p == NULL)
19787866Ssheldonh		return NULL;
19888282Ssheldonh#ifdef APPLE
19988282Ssheldonh	seteuid(eff_uid); /* restore setuid root briefly */
20088282Ssheldonh#endif
20187866Ssheldonh	error = sysctlbyname("net.smb.treedump", p, &len, NULL, 0);
20288282Ssheldonh#ifdef APPLE
20388282Ssheldonh	seteuid(real_uid); /* and back to real user */
20488282Ssheldonh#endif
20587866Ssheldonh	if (error) {
20687866Ssheldonh		free(p);
20787866Ssheldonh		return NULL;
20887866Ssheldonh	}
20987866Ssheldonh	return p;
21087866Ssheldonh}
21187866Ssheldonh
21288282Ssheldonhchar *
21387866Ssheldonhsmb_simplecrypt(char *dst, const char *src)
21487866Ssheldonh{
21587866Ssheldonh	int ch, pos;
21688282Ssheldonh	char *dp;
21787866Ssheldonh
21888282Ssheldonh	if (dst == NULL) {
21988282Ssheldonh		dst = malloc(4 + 2 * strlen(src));
22088282Ssheldonh		if (dst == NULL)
22188282Ssheldonh			return NULL;
22288282Ssheldonh	}
22388282Ssheldonh	dp = dst;
22487866Ssheldonh	*dst++ = '$';
22587866Ssheldonh	*dst++ = '$';
22687866Ssheldonh	*dst++ = '1';
22787866Ssheldonh	pos = 27;
22887866Ssheldonh	while (*src) {
22987866Ssheldonh		ch = *src++;
23087866Ssheldonh		if (isascii(ch))
23187866Ssheldonh		    ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) :
23287866Ssheldonh			  islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch);
23387866Ssheldonh		ch ^= pos;
23487866Ssheldonh		pos += 13;
23587866Ssheldonh		sprintf(dst, "%02x", ch);
23687866Ssheldonh		dst += 2;
23787866Ssheldonh	}
23887866Ssheldonh	*dst = 0;
23988282Ssheldonh	return dp;
24087866Ssheldonh}
24187866Ssheldonh
24287866Ssheldonhint
24387866Ssheldonhsmb_simpledecrypt(char *dst, const char *src)
24487866Ssheldonh{
24587866Ssheldonh	char *ep, hexval[3];
24687866Ssheldonh	int len, ch, pos;
24787866Ssheldonh
24887866Ssheldonh	if (strncmp(src, "$$1", 3) != 0)
24987866Ssheldonh		return EINVAL;
25087866Ssheldonh	src += 3;
25187866Ssheldonh	len = strlen(src);
25287866Ssheldonh	if (len & 1)
25387866Ssheldonh		return EINVAL;
25487866Ssheldonh	len /= 2;
25587866Ssheldonh	hexval[2] = 0;
25687866Ssheldonh	pos = 27;
25787866Ssheldonh	while (len--) {
25887866Ssheldonh		hexval[0] = *src++;
25987866Ssheldonh		hexval[1] = *src++;
26087866Ssheldonh		ch = strtoul(hexval, &ep, 16);
26187866Ssheldonh		if (*ep != 0)
26287866Ssheldonh			return EINVAL;
26387866Ssheldonh		ch ^= pos;
26487866Ssheldonh		pos += 13;
26587866Ssheldonh		if (isascii(ch))
26687866Ssheldonh		    ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) :
26787866Ssheldonh			  islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch);
26887866Ssheldonh		*dst++ = ch;
26987866Ssheldonh	}
27087866Ssheldonh	*dst = 0;
27187866Ssheldonh	return 0;
27287866Ssheldonh}
27388282Ssheldonh
27488282Ssheldonh
27588282Ssheldonh#ifdef APPLE
27688282Ssheldonhstatic int
27788282Ssheldonhsafe_execv(char *args[])
27888282Ssheldonh{
27988282Ssheldonh	int	     pid;
28088282Ssheldonh	union wait      status;
28188282Ssheldonh
28288282Ssheldonh	pid = fork();
28388282Ssheldonh	if (pid == 0) {
28488282Ssheldonh		(void)execv(args[0], args);
28588282Ssheldonh		errx(EX_OSERR, "%s: execv %s failed, %s\n", __progname,
28688282Ssheldonh		     args[0], strerror(errno));
28788282Ssheldonh	}
28888282Ssheldonh	if (pid == -1) {
28988282Ssheldonh		fprintf(stderr, "%s: fork failed, %s\n", __progname,
29088282Ssheldonh			strerror(errno));
29188282Ssheldonh		return (1);
29288282Ssheldonh	}
29388282Ssheldonh	if (wait4(pid, (int *)&status, 0, NULL) != pid) {
29488282Ssheldonh		fprintf(stderr, "%s: BUG executing %s command\n", __progname,
29588282Ssheldonh			args[0]);
29688282Ssheldonh		return (1);
29788282Ssheldonh	} else if (!WIFEXITED(status)) {
29888282Ssheldonh		fprintf(stderr, "%s: %s command aborted by signal %d\n",
29988282Ssheldonh			__progname, args[0], WTERMSIG(status));
30088282Ssheldonh		return (1);
30188282Ssheldonh	} else if (WEXITSTATUS(status)) {
30288282Ssheldonh		fprintf(stderr, "%s: %s command failed, exit status %d: %s\n",
30388282Ssheldonh			__progname, args[0], WEXITSTATUS(status),
30488282Ssheldonh			strerror(WEXITSTATUS(status)));
30588282Ssheldonh		return (1);
30688282Ssheldonh	}
30788282Ssheldonh	return (0);
30888282Ssheldonh}
30988282Ssheldonh
31088282Ssheldonh
31188282Ssheldonhvoid
31288282Ssheldonhdropsuid()
31388282Ssheldonh{
31488282Ssheldonh	/* drop setuid root privs asap */
31588282Ssheldonh	eff_uid = geteuid();
31688282Ssheldonh	real_uid = getuid();
31788282Ssheldonh	seteuid(real_uid);
31888282Ssheldonh	return;
31988282Ssheldonh}
32088282Ssheldonh
32188282Ssheldonh
32288282Ssheldonhstatic int
32388282Ssheldonhkextisloaded(char * kextname)
32488282Ssheldonh{
32588282Ssheldonh	mach_port_t kernel_port;
32688282Ssheldonh	kmod_info_t *k, *loaded_modules = 0;
32788282Ssheldonh	int err, loaded_count = 0;
32888282Ssheldonh
32988282Ssheldonh	/* on error return not loaded - to make loadsmbvfs fail */
33088282Ssheldonh
33188282Ssheldonh	err = task_for_pid(mach_task_self(), 0, &kernel_port);
33288282Ssheldonh	if (err) {
33388282Ssheldonh		fprintf(stderr, "%s: %s: %s\n", __progname,
33488282Ssheldonh			"unable to get kernel task port",
33588282Ssheldonh			mach_error_string(err));
33688282Ssheldonh		return (0);
33788282Ssheldonh	}
33888282Ssheldonh	err = kmod_get_info(kernel_port, (void *)&loaded_modules,
33988282Ssheldonh			    &loaded_count); /* never freed */
34088282Ssheldonh	if (err) {
34188282Ssheldonh		fprintf(stderr, "%s: %s: %s\n", __progname,
34288282Ssheldonh			"kmod_get_info() failed",
34388282Ssheldonh			mach_error_string(err));
34488282Ssheldonh		return (0);
34588282Ssheldonh	}
34688282Ssheldonh	for (k = loaded_modules; k; k = k->next ? k+1 : 0)
34788282Ssheldonh		if (!strcmp(k->name, kextname))
34888282Ssheldonh			return (1);
34988282Ssheldonh	return (0);
35088282Ssheldonh}
35188282Ssheldonh
35288282Ssheldonh
35388282Ssheldonh#define KEXTLOAD_COMMAND	"/sbin/kextload"
35488282Ssheldonh#define FS_KEXT_DIR		"/System/Library/Extensions/smbfs.kext"
35588282Ssheldonh#define FULL_KEXTNAME		"com.apple.filesystems.smbfs"
35688282Ssheldonh
35788282Ssheldonh
35888282Ssheldonhint
35988282Ssheldonhloadsmbvfs()
36088282Ssheldonh{
36188282Ssheldonh	const char *kextargs[] = {KEXTLOAD_COMMAND, FS_KEXT_DIR, NULL};
36288282Ssheldonh	int error = 0;
36388282Ssheldonh
36488282Ssheldonh	/*
36588282Ssheldonh	 * temporarily revert to root (required for kextload)
36688282Ssheldonh	 */
36788282Ssheldonh	seteuid(eff_uid);
36888282Ssheldonh	if (!kextisloaded(FULL_KEXTNAME)) {
36988282Ssheldonh		error = safe_execv(kextargs);
37088282Ssheldonh		if (!error)
37188282Ssheldonh			error = !kextisloaded(FULL_KEXTNAME);
37288282Ssheldonh	}
37388282Ssheldonh	seteuid(real_uid); /* and back to real user */
37488282Ssheldonh	return (error);
37588282Ssheldonh}
37688282Ssheldonh#endif /* APPLE */
377