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