xref: /dragonfly/contrib/smbfs/lib/smb/ctx.c (revision 4eab696808e511e585602aa64af9891aa0e4c441)
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
smb_ctx_init(struct smb_ctx * ctx,int argc,char * argv[],int minlevel,int maxlevel,int sharetype)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
smb_ctx_done(struct smb_ctx * ctx)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
getsubstring(const char * p,u_char sep,char * dest,int maxlen,const char ** next)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
smb_ctx_parseunc(struct smb_ctx * ctx,const char * unc,int sharetype,const char ** next)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
smb_ctx_setcharset(struct smb_ctx * ctx,const char * arg)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
smb_ctx_setserver(struct smb_ctx * ctx,const char * name)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
smb_ctx_setuser(struct smb_ctx * ctx,const char * name)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
smb_ctx_setworkgroup(struct smb_ctx * ctx,const char * name)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
smb_ctx_setpassword(struct smb_ctx * ctx,const char * passwd)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
smb_ctx_setshare(struct smb_ctx * ctx,const char * share,int stype)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
smb_ctx_setsrvaddr(struct smb_ctx * ctx,const char * addr)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
smb_parse_owner(char * pair,uid_t * uid,gid_t * gid)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
smb_ctx_opt(struct smb_ctx * ctx,int opt,const char * arg)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
smb_addiconvtbl(const char * to,const char * from,const u_char * tbl)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
smb_ctx_resolve(struct smb_ctx * ctx)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, "ISO8859-1");
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
smb_ctx_gethandle(struct smb_ctx * ctx)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
smb_ctx_lookup(struct smb_ctx * ctx,int level,int flags)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
smb_ctx_login(struct smb_ctx * ctx)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
smb_ctx_setflags(struct smb_ctx * ctx,int level,int mask,int flags)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
smb_ctx_readrcsection(struct smb_ctx * ctx,const char * sname,int level)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
smb_ctx_readrc(struct smb_ctx * ctx)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 
782