]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/smbfs/lib/smb/ctx.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / smbfs / lib / smb / ctx.c
1 /*
2  * Copyright (c) 2000-2002, 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: ctx.c,v 1.24 2002/04/13 14:35:28 bp Exp $
33  * $FreeBSD$
34  */
35 #include <sys/param.h>
36 #include <sys/sysctl.h>
37 #include <sys/ioctl.h>
38 #include <sys/time.h>
39 #include <sys/mount.h>
40 #include <fcntl.h>
41 #include <ctype.h>
42 #include <errno.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <pwd.h>
47 #include <grp.h>
48 #include <unistd.h>
49 #include <sys/iconv.h>
50
51 #define NB_NEEDRESOLVER
52
53 #include <netsmb/smb_lib.h>
54 #include <netsmb/netbios.h>
55 #include <netsmb/nb_lib.h>
56 #include <netsmb/smb_conn.h>
57 #include <cflib.h>
58
59 /*
60  * Prescan command line for [-U user] argument
61  * and fill context with defaults
62  */
63 int
64 smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[],
65         int minlevel, int maxlevel, int sharetype)
66 {
67         int  opt, error = 0;
68         uid_t euid;
69         const char *arg, *cp;
70         struct passwd *pwd;
71
72         bzero(ctx,sizeof(*ctx));
73         error = nb_ctx_create(&ctx->ct_nb);
74         if (error)
75                 return error;
76         ctx->ct_fd = -1;
77         ctx->ct_parsedlevel = SMBL_NONE;
78         ctx->ct_minlevel = minlevel;
79         ctx->ct_maxlevel = maxlevel;
80         ctx->ct_smbtcpport = SMB_TCP_PORT;
81
82         ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE;
83         ctx->ct_ssn.ioc_timeout = 15;
84         ctx->ct_ssn.ioc_retrycount = 4;
85         ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER;
86         ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP;
87         ctx->ct_ssn.ioc_mode = SMBM_EXEC;
88         ctx->ct_ssn.ioc_rights = SMBM_DEFAULT;
89
90         ctx->ct_sh.ioc_opt = SMBVOPT_CREATE;
91         ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
92         ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
93         ctx->ct_sh.ioc_mode = SMBM_EXEC;
94         ctx->ct_sh.ioc_rights = SMBM_DEFAULT;
95         ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
96         ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
97
98         nb_ctx_setscope(ctx->ct_nb, "");
99         euid = geteuid();
100         if ((pwd = getpwuid(euid)) != NULL) {
101                 smb_ctx_setuser(ctx, pwd->pw_name);
102                 endpwent();
103         } else if (euid == 0)
104                 smb_ctx_setuser(ctx, "root");
105         else
106                 return 0;
107         if (argv == NULL)
108                 return 0;
109         for (opt = 1; opt < argc; opt++) {
110                 cp = argv[opt];
111                 if (strncmp(cp, "//", 2) != 0)
112                         continue;
113                 error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp);
114                 if (error)
115                         return error;
116                 ctx->ct_uncnext = cp;
117                 break;
118         }
119         while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) {
120                 arg = cf_optarg;
121                 switch (opt) {
122                     case 'E':
123                         error = smb_ctx_setcharset(ctx, arg);
124                         if (error)
125                                 return error;
126                         break;
127                     case 'L':
128                         error = nls_setlocale(arg);
129                         if (error)
130                                 break;
131                         break;
132                     case 'U':
133                         error = smb_ctx_setuser(ctx, arg);
134                         break;
135                 }
136         }
137         cf_optind = cf_optreset = 1;
138         return error;
139 }
140
141 void
142 smb_ctx_done(struct smb_ctx *ctx)
143 {
144         if (ctx->ct_ssn.ioc_server)
145                 nb_snbfree(ctx->ct_ssn.ioc_server);
146         if (ctx->ct_ssn.ioc_local)
147                 nb_snbfree(ctx->ct_ssn.ioc_local);
148         if (ctx->ct_srvaddr)
149                 free(ctx->ct_srvaddr);
150         if (ctx->ct_nb)
151                 nb_ctx_done(ctx->ct_nb);
152 }
153
154 static int
155 getsubstring(const char *p, u_char sep, char *dest, int maxlen, const char **next)
156 {
157         int len;
158
159         maxlen--;
160         for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
161                 if (*p == 0)
162                         return EINVAL;
163                 *dest = *p;
164         }
165         *dest = 0;
166         *next = *p ? p + 1 : p;
167         return 0;
168 }
169
170 /*
171  * Here we expect something like "[proto:]//[user@]host[:psmb[:pnb]][/share][/path]"
172  */
173 int
174 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
175         const char **next)
176 {
177         const char *p = unc;
178         char *p1, *psmb, *pnb;
179         char tmp[1024];
180         int error ;
181
182         ctx->ct_parsedlevel = SMBL_NONE;
183         if (*p++ != '/' || *p++ != '/') {
184                 smb_error("UNC should start with '//'", 0);
185                 return EINVAL;
186         }
187         p1 = tmp;
188         error = getsubstring(p, '@', p1, sizeof(tmp), &p);
189         if (!error) {
190                 if (ctx->ct_maxlevel < SMBL_VC) {
191                         smb_error("no user name required", 0);
192                         return EINVAL;
193                 }
194                 if (*p1 == 0) {
195                         smb_error("empty user name", 0);
196                         return EINVAL;
197                 }
198                 error = smb_ctx_setuser(ctx, tmp);
199                 if (error)
200                         return error;
201                 ctx->ct_parsedlevel = SMBL_VC;
202         }
203         error = getsubstring(p, '/', p1, sizeof(tmp), &p);
204         if (error) {
205                 error = getsubstring(p, '\0', p1, sizeof(tmp), &p);
206                 if (error) {
207                         smb_error("no server name found", 0);
208                         return error;
209                 }
210         }
211         if (*p1 == 0) {
212                 smb_error("empty server name", 0);
213                 return EINVAL;
214         }
215         /*
216          * Check for port number specification.
217          */
218         psmb = strchr(tmp, ':');
219         if (psmb) {
220                 *psmb++ = '\0';
221                 pnb = strchr(psmb, ':');
222                 if (pnb) {
223                         *pnb++ = '\0';
224                         error = smb_ctx_setnbport(ctx, atoi(pnb));
225                         if (error) {
226                                 smb_error("Invalid NetBIOS port number", 0);
227                                 return error;
228                         }
229                 }
230                 error = smb_ctx_setsmbport(ctx, atoi(psmb));
231                 if (error) {
232                         smb_error("Invalid SMB port number", 0);
233                         return error;
234                 }
235         }
236         error = smb_ctx_setserver(ctx, tmp);
237         if (error)
238                 return error;
239         if (sharetype == SMB_ST_NONE) {
240                 *next = p;
241                 return 0;
242         }
243         if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
244                 smb_error("no share name required", 0);
245                 return EINVAL;
246         }
247         error = getsubstring(p, '/', p1, sizeof(tmp), &p);
248         if (error) {
249                 error = getsubstring(p, '\0', p1, sizeof(tmp), &p);
250                 if (error) {
251                         smb_error("unexpected end of line", 0);
252                         return error;
253                 }
254         }
255         if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) {
256                 smb_error("empty share name", 0);
257                 return EINVAL;
258         }
259         *next = p;
260         if (*p1 == 0)
261                 return 0;
262         error = smb_ctx_setshare(ctx, p1, sharetype);
263         return error;
264 }
265
266 int
267 smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
268 {
269         char *cp, *servercs, *localcs;
270         int cslen = sizeof(ctx->ct_ssn.ioc_localcs);
271         int scslen, lcslen, error;
272
273         cp = strchr(arg, ':');
274         lcslen = cp ? (cp - arg) : 0;
275         if (lcslen == 0 || lcslen >= cslen) {
276                 smb_error("invalid local charset specification (%s)", 0, arg);
277                 return EINVAL;
278         }
279         scslen = (size_t)strlen(++cp);
280         if (scslen == 0 || scslen >= cslen) {
281                 smb_error("invalid server charset specification (%s)", 0, arg);
282                 return EINVAL;
283         }
284         localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
285         localcs[lcslen] = 0;
286         servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
287         error = nls_setrecode(localcs, servercs);
288         if (error == 0)
289                 return 0;
290         smb_error("can't initialize iconv support (%s:%s)",
291             error, localcs, servercs);
292         localcs[0] = 0;
293         servercs[0] = 0;
294         return error;
295 }
296
297 int
298 smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
299 {
300         if (strlen(name) > SMB_MAXSRVNAMELEN) {
301                 smb_error("server name '%s' too long", 0, name);
302                 return ENAMETOOLONG;
303         }
304         nls_str_upper(ctx->ct_ssn.ioc_srvname, name);
305         return 0;
306 }
307
308 int
309 smb_ctx_setnbport(struct smb_ctx *ctx, int port)
310 {
311         if (port < 1 || port > 0xffff)
312                 return EINVAL;
313         ctx->ct_nb->nb_nmbtcpport = port;
314         return 0;
315 }
316
317 int
318 smb_ctx_setsmbport(struct smb_ctx *ctx, int port)
319 {
320         if (port < 1 || port > 0xffff)
321                 return EINVAL;
322         ctx->ct_smbtcpport = port;
323         ctx->ct_nb->nb_smbtcpport = port;
324         return 0;
325 }
326
327 int
328 smb_ctx_setuser(struct smb_ctx *ctx, const char *name)
329 {
330         if (strlen(name) > SMB_MAXUSERNAMELEN) {
331                 smb_error("user name '%s' too long", 0, name);
332                 return ENAMETOOLONG;
333         }
334         nls_str_upper(ctx->ct_ssn.ioc_user, name);
335         return 0;
336 }
337
338 int
339 smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name)
340 {
341         if (strlen(name) > SMB_MAXUSERNAMELEN) {
342                 smb_error("workgroup name '%s' too long", 0, name);
343                 return ENAMETOOLONG;
344         }
345         nls_str_upper(ctx->ct_ssn.ioc_workgroup, name);
346         return 0;
347 }
348
349 int
350 smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd)
351 {
352         if (passwd == NULL)
353                 return EINVAL;
354         if (strlen(passwd) > SMB_MAXPASSWORDLEN) {
355                 smb_error("password too long", 0);
356                 return ENAMETOOLONG;
357         }
358         if (strncmp(passwd, "$$1", 3) == 0)
359                 smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd);
360         else
361                 strcpy(ctx->ct_ssn.ioc_password, passwd);
362         strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password);
363         return 0;
364 }
365
366 int
367 smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
368 {
369         if (strlen(share) > SMB_MAXSHARENAMELEN) {
370                 smb_error("share name '%s' too long", 0, share);
371                 return ENAMETOOLONG;
372         }
373         nls_str_upper(ctx->ct_sh.ioc_share, share);
374         if (share[0] != 0)
375                 ctx->ct_parsedlevel = SMBL_SHARE;
376         ctx->ct_sh.ioc_stype = stype;
377         return 0;
378 }
379
380 int
381 smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
382 {
383         if (addr == NULL || addr[0] == 0)
384                 return EINVAL;
385         if (ctx->ct_srvaddr)
386                 free(ctx->ct_srvaddr);
387         if ((ctx->ct_srvaddr = strdup(addr)) == NULL)
388                 return ENOMEM;
389         return 0;
390 }
391
392 static int
393 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
394 {
395         struct group *gr;
396         struct passwd *pw;
397         char *cp;
398
399         cp = strchr(pair, ':');
400         if (cp) {
401                 *cp++ = '\0';
402                 if (*cp) {
403                         gr = getgrnam(cp);
404                         if (gr) {
405                                 *gid = gr->gr_gid;
406                         } else
407                                 smb_error("Invalid group name %s, ignored",
408                                     0, cp);
409                 }
410         }
411         if (*pair) {
412                 pw = getpwnam(pair);
413                 if (pw) {
414                         *uid = pw->pw_uid;
415                 } else
416                         smb_error("Invalid user name %s, ignored", 0, pair);
417         }
418         endpwent();
419         return 0;
420 }
421
422 int
423 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
424 {
425         int error = 0;
426         char *p, *cp;
427
428         switch(opt) {
429             case 'U':
430                 break;
431             case 'I':
432                 error = smb_ctx_setsrvaddr(ctx, arg);
433                 break;
434             case 'M':
435                 ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8);
436                 if (*cp == '/') {
437                         ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8);
438                         ctx->ct_flags |= SMBCF_SRIGHTS;
439                 }
440                 break;
441             case 'N':
442                 ctx->ct_flags |= SMBCF_NOPWD;
443                 break;
444             case 'O':
445                 p = strdup(arg);
446                 cp = strchr(p, '/');
447                 if (cp) {
448                         *cp++ = '\0';
449                         error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner,
450                             &ctx->ct_sh.ioc_group);
451                 }
452                 if (*p && error == 0) {
453                         error = smb_parse_owner(p, &ctx->ct_ssn.ioc_owner,
454                             &ctx->ct_ssn.ioc_group);
455                 }
456                 free(p);
457                 break;
458             case 'P':
459 /*              ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT;*/
460                 break;
461             case 'R':
462                 ctx->ct_ssn.ioc_retrycount = atoi(arg);
463                 break;
464             case 'T':
465                 ctx->ct_ssn.ioc_timeout = atoi(arg);
466                 break;
467             case 'W':
468                 error = smb_ctx_setworkgroup(ctx, arg);
469                 break;
470         }
471         return error;
472 }
473
474 #if 0
475 static void
476 smb_hexdump(const u_char *buf, int len) {
477         int ofs = 0;
478
479         while (len--) {
480                 if (ofs % 16 == 0)
481                         printf("\n%02X: ", ofs);
482                 printf("%02x ", *buf++);
483                 ofs++;
484         }
485         printf("\n");
486 }
487 #endif
488
489
490 static int
491 smb_addiconvtbl(const char *to, const char *from, const u_char *tbl)
492 {
493         int error;
494
495         error = kiconv_add_xlat_table(to, from, tbl);
496         if (error && error != EEXIST) {
497                 smb_error("can not setup kernel iconv table (%s:%s)", error,
498                     from, to);
499                 return error;
500         }
501         return 0;
502 }
503
504 /*
505  * Verify context before connect operation(s),
506  * lookup specified server and try to fill all forgotten fields.
507  */
508 int
509 smb_ctx_resolve(struct smb_ctx *ctx)
510 {
511         struct smbioc_ossn *ssn = &ctx->ct_ssn;
512         struct smbioc_oshare *sh = &ctx->ct_sh;
513         struct nb_name nn;
514         struct sockaddr *sap;
515         struct sockaddr_nb *salocal, *saserver;
516         char *cp;
517         int error = 0;
518         
519         ctx->ct_flags &= ~SMBCF_RESOLVED;
520         if (ssn->ioc_srvname[0] == 0) {
521                 smb_error("no server name specified", 0);
522                 return EINVAL;
523         }
524         if (ssn->ioc_user[0] == 0) {
525                 smb_error("no user name specified for server %s",
526                     0, ssn->ioc_srvname);
527                 return EINVAL;
528         }
529         if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0) {
530                 smb_error("no share name specified for %s@%s",
531                     0, ssn->ioc_user, ssn->ioc_srvname);
532                 return EINVAL;
533         }
534         error = nb_ctx_resolve(ctx->ct_nb);
535         if (error)
536                 return error;
537         if (ssn->ioc_localcs[0] == 0)
538                 strcpy(ssn->ioc_localcs, "ISO8859-1");
539         error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
540         if (error)
541                 return error;
542         error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
543         if (error)
544                 return error;
545         if (ssn->ioc_servercs[0] != 0) {
546                 error = kiconv_add_xlat16_cspairs
547                         (ssn->ioc_servercs, ssn->ioc_localcs);
548                 if (error) return error;
549         }
550         if (ctx->ct_srvaddr) {
551                 error = nb_resolvehost_in(ctx->ct_srvaddr, &sap, ctx->ct_smbtcpport);
552         } else {
553                 error = nbns_resolvename(ssn->ioc_srvname, ctx->ct_nb, &sap);
554         }
555         if (error) {
556                 smb_error("can't get server address", error);
557                 return error;
558         }
559         nn.nn_scope = ctx->ct_nb->nb_scope;
560         nn.nn_type = NBT_SERVER;
561         strcpy(nn.nn_name, ssn->ioc_srvname);
562         error = nb_sockaddr(sap, &nn, &saserver);
563         nb_snbfree(sap);
564         if (error) {
565                 smb_error("can't allocate server address", error);
566                 return error;
567         }
568         ssn->ioc_server = (struct sockaddr*)saserver;
569         if (ctx->ct_locname[0] == 0) {
570                 error = nb_getlocalname(ctx->ct_locname);
571                 if (error) {
572                         smb_error("can't get local name", error);
573                         return error;
574                 }
575                 nls_str_upper(ctx->ct_locname, ctx->ct_locname);
576         }
577         strcpy(nn.nn_name, ctx->ct_locname);
578         nn.nn_type = NBT_WKSTA;
579         nn.nn_scope = ctx->ct_nb->nb_scope;
580         error = nb_sockaddr(NULL, &nn, &salocal);
581         if (error) {
582                 nb_snbfree((struct sockaddr*)saserver);
583                 smb_error("can't allocate local address", error);
584                 return error;
585         }
586         ssn->ioc_local = (struct sockaddr*)salocal;
587         ssn->ioc_lolen = salocal->snb_len;
588         ssn->ioc_svlen = saserver->snb_len;
589         if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) {
590                 cp = getpass("Password:");
591                 error = smb_ctx_setpassword(ctx, cp);
592                 if (error)
593                         return error;
594         }
595         ctx->ct_flags |= SMBCF_RESOLVED;
596         return 0;
597 }
598
599 static int
600 smb_ctx_gethandle(struct smb_ctx *ctx)
601 {
602         int fd, i;
603         char buf[20];
604
605         fd = open("/dev/"NSMB_NAME, O_RDWR);
606         if (fd >= 0) {
607                 ctx->ct_fd = fd;
608                 return 0;
609         }
610         return ENOENT;
611 }
612
613 int
614 smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags)
615 {
616         struct smbioc_lookup rq;
617         int error;
618
619         if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
620                 smb_error("smb_ctx_lookup() data is not resolved", 0);
621                 return EINVAL;
622         }
623         if (ctx->ct_fd != -1) {
624                 close(ctx->ct_fd);
625                 ctx->ct_fd = -1;
626         }
627         error = smb_ctx_gethandle(ctx);
628         if (error) {
629                 smb_error("can't get handle to requester (no /dev/"NSMB_NAME"* device)", 0);
630                 return EINVAL;
631         }
632         bzero(&rq, sizeof(rq));
633         bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof(struct smbioc_ossn));
634         bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof(struct smbioc_oshare));
635         rq.ioc_flags = flags;
636         rq.ioc_level = level;
637         if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) {
638                 error = errno;
639                 if (flags & SMBLK_CREATE)
640                         smb_error("unable to open connection", error);
641                 return error;
642         }
643         return 0;
644 }
645
646 int
647 smb_ctx_login(struct smb_ctx *ctx)
648 {
649         struct smbioc_ossn *ssn = &ctx->ct_ssn;
650         struct smbioc_oshare *sh = &ctx->ct_sh;
651         int error;
652
653         if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
654                 smb_error("smb_ctx_resolve() should be called first", 0);
655                 return EINVAL;
656         }
657         if (ctx->ct_fd != -1) {
658                 close(ctx->ct_fd);
659                 ctx->ct_fd = -1;
660         }
661         error = smb_ctx_gethandle(ctx);
662         if (error) {
663                 smb_error("can't get handle to requester", 0);
664                 return EINVAL;
665         }
666         if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) {
667                 error = errno;
668                 smb_error("can't open session to server %s", error, ssn->ioc_srvname);
669                 return error;
670         }
671         if (sh->ioc_share[0] == 0)
672                 return 0;
673         if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) {
674                 error = errno;
675                 smb_error("can't connect to share //%s/%s", error,
676                     ssn->ioc_srvname, sh->ioc_share);
677                 return error;
678         }
679         return 0;
680 }
681
682 int
683 smb_ctx_setflags(struct smb_ctx *ctx, int level, int mask, int flags)
684 {
685         struct smbioc_flags fl;
686
687         if (ctx->ct_fd == -1)
688                 return EINVAL;
689         fl.ioc_level = level;
690         fl.ioc_mask = mask;
691         fl.ioc_flags = flags;
692         if (ioctl(ctx->ct_fd, SMBIOC_SETFLAGS, &fl) == -1)
693                 return errno;
694         return 0;
695 }
696
697 /*
698  * level values:
699  * 0 - default
700  * 1 - server
701  * 2 - server:user
702  * 3 - server:user:share
703  */
704 static int
705 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
706 {
707         char *p;
708         int error;
709
710         if (level >= 0) {
711                 rc_getstringptr(smb_rc, sname, "charsets", &p);
712                 if (p) {
713                         error = smb_ctx_setcharset(ctx, p);
714                         if (error)
715                                 smb_error("charset specification in the section '%s' ignored", error, sname);
716                 }
717         }
718         if (level <= 1) {
719                 rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout);
720                 rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount);
721         }
722         if (level == 1) {
723                 rc_getstringptr(smb_rc, sname, "addr", &p);
724                 if (p) {
725                         error = smb_ctx_setsrvaddr(ctx, p);
726                         if (error) {
727                                 smb_error("invalid address specified in the section %s", 0, sname);
728                                 return error;
729                         }
730                 }
731         }
732         if (level >= 2) {
733                 rc_getstringptr(smb_rc, sname, "password", &p);
734                 if (p)
735                         smb_ctx_setpassword(ctx, p);
736         }
737         rc_getstringptr(smb_rc, sname, "workgroup", &p);
738         if (p)
739                 smb_ctx_setworkgroup(ctx, p);
740         return 0;
741 }
742
743 /*
744  * read rc file as follows:
745  * 1. read [default] section
746  * 2. override with [server] section
747  * 3. override with [server:user:share] section
748  * Since abcence of rcfile is not fatal, silently ignore this fact.
749  * smb_rc file should be closed by caller.
750  */
751 int
752 smb_ctx_readrc(struct smb_ctx *ctx)
753 {
754         char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + SMB_MAXSHARENAMELEN + 4];
755 /*      char *p;*/
756
757         if (smb_open_rcfile() != 0)
758                 return 0;
759
760         if (ctx->ct_ssn.ioc_user[0] == 0 || ctx->ct_ssn.ioc_srvname[0] == 0)
761                 return 0;
762
763         smb_ctx_readrcsection(ctx, "default", 0);
764         nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
765         smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1);
766         nb_ctx_readrcsection(smb_rc, ctx->ct_nb, ctx->ct_ssn.ioc_srvname, 1);
767         /*
768          * SERVER:USER parameters
769          */
770         snprintf(sname, sizeof(sname), "%s:%s", ctx->ct_ssn.ioc_srvname,
771             ctx->ct_ssn.ioc_user);
772         smb_ctx_readrcsection(ctx, sname, 2);
773
774         if (ctx->ct_sh.ioc_share[0] != 0) {
775                 /*
776                  * SERVER:USER:SHARE parameters
777                  */
778                 snprintf(sname, sizeof(sname), "%s:%s:%s", ctx->ct_ssn.ioc_srvname,
779                     ctx->ct_ssn.ioc_user, ctx->ct_sh.ioc_share);
780                 smb_ctx_readrcsection(ctx, sname, 3);
781         }
782         return 0;
783 }
784