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