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