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