Merge branch 'vendor/ZSTD' into master
[dragonfly.git] / contrib / smbfs / lib / smb / subr.c
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.12 2001/08/22 03:31:37 bp Exp $
33  */
34
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/errno.h>
38 #include <sys/sysctl.h>
39 #include <sys/syscall.h>
40 #include <unistd.h>
41 #include <ctype.h>
42 #include <string.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 #include <err.h>
47
48 #include <netsmb/netbios.h>
49 #include <netsmb/smb_lib.h>
50 #include <netsmb/nb_lib.h>
51 #include <cflib.h>
52
53 #ifdef APPLE
54 #include <sysexits.h>
55 #include <sys/wait.h>
56 #include <mach/mach.h>
57 #include <mach/mach_error.h>
58
59 uid_t real_uid, eff_uid;
60 #endif
61
62 extern char *__progname;
63
64 static int smblib_initialized;
65
66 struct rcfile *smb_rc;
67
68 int
69 smb_lib_init(void)
70 {
71         int error;
72         int kv;
73         size_t kvlen = sizeof(kv);
74
75         if (smblib_initialized)
76                 return 0;
77         error = sysctlbyname("net.smb.version", &kv, &kvlen, NULL, 0);
78         if (error) {
79                 warnx("%s: can't find kernel module\n", __FUNCTION__);
80                 return error;
81         }
82         if (NSMB_VERSION != kv) {
83                 warnx("%s: kernel module version(%d) don't match library(%d).\n", __FUNCTION__, kv, NSMB_VERSION);
84                 return EINVAL;
85         }
86         if ((error = nls_setlocale("")) != 0) {
87                 warnx("%s: can't initialise locale\n", __FUNCTION__);
88                 return error;
89         }
90         smblib_initialized++;
91         return 0;
92 }
93
94 /*
95  * Print a (descriptive) error message
96  * error values:
97  *         0 - no specific error code available;
98  *  1..32767 - system error
99  */
100 void
101 smb_error(const char *fmt, int error,...) {
102         va_list ap;
103         const char *cp;
104         int errtype = error & SMB_ERRTYPE_MASK;
105
106         fprintf(stderr, "%s: ", __progname);
107         va_start(ap, error);
108         vfprintf(stderr, fmt, ap);
109         va_end(ap);
110         if (error == -1)
111                 error = errno;
112         else
113                 error &= ~SMB_ERRTYPE_MASK;
114         switch (errtype) {
115             case SMB_SYS_ERROR:
116                 if (error)
117                         fprintf(stderr, ": syserr = %s\n", strerror(error));
118                 else
119                         fprintf(stderr, "\n");
120                 break;
121             case SMB_RAP_ERROR:
122                 fprintf(stderr, ": raperr = %d (0x%04x)\n", error, error);
123                 break;
124             case SMB_NB_ERROR:
125                 cp = nb_strerror(error);
126                 if (cp == NULL)
127                         fprintf(stderr, ": nberr = unknown (0x%04x)\n", error);
128                 else
129                         fprintf(stderr, ": nberr = %s\n", cp);
130                 break;
131             default:
132                 fprintf(stderr, "\n");
133         }
134 }
135
136 char *
137 smb_printb(char *dest, int flags, const struct smb_bitname *bnp) {
138         int first = 1;
139
140         strcpy(dest, "<");
141         for(; bnp->bn_bit; bnp++) {
142                 if (flags & bnp->bn_bit) {
143                         strcat(dest, bnp->bn_name);
144                         first = 0;
145                 }
146                 if (!first && (flags & bnp[1].bn_bit))
147                         strcat(dest, "|");
148         }
149         strcat(dest, ">");
150         return dest;
151 }
152
153 /*
154  * first read ~/.smbrc, next try to merge SMB_CFG_FILE
155  */
156 int
157 smb_open_rcfile(void)
158 {
159         char *home, *fn;
160         int error;
161
162         home = getenv("HOME");
163         if (home) {
164                 fn = malloc(strlen(home) + 20);
165                 sprintf(fn, "%s/.nsmbrc", home);
166                 error = rc_open(fn, "r", &smb_rc);
167                 free(fn);
168         }
169         error = rc_merge(SMB_CFG_FILE, &smb_rc);
170         if (smb_rc == NULL) {
171                 printf("Warning: no cfg file(s) found.\n");
172                 return ENOENT;
173         }
174         return 0;
175 }
176
177 void *
178 smb_dumptree(void)
179 {
180         size_t len;
181         void *p;
182         int error;
183         
184 #ifdef APPLE
185         seteuid(eff_uid); /* restore setuid root briefly */
186 #endif
187         error = sysctlbyname("net.smb.treedump", NULL, &len, NULL, 0);
188 #ifdef APPLE
189         seteuid(real_uid); /* and back to real user */
190 #endif
191         if (error)
192                 return NULL;
193         p = malloc(len);
194         if (p == NULL)
195                 return NULL;
196 #ifdef APPLE
197         seteuid(eff_uid); /* restore setuid root briefly */
198 #endif
199         error = sysctlbyname("net.smb.treedump", p, &len, NULL, 0);
200 #ifdef APPLE
201         seteuid(real_uid); /* and back to real user */
202 #endif
203         if (error) {
204                 free(p);
205                 return NULL;
206         }
207         return p;
208 }
209
210 char *
211 smb_simplecrypt(char *dst, const char *src)
212 {
213         int ch, pos;
214         char *dp;
215
216         if (dst == NULL) {
217                 dst = malloc(4 + 2 * strlen(src));
218                 if (dst == NULL)
219                         return NULL;
220         }
221         dp = dst;
222         *dst++ = '$';
223         *dst++ = '$';
224         *dst++ = '1';
225         pos = 27;
226         while (*src) {
227                 ch = *src++;
228                 if (isascii(ch))
229                     ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) :
230                           islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch);
231                 ch ^= pos;
232                 pos += 13;
233                 if (pos > 256)
234                         pos -= 256;
235                 sprintf(dst, "%02x", ch);
236                 dst += 2;
237         }
238         *dst = 0;
239         return dp;
240 }
241
242 int
243 smb_simpledecrypt(char *dst, const char *src)
244 {
245         char *ep, hexval[3];
246         int len, ch, pos;
247
248         if (strncmp(src, "$$1", 3) != 0)
249                 return EINVAL;
250         src += 3;
251         len = strlen(src);
252         if (len & 1)
253                 return EINVAL;
254         len /= 2;
255         hexval[2] = 0;
256         pos = 27;
257         while (len--) {
258                 hexval[0] = *src++;
259                 hexval[1] = *src++;
260                 ch = strtoul(hexval, &ep, 16);
261                 if (*ep != 0)
262                         return EINVAL;
263                 ch ^= pos;
264                 pos += 13;
265                 if (pos > 256)
266                         pos -= 256;
267                 if (isascii(ch))
268                     ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) :
269                           islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch);
270                 *dst++ = ch;
271         }
272         *dst = 0;
273         return 0;
274 }
275
276
277 #ifdef APPLE
278 static int
279 safe_execv(char *args[])
280 {       
281         int          pid;   
282         union wait      status;
283         
284         pid = fork();  
285         if (pid == 0) {
286                 (void)execv(args[0], args);
287                 errx(EX_OSERR, "%s: execv %s failed, %s\n", __progname,
288                      args[0], strerror(errno));
289         }
290         if (pid == -1) {
291                 fprintf(stderr, "%s: fork failed, %s\n", __progname,
292                         strerror(errno));
293                 return (1);
294         }
295         if (wait4(pid, (int *)&status, 0, NULL) != pid) {
296                 fprintf(stderr, "%s: BUG executing %s command\n", __progname,
297                         args[0]);  
298                 return (1);
299         } else if (!WIFEXITED(status)) {
300                 fprintf(stderr, "%s: %s command aborted by signal %d\n",
301                         __progname, args[0], WTERMSIG(status));
302                 return (1);
303         } else if (WEXITSTATUS(status)) {
304                 fprintf(stderr, "%s: %s command failed, exit status %d: %s\n",
305                         __progname, args[0], WEXITSTATUS(status),
306                         strerror(WEXITSTATUS(status)));
307                 return (1);
308         }       
309         return (0);
310 }       
311
312
313 void
314 dropsuid()
315 {
316         /* drop setuid root privs asap */
317         eff_uid = geteuid();
318         real_uid = getuid();
319         seteuid(real_uid);
320         return;
321 }
322
323
324 static int
325 kextisloaded(char * kextname)
326 {
327         mach_port_t kernel_port;
328         kmod_info_t *k, *loaded_modules = 0;
329         int err, loaded_count = 0;
330
331         /* on error return not loaded - to make loadsmbvfs fail */
332
333         err = task_for_pid(mach_task_self(), 0, &kernel_port);
334         if (err) {
335                 fprintf(stderr, "%s: %s: %s\n", __progname,
336                         "unable to get kernel task port",
337                         mach_error_string(err));
338                 return (0);
339         }
340         err = kmod_get_info(kernel_port, (void *)&loaded_modules,
341                             &loaded_count); /* never freed */
342         if (err) {
343                 fprintf(stderr, "%s: %s: %s\n", __progname,
344                         "kmod_get_info() failed",
345                         mach_error_string(err));
346                 return (0);
347         }
348         for (k = loaded_modules; k; k = k->next ? k+1 : 0)
349                 if (!strcmp(k->name, kextname))
350                         return (1);
351         return (0);
352 }
353
354
355 #define KEXTLOAD_COMMAND        "/sbin/kextload"
356 #define FS_KEXT_DIR             "/System/Library/Extensions/smbfs.kext"
357 #define FULL_KEXTNAME           "com.apple.filesystems.smbfs"
358
359
360 int
361 loadsmbvfs()
362 {       
363         const char *kextargs[] = {KEXTLOAD_COMMAND, FS_KEXT_DIR, NULL};
364         int error = 0;
365
366         /*
367          * temporarily revert to root (required for kextload)
368          */
369         seteuid(eff_uid);
370         if (!kextisloaded(FULL_KEXTNAME)) {
371                 error = safe_execv(kextargs);
372                 if (!error)
373                         error = !kextisloaded(FULL_KEXTNAME);
374         }
375         seteuid(real_uid); /* and back to real user */
376         return (error);
377 }       
378 #endif /* APPLE */