PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/lib/libsmbfs/smb/ctx.c

https://bitbucket.org/osunix/osunix-gate
C | 1616 lines | 1121 code | 171 blank | 324 comment | 292 complexity | 3a2115365105468e7459a8049828b641 MD5 | raw file
Possible License(s): BSD-3-Clause-No-Nuclear-License-2014, MPL-2.0-no-copyleft-exception, BSD-3-Clause, BSD-2-Clause, LGPL-3.0, 0BSD, GPL-2.0, LGPL-2.0, AGPL-1.0, AGPL-3.0, GPL-3.0, LGPL-2.1
  1. /*
  2. * Copyright (c) 2000, Boris Popov
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. All advertising materials mentioning features or use of this software
  14. * must display the following acknowledgement:
  15. * This product includes software developed by Boris Popov.
  16. * 4. Neither the name of the author nor the names of any co-contributors
  17. * may be used to endorse or promote products derived from this software
  18. * without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $
  33. */
  34. /*
  35. * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  36. */
  37. #include <sys/param.h>
  38. #include <sys/ioctl.h>
  39. #include <sys/time.h>
  40. #include <sys/mount.h>
  41. #include <sys/types.h>
  42. #include <sys/byteorder.h>
  43. #include <fcntl.h>
  44. #include <ctype.h>
  45. #include <errno.h>
  46. #include <stdio.h>
  47. #include <string.h>
  48. #include <strings.h>
  49. #include <stdlib.h>
  50. #include <pwd.h>
  51. #include <grp.h>
  52. #include <unistd.h>
  53. #include <libintl.h>
  54. #include <assert.h>
  55. #include <nss_dbdefs.h>
  56. #include <cflib.h>
  57. #include <netsmb/smb_lib.h>
  58. #include <netsmb/netbios.h>
  59. #include <netsmb/nb_lib.h>
  60. #include <netsmb/smb_dev.h>
  61. #include "charsets.h"
  62. #include "spnego.h"
  63. #include "derparse.h"
  64. #include "private.h"
  65. #include "ntlm.h"
  66. #ifndef FALSE
  67. #define FALSE 0
  68. #endif
  69. #ifndef TRUE
  70. #define TRUE 1
  71. #endif
  72. struct nv {
  73. char *name;
  74. int value;
  75. };
  76. /* These two may be set by commands. */
  77. int smb_debug, smb_verbose;
  78. /*
  79. * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
  80. */
  81. const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
  82. /*
  83. * Give the RPC library a callback hook that will be
  84. * called whenever we destroy or reinit an smb_ctx_t.
  85. * The name rpc_cleanup_smbctx() is legacy, and was
  86. * originally a direct call into the RPC code.
  87. */
  88. static smb_ctx_close_hook_t close_hook;
  89. static void
  90. rpc_cleanup_smbctx(struct smb_ctx *ctx)
  91. {
  92. if (close_hook)
  93. (*close_hook)(ctx);
  94. }
  95. void
  96. smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)
  97. {
  98. close_hook = hook;
  99. }
  100. void
  101. dump_ctx_flags(int flags)
  102. {
  103. printf(" Flags: ");
  104. if (flags == 0)
  105. printf("0");
  106. if (flags & SMBCF_NOPWD)
  107. printf("NOPWD ");
  108. if (flags & SMBCF_SRIGHTS)
  109. printf("SRIGHTS ");
  110. if (flags & SMBCF_LOCALE)
  111. printf("LOCALE ");
  112. if (flags & SMBCF_CMD_DOM)
  113. printf("CMD_DOM ");
  114. if (flags & SMBCF_CMD_USR)
  115. printf("CMD_USR ");
  116. if (flags & SMBCF_CMD_PW)
  117. printf("CMD_PW ");
  118. if (flags & SMBCF_RESOLVED)
  119. printf("RESOLVED ");
  120. if (flags & SMBCF_KCBAD)
  121. printf("KCBAD ");
  122. if (flags & SMBCF_KCFOUND)
  123. printf("KCFOUND ");
  124. if (flags & SMBCF_BROWSEOK)
  125. printf("BROWSEOK ");
  126. if (flags & SMBCF_AUTHREQ)
  127. printf("AUTHREQ ");
  128. if (flags & SMBCF_KCSAVE)
  129. printf("KCSAVE ");
  130. if (flags & SMBCF_XXX)
  131. printf("XXX ");
  132. if (flags & SMBCF_SSNACTIVE)
  133. printf("SSNACTIVE ");
  134. if (flags & SMBCF_KCDOMAIN)
  135. printf("KCDOMAIN ");
  136. printf("\n");
  137. }
  138. void
  139. dump_iod_ssn(smb_iod_ssn_t *is)
  140. {
  141. static const char zeros[NTLM_HASH_SZ] = {0};
  142. struct smbioc_ossn *ssn = &is->iod_ossn;
  143. printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
  144. dump_sockaddr(&ssn->ssn_srvaddr.sa);
  145. printf(" dom=\"%s\", user=\"%s\"\n",
  146. ssn->ssn_domain, ssn->ssn_user);
  147. printf(" ct_vopt=0x%x, ct_owner=%d\n",
  148. ssn->ssn_vopt, ssn->ssn_owner);
  149. printf(" ct_authflags=0x%x\n", is->iod_authflags);
  150. printf(" ct_nthash:");
  151. if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
  152. smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
  153. else
  154. printf(" {0}\n");
  155. printf(" ct_lmhash:");
  156. if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
  157. smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
  158. else
  159. printf(" {0}\n");
  160. }
  161. void
  162. dump_ctx(char *where, struct smb_ctx *ctx)
  163. {
  164. printf("context %s:\n", where);
  165. dump_ctx_flags(ctx->ct_flags);
  166. if (ctx->ct_locname)
  167. printf(" localname=\"%s\"", ctx->ct_locname);
  168. else
  169. printf(" localname=NULL");
  170. if (ctx->ct_fullserver)
  171. printf(" fullserver=\"%s\"", ctx->ct_fullserver);
  172. else
  173. printf(" fullserver=NULL");
  174. if (ctx->ct_srvaddr_s)
  175. printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
  176. else
  177. printf(" srvaddr_s=NULL\n");
  178. if (ctx->ct_addrinfo)
  179. dump_addrinfo(ctx->ct_addrinfo);
  180. else
  181. printf(" ct_addrinfo = NULL\n");
  182. dump_iod_ssn(&ctx->ct_iod_ssn);
  183. printf(" share_name=\"%s\", share_type=%d\n",
  184. ctx->ct_origshare ? ctx->ct_origshare : "",
  185. ctx->ct_shtype_req);
  186. /* dump_iod_work()? */
  187. }
  188. int
  189. smb_ctx_alloc(struct smb_ctx **ctx_pp)
  190. {
  191. smb_ctx_t *ctx;
  192. int err;
  193. ctx = malloc(sizeof (*ctx));
  194. if (ctx == NULL)
  195. return (ENOMEM);
  196. err = smb_ctx_init(ctx);
  197. if (err != 0) {
  198. free(ctx);
  199. return (err);
  200. }
  201. *ctx_pp = ctx;
  202. return (0);
  203. }
  204. /*
  205. * Initialize an smb_ctx struct (defaults)
  206. */
  207. int
  208. smb_ctx_init(struct smb_ctx *ctx)
  209. {
  210. char pwbuf[NSS_BUFLEN_PASSWD];
  211. struct passwd pw;
  212. int error = 0;
  213. bzero(ctx, sizeof (*ctx));
  214. error = nb_ctx_create(&ctx->ct_nb);
  215. if (error)
  216. return (error);
  217. ctx->ct_dev_fd = -1;
  218. ctx->ct_door_fd = -1;
  219. ctx->ct_tran_fd = -1;
  220. ctx->ct_parsedlevel = SMBL_NONE;
  221. ctx->ct_minlevel = SMBL_NONE;
  222. ctx->ct_maxlevel = SMBL_PATH;
  223. /* Fill in defaults */
  224. ctx->ct_vopt = SMBVOPT_EXT_SEC;
  225. ctx->ct_owner = SMBM_ANY_OWNER;
  226. ctx->ct_authflags = SMB_AT_DEFAULT;
  227. ctx->ct_minauth = SMB_AT_DEFAULT;
  228. error = nb_ctx_setscope(ctx->ct_nb, "");
  229. if (error)
  230. return (error);
  231. /*
  232. * if the user name is not specified some other way,
  233. * use the current user name (built-in default)
  234. */
  235. if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
  236. error = smb_ctx_setuser(ctx, pw.pw_name, 0);
  237. if (error)
  238. return (error);
  239. ctx->ct_home = strdup(pw.pw_name);
  240. if (ctx->ct_home == NULL)
  241. return (ENOMEM);
  242. }
  243. /*
  244. * Set a built-in default domain (workgroup).
  245. * Using the Windows/NT default for now.
  246. */
  247. error = smb_ctx_setdomain(ctx, "WORKGROUP", 0);
  248. if (error)
  249. return (error);
  250. return (error);
  251. }
  252. /*
  253. * "Scan" the command line args to find the server name,
  254. * user name, and share name, as needed. We need these
  255. * before reading the RC files and/or sharectl values.
  256. *
  257. * The sequence for getting all the members filled in
  258. * has some tricky aspects. Here's how it works:
  259. *
  260. * The search order for options is as follows:
  261. * command line options
  262. * values parsed from UNC path (cmd)
  263. * values from RC file (per-user)
  264. * values from SMF (system-wide)
  265. * built-in defaults
  266. *
  267. * Normally, one would simply get all the values starting with
  268. * the bottom of the above list and working to the top, and
  269. * overwriting values as you go. But we need an exception.
  270. *
  271. * In this function, we parse the UNC path and command line options,
  272. * because we need (at least) the server name when we're getting the
  273. * SMF and RC file values. However, values we get from the command
  274. * should not be overwritten by SMF or RC file parsing, so we mark
  275. * values from the command as "from CMD" and the RC file parser
  276. * leaves in place any values so marked. See: SMBCF_CMD_*
  277. *
  278. * The semantics of these flags are: "This value came from the
  279. * current command instance, not from sources that may apply to
  280. * multiple commands." (Different from the old "FROMUSR" flag.)
  281. *
  282. * Note that smb_ctx_opt() is called later to handle the
  283. * remaining options, which should be ignored here.
  284. * The (magic) leading ":" in cf_getopt() makes it
  285. * ignore options not in the options string.
  286. */
  287. int
  288. smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
  289. int minlevel, int maxlevel, int sharetype)
  290. {
  291. int ind, opt, error = 0;
  292. int aflg = 0, uflg = 0;
  293. const char *arg;
  294. /*
  295. * Parse options, if any. Values from here too
  296. * are marked as "from CMD".
  297. */
  298. if (argv == NULL)
  299. return (0);
  300. ctx->ct_minlevel = minlevel;
  301. ctx->ct_maxlevel = maxlevel;
  302. ctx->ct_shtype_req = sharetype;
  303. cf_opt_lock();
  304. /* Careful: no return/goto before cf_opt_unlock! */
  305. while (error == 0) {
  306. opt = cf_getopt(argc, argv, STDPARAM_OPT);
  307. if (opt == -1)
  308. break;
  309. arg = cf_optarg;
  310. /* NB: handle most in smb_ctx_opt */
  311. switch (opt) {
  312. case 'A':
  313. aflg = 1;
  314. error = smb_ctx_setuser(ctx, "", TRUE);
  315. ctx->ct_flags |= SMBCF_NOPWD;
  316. break;
  317. case 'U':
  318. uflg = 1;
  319. error = smb_ctx_setuser(ctx, arg, TRUE);
  320. break;
  321. default:
  322. DPRINT("skip opt=%c", opt);
  323. break;
  324. }
  325. }
  326. ind = cf_optind;
  327. arg = argv[ind];
  328. cf_optind = cf_optreset = 1;
  329. cf_opt_unlock();
  330. if (error)
  331. return (error);
  332. if (aflg && uflg) {
  333. printf(gettext("-A and -U flags are exclusive.\n"));
  334. return (EINVAL);
  335. }
  336. /*
  337. * Parse the UNC path. Values from here are
  338. * marked as "from CMD".
  339. */
  340. for (; ind < argc; ind++) {
  341. arg = argv[ind];
  342. if (strncmp(arg, "//", 2) != 0)
  343. continue;
  344. error = smb_ctx_parseunc(ctx, arg,
  345. minlevel, maxlevel, sharetype, &arg);
  346. if (error)
  347. return (error);
  348. break;
  349. }
  350. return (error);
  351. }
  352. void
  353. smb_ctx_free(smb_ctx_t *ctx)
  354. {
  355. smb_ctx_done(ctx);
  356. free(ctx);
  357. }
  358. void
  359. smb_ctx_done(struct smb_ctx *ctx)
  360. {
  361. rpc_cleanup_smbctx(ctx);
  362. if (ctx->ct_dev_fd != -1) {
  363. close(ctx->ct_dev_fd);
  364. ctx->ct_dev_fd = -1;
  365. }
  366. if (ctx->ct_door_fd != -1) {
  367. close(ctx->ct_door_fd);
  368. ctx->ct_door_fd = -1;
  369. }
  370. if (ctx->ct_tran_fd != -1) {
  371. close(ctx->ct_tran_fd);
  372. ctx->ct_tran_fd = -1;
  373. }
  374. if (ctx->ct_srvaddr_s) {
  375. free(ctx->ct_srvaddr_s);
  376. ctx->ct_srvaddr_s = NULL;
  377. }
  378. if (ctx->ct_nb) {
  379. nb_ctx_done(ctx->ct_nb);
  380. ctx->ct_nb = NULL;
  381. }
  382. if (ctx->ct_locname) {
  383. free(ctx->ct_locname);
  384. ctx->ct_locname = NULL;
  385. }
  386. if (ctx->ct_origshare) {
  387. free(ctx->ct_origshare);
  388. ctx->ct_origshare = NULL;
  389. }
  390. if (ctx->ct_fullserver) {
  391. free(ctx->ct_fullserver);
  392. ctx->ct_fullserver = NULL;
  393. }
  394. if (ctx->ct_addrinfo) {
  395. freeaddrinfo(ctx->ct_addrinfo);
  396. ctx->ct_addrinfo = NULL;
  397. }
  398. if (ctx->ct_home)
  399. free(ctx->ct_home);
  400. if (ctx->ct_srv_OS) {
  401. free(ctx->ct_srv_OS);
  402. ctx->ct_srv_OS = NULL;
  403. }
  404. if (ctx->ct_srv_LM) {
  405. free(ctx->ct_srv_LM);
  406. ctx->ct_srv_LM = NULL;
  407. }
  408. if (ctx->ct_mackey) {
  409. free(ctx->ct_mackey);
  410. ctx->ct_mackey = NULL;
  411. }
  412. }
  413. static int
  414. getsubstring(const char *p, uchar_t sep, char *dest, int maxlen,
  415. const char **next)
  416. {
  417. int len;
  418. maxlen--;
  419. for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
  420. if (*p == 0)
  421. return (EINVAL);
  422. *dest = *p;
  423. }
  424. *dest = 0;
  425. *next = *p ? p + 1 : p;
  426. return (0);
  427. }
  428. /*
  429. * Parse the UNC path. Here we expect something like
  430. * "//[workgroup;][user[:password]@]host[/share[/path]]"
  431. * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
  432. * Values found here are marked as "from CMD".
  433. */
  434. int
  435. smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
  436. int minlevel, int maxlevel, int sharetype,
  437. const char **next)
  438. {
  439. const char *p = unc;
  440. char *p1, *colon;
  441. char tmp[1024];
  442. int error;
  443. /*
  444. * This may be called outside of _scan_argv,
  445. * so make sure these get initialized.
  446. */
  447. ctx->ct_minlevel = minlevel;
  448. ctx->ct_maxlevel = maxlevel;
  449. ctx->ct_shtype_req = sharetype;
  450. ctx->ct_parsedlevel = SMBL_NONE;
  451. if (*p++ != '/' || *p++ != '/') {
  452. smb_error(dgettext(TEXT_DOMAIN,
  453. "UNC should start with '//'"), 0);
  454. error = EINVAL;
  455. goto out;
  456. }
  457. p1 = tmp;
  458. error = getsubstring(p, ';', p1, sizeof (tmp), &p);
  459. if (!error) {
  460. if (*p1 == 0) {
  461. smb_error(dgettext(TEXT_DOMAIN,
  462. "empty workgroup name"), 0);
  463. error = EINVAL;
  464. goto out;
  465. }
  466. error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE);
  467. if (error)
  468. goto out;
  469. }
  470. colon = (char *)p;
  471. error = getsubstring(p, '@', p1, sizeof (tmp), &p);
  472. if (!error) {
  473. if (ctx->ct_maxlevel < SMBL_VC) {
  474. smb_error(dgettext(TEXT_DOMAIN,
  475. "no user name required"), 0);
  476. error = EINVAL;
  477. goto out;
  478. }
  479. p1 = strchr(tmp, ':');
  480. if (p1) {
  481. colon += p1 - tmp;
  482. *p1++ = (char)0;
  483. error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
  484. if (error)
  485. goto out;
  486. if (p - colon > 2)
  487. memset(colon+1, '*', p - colon - 2);
  488. }
  489. p1 = tmp;
  490. if (*p1 == 0) {
  491. smb_error(dgettext(TEXT_DOMAIN,
  492. "empty user name"), 0);
  493. error = EINVAL;
  494. goto out;
  495. }
  496. error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
  497. if (error)
  498. goto out;
  499. ctx->ct_parsedlevel = SMBL_VC;
  500. }
  501. error = getsubstring(p, '/', p1, sizeof (tmp), &p);
  502. if (error) {
  503. error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
  504. if (error) {
  505. smb_error(dgettext(TEXT_DOMAIN,
  506. "no server name found"), 0);
  507. goto out;
  508. }
  509. }
  510. if (*p1 == 0) {
  511. smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
  512. error = EINVAL;
  513. goto out;
  514. }
  515. /*
  516. * Save ct_fullserver without case conversion.
  517. */
  518. if (strchr(tmp, '%'))
  519. (void) unpercent(tmp);
  520. error = smb_ctx_setfullserver(ctx, tmp);
  521. if (error)
  522. goto out;
  523. #ifdef SMB_ST_NONE
  524. if (sharetype == SMB_ST_NONE) {
  525. if (next)
  526. *next = p;
  527. error = 0;
  528. goto out;
  529. }
  530. #endif
  531. if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
  532. smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0);
  533. error = EINVAL;
  534. goto out;
  535. }
  536. error = getsubstring(p, '/', p1, sizeof (tmp), &p);
  537. if (error) {
  538. error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
  539. if (error) {
  540. smb_error(dgettext(TEXT_DOMAIN,
  541. "unexpected end of line"), 0);
  542. goto out;
  543. }
  544. }
  545. if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
  546. !(ctx->ct_flags & SMBCF_BROWSEOK)) {
  547. smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
  548. error = EINVAL;
  549. goto out;
  550. }
  551. if (next)
  552. *next = p;
  553. if (*p1 == 0) {
  554. error = 0;
  555. goto out;
  556. }
  557. error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
  558. out:
  559. if (error == 0 && smb_debug > 0)
  560. dump_ctx("after smb_ctx_parseunc", ctx);
  561. return (error);
  562. }
  563. #ifdef KICONV_SUPPORT
  564. int
  565. smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
  566. {
  567. char *cp, *servercs, *localcs;
  568. int cslen = sizeof (ctx->ct_ssn.ioc_localcs);
  569. int scslen, lcslen, error;
  570. cp = strchr(arg, ':');
  571. lcslen = cp ? (cp - arg) : 0;
  572. if (lcslen == 0 || lcslen >= cslen) {
  573. smb_error(dgettext(TEXT_DOMAIN,
  574. "invalid local charset specification (%s)"), 0, arg);
  575. return (EINVAL);
  576. }
  577. scslen = (size_t)strlen(++cp);
  578. if (scslen == 0 || scslen >= cslen) {
  579. smb_error(dgettext(TEXT_DOMAIN,
  580. "invalid server charset specification (%s)"), 0, arg);
  581. return (EINVAL);
  582. }
  583. localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
  584. localcs[lcslen] = 0;
  585. servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
  586. error = nls_setrecode(localcs, servercs);
  587. if (error == 0)
  588. return (0);
  589. smb_error(dgettext(TEXT_DOMAIN,
  590. "can't initialize iconv support (%s:%s)"),
  591. error, localcs, servercs);
  592. localcs[0] = 0;
  593. servercs[0] = 0;
  594. return (error);
  595. }
  596. #endif /* KICONV_SUPPORT */
  597. int
  598. smb_ctx_setauthflags(struct smb_ctx *ctx, int flags)
  599. {
  600. ctx->ct_authflags = flags;
  601. return (0);
  602. }
  603. int
  604. smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
  605. {
  606. char *p = strdup(name);
  607. if (p == NULL)
  608. return (ENOMEM);
  609. if (ctx->ct_fullserver)
  610. free(ctx->ct_fullserver);
  611. ctx->ct_fullserver = p;
  612. return (0);
  613. }
  614. int
  615. smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
  616. {
  617. strlcpy(ctx->ct_srvname, name,
  618. sizeof (ctx->ct_srvname));
  619. return (0);
  620. }
  621. int
  622. smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
  623. {
  624. if (strlen(name) >= sizeof (ctx->ct_user)) {
  625. smb_error(dgettext(TEXT_DOMAIN,
  626. "user name '%s' too long"), 0, name);
  627. return (ENAMETOOLONG);
  628. }
  629. /*
  630. * Don't overwrite a value from the command line
  631. * with one from anywhere else.
  632. */
  633. if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR))
  634. return (0);
  635. strlcpy(ctx->ct_user, name,
  636. sizeof (ctx->ct_user));
  637. /* Mark this as "from the command line". */
  638. if (from_cmd)
  639. ctx->ct_flags |= SMBCF_CMD_USR;
  640. return (0);
  641. }
  642. /*
  643. * Don't overwrite a domain name from the
  644. * command line with one from anywhere else.
  645. * See smb_ctx_init() for notes about this.
  646. */
  647. int
  648. smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd)
  649. {
  650. if (strlen(name) >= sizeof (ctx->ct_domain)) {
  651. smb_error(dgettext(TEXT_DOMAIN,
  652. "workgroup name '%s' too long"), 0, name);
  653. return (ENAMETOOLONG);
  654. }
  655. /*
  656. * Don't overwrite a value from the command line
  657. * with one from anywhere else.
  658. */
  659. if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
  660. return (0);
  661. strlcpy(ctx->ct_domain, name,
  662. sizeof (ctx->ct_domain));
  663. /* Mark this as "from the command line". */
  664. if (from_cmd)
  665. ctx->ct_flags |= SMBCF_CMD_DOM;
  666. return (0);
  667. }
  668. int
  669. smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
  670. {
  671. int err;
  672. if (passwd == NULL)
  673. return (EINVAL);
  674. if (strlen(passwd) >= sizeof (ctx->ct_password)) {
  675. smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0);
  676. return (ENAMETOOLONG);
  677. }
  678. /*
  679. * If called again after comand line parsing,
  680. * don't overwrite a value from the command line
  681. * with one from any stored config.
  682. */
  683. if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
  684. return (0);
  685. memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
  686. if (strncmp(passwd, "$$1", 3) == 0)
  687. (void) smb_simpledecrypt(ctx->ct_password, passwd);
  688. else
  689. strlcpy(ctx->ct_password, passwd,
  690. sizeof (ctx->ct_password));
  691. /*
  692. * Compute LM hash, NT hash.
  693. */
  694. if (ctx->ct_password[0]) {
  695. err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
  696. if (err != 0)
  697. return (err);
  698. err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
  699. if (err != 0)
  700. return (err);
  701. }
  702. /* Mark this as "from the command line". */
  703. if (from_cmd)
  704. ctx->ct_flags |= SMBCF_CMD_PW;
  705. return (0);
  706. }
  707. /*
  708. * Use this to set NTLM auth. info (hashes)
  709. * when we don't have the password.
  710. */
  711. int
  712. smb_ctx_setpwhash(smb_ctx_t *ctx,
  713. const uchar_t *nthash, const uchar_t *lmhash)
  714. {
  715. /* Need ct_password to be non-null. */
  716. if (ctx->ct_password[0] == '\0')
  717. strlcpy(ctx->ct_password, "$HASH",
  718. sizeof (ctx->ct_password));
  719. /*
  720. * Compute LM hash, NT hash.
  721. */
  722. memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
  723. /* The LM hash is optional */
  724. if (lmhash) {
  725. memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
  726. }
  727. return (0);
  728. }
  729. int
  730. smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
  731. {
  732. if (strlen(share) >= SMBIOC_MAX_NAME) {
  733. smb_error(dgettext(TEXT_DOMAIN,
  734. "share name '%s' too long"), 0, share);
  735. return (ENAMETOOLONG);
  736. }
  737. if (ctx->ct_origshare)
  738. free(ctx->ct_origshare);
  739. if ((ctx->ct_origshare = strdup(share)) == NULL)
  740. return (ENOMEM);
  741. ctx->ct_shtype_req = stype;
  742. return (0);
  743. }
  744. int
  745. smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
  746. {
  747. if (addr == NULL || addr[0] == 0)
  748. return (EINVAL);
  749. if (ctx->ct_srvaddr_s)
  750. free(ctx->ct_srvaddr_s);
  751. if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL)
  752. return (ENOMEM);
  753. return (0);
  754. }
  755. /*
  756. * API for library caller to set signing enabled, required
  757. * Note: if not enable, ignore require
  758. */
  759. int
  760. smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
  761. {
  762. ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
  763. if (enable) {
  764. ctx->ct_vopt |= SMBVOPT_SIGNING_ENABLED;
  765. if (require)
  766. ctx->ct_vopt |= SMBVOPT_SIGNING_REQUIRED;
  767. }
  768. return (0);
  769. }
  770. static int
  771. smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
  772. {
  773. struct group gr;
  774. struct passwd pw;
  775. char buf[NSS_BUFLEN_PASSWD];
  776. char *cp;
  777. cp = strchr(pair, ':');
  778. if (cp) {
  779. *cp++ = '\0';
  780. if (*cp && gid) {
  781. if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
  782. *gid = gr.gr_gid;
  783. } else
  784. smb_error(dgettext(TEXT_DOMAIN,
  785. "Invalid group name %s, ignored"), 0, cp);
  786. }
  787. }
  788. if (*pair) {
  789. if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
  790. *uid = pw.pw_uid;
  791. } else
  792. smb_error(dgettext(TEXT_DOMAIN,
  793. "Invalid user name %s, ignored"), 0, pair);
  794. }
  795. return (0);
  796. }
  797. /*
  798. * Suport a securty options arg, i.e. -S noext,lm,ntlm
  799. * for testing various type of authenticators.
  800. */
  801. static struct nv
  802. sectype_table[] = {
  803. /* noext - handled below */
  804. { "anon", SMB_AT_ANON },
  805. { "lm", SMB_AT_LM1 },
  806. { "ntlm", SMB_AT_NTLM1 },
  807. { "ntlm2", SMB_AT_NTLM2 },
  808. { "krb5", SMB_AT_KRB5 },
  809. { NULL, 0 },
  810. };
  811. int
  812. smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
  813. {
  814. const char *sep = ":;,";
  815. const char *p = arg;
  816. struct nv *nv;
  817. int nlen, tlen;
  818. int authflags = 0;
  819. for (;;) {
  820. /* skip separators */
  821. tlen = strspn(p, sep);
  822. p += tlen;
  823. nlen = strcspn(p, sep);
  824. if (nlen == 0)
  825. break;
  826. if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) {
  827. /* Don't offer extended security. */
  828. ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
  829. p += nlen;
  830. continue;
  831. }
  832. /* This is rarely called, so not optimized. */
  833. for (nv = sectype_table; nv->name; nv++) {
  834. tlen = strlen(nv->name);
  835. if (tlen == nlen && 0 == strncmp(p, nv->name, tlen))
  836. break;
  837. }
  838. if (nv->name == NULL) {
  839. smb_error(dgettext(TEXT_DOMAIN,
  840. "%s: invalid security options"), 0, p);
  841. return (EINVAL);
  842. }
  843. authflags |= nv->value;
  844. p += nlen;
  845. }
  846. if (authflags)
  847. ctx->ct_authflags = authflags;
  848. return (0);
  849. }
  850. /*
  851. * Commands use this with getopt. See:
  852. * STDPARAM_OPT, STDPARAM_ARGS
  853. * Called after smb_ctx_readrc().
  854. */
  855. int
  856. smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
  857. {
  858. int error = 0;
  859. char *p, *cp;
  860. char tmp[1024];
  861. switch (opt) {
  862. case 'A':
  863. case 'U':
  864. /* Handled in smb_ctx_init() */
  865. break;
  866. case 'I':
  867. error = smb_ctx_setsrvaddr(ctx, arg);
  868. break;
  869. case 'M':
  870. /* share connect rights - ignored */
  871. ctx->ct_flags |= SMBCF_SRIGHTS;
  872. break;
  873. case 'N':
  874. ctx->ct_flags |= SMBCF_NOPWD;
  875. break;
  876. case 'O':
  877. p = strdup(arg);
  878. cp = strchr(p, '/');
  879. if (cp)
  880. *cp = '\0';
  881. error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
  882. free(p);
  883. break;
  884. case 'P':
  885. /* ctx->ct_vopt |= SMBCOPT_PERMANENT; */
  886. break;
  887. case 'R':
  888. /* retry count - ignored */
  889. break;
  890. case 'S':
  891. /* Security options (undocumented, just for tests) */
  892. error = smb_parse_secopts(ctx, arg);
  893. break;
  894. case 'T':
  895. /* timeout - ignored */
  896. break;
  897. case 'D': /* domain */
  898. case 'W': /* workgroup (legacy alias) */
  899. error = smb_ctx_setdomain(ctx, tmp, TRUE);
  900. break;
  901. }
  902. return (error);
  903. }
  904. /*
  905. * Original code injected iconv tables into the kernel.
  906. * Not sure if we'll need this or not... REVISIT
  907. */
  908. #ifdef KICONV_SUPPORT
  909. static int
  910. smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
  911. {
  912. int error = 0;
  913. error = kiconv_add_xlat_table(to, from, tbl);
  914. if (error && error != EEXIST) {
  915. smb_error(dgettext(TEXT_DOMAIN,
  916. "can not setup kernel iconv table (%s:%s)"),
  917. error, from, to);
  918. return (error);
  919. }
  920. return (error);
  921. }
  922. #endif /* KICONV_SUPPORT */
  923. /*
  924. * Verify context info. before connect operation(s),
  925. * lookup specified server and try to fill all forgotten fields.
  926. * Legacy name used by commands.
  927. */
  928. int
  929. smb_ctx_resolve(struct smb_ctx *ctx)
  930. {
  931. struct smbioc_ossn *ssn = &ctx->ct_ssn;
  932. int error = 0;
  933. #ifdef KICONV_SUPPORT
  934. uchar_t cstbl[256];
  935. uint_t i;
  936. #endif
  937. if (smb_debug)
  938. dump_ctx("before smb_ctx_resolve", ctx);
  939. ctx->ct_flags &= ~SMBCF_RESOLVED;
  940. if (ctx->ct_fullserver == NULL) {
  941. smb_error(dgettext(TEXT_DOMAIN,
  942. "no server name specified"), 0);
  943. return (EINVAL);
  944. }
  945. if (ctx->ct_minlevel >= SMBL_SHARE &&
  946. ctx->ct_origshare == NULL) {
  947. smb_error(dgettext(TEXT_DOMAIN,
  948. "no share name specified for %s@%s"),
  949. 0, ssn->ssn_user, ctx->ct_fullserver);
  950. return (EINVAL);
  951. }
  952. error = nb_ctx_resolve(ctx->ct_nb);
  953. if (error)
  954. return (error);
  955. #ifdef KICONV_SUPPORT
  956. if (ssn->ioc_localcs[0] == 0)
  957. strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */
  958. error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
  959. if (error)
  960. return (error);
  961. error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
  962. if (error)
  963. return (error);
  964. if (ssn->ioc_servercs[0] != 0) {
  965. for (i = 0; i < sizeof (cstbl); i++)
  966. cstbl[i] = i;
  967. nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
  968. error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
  969. cstbl);
  970. if (error)
  971. return (error);
  972. for (i = 0; i < sizeof (cstbl); i++)
  973. cstbl[i] = i;
  974. nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
  975. error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
  976. cstbl);
  977. if (error)
  978. return (error);
  979. }
  980. #endif /* KICONV_SUPPORT */
  981. /*
  982. * Lookup the IP address and fill in ct_addrinfo.
  983. *
  984. * Note: smb_ctx_getaddr() returns a EAI_xxx
  985. * error value like getaddrinfo(3), but this
  986. * function needs to return an errno value.
  987. */
  988. error = smb_ctx_getaddr(ctx);
  989. if (error) {
  990. const char *ais = gai_strerror(error);
  991. smb_error(dgettext(TEXT_DOMAIN,
  992. "can't resolve name\"%s\", %s"),
  993. 0, ctx->ct_fullserver, ais);
  994. return (ENODATA);
  995. }
  996. assert(ctx->ct_addrinfo != NULL);
  997. /*
  998. * If we have a user name but no password,
  999. * check for a keychain entry.
  1000. * XXX: Only for auth NTLM?
  1001. */
  1002. if (ctx->ct_user[0] == '\0') {
  1003. /*
  1004. * No user name (anonymous session).
  1005. * The minauth checks do not apply.
  1006. */
  1007. ctx->ct_authflags = SMB_AT_ANON;
  1008. } else {
  1009. /*
  1010. * Have a user name.
  1011. * If we don't have a p/w yet,
  1012. * try the keychain.
  1013. */
  1014. if (ctx->ct_password[0] == '\0')
  1015. (void) smb_get_keychain(ctx);
  1016. /*
  1017. * Mask out disallowed auth types.
  1018. */
  1019. ctx->ct_authflags &= ctx->ct_minauth;
  1020. }
  1021. if (ctx->ct_authflags == 0) {
  1022. smb_error(dgettext(TEXT_DOMAIN,
  1023. "no valid auth. types"), 0);
  1024. return (ENOTSUP);
  1025. }
  1026. ctx->ct_flags |= SMBCF_RESOLVED;
  1027. if (smb_debug)
  1028. dump_ctx("after smb_ctx_resolve", ctx);
  1029. return (0);
  1030. }
  1031. int
  1032. smb_open_driver()
  1033. {
  1034. int err, fd;
  1035. uint32_t version;
  1036. fd = open("/dev/"NSMB_NAME, O_RDWR);
  1037. if (fd < 0) {
  1038. err = errno;
  1039. smb_error(dgettext(TEXT_DOMAIN,
  1040. "failed to open driver"), err);
  1041. return (-1);
  1042. }
  1043. /*
  1044. * Check the driver version (paranoia)
  1045. * Do this BEFORE any other ioctl calls.
  1046. */
  1047. if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
  1048. version = 0;
  1049. if (version != NSMB_VERSION) {
  1050. smb_error(dgettext(TEXT_DOMAIN,
  1051. "incorrect driver version"), 0);
  1052. close(fd);
  1053. return (-1);
  1054. }
  1055. /* This handle controls per-process resources. */
  1056. (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
  1057. return (fd);
  1058. }
  1059. int
  1060. smb_ctx_gethandle(struct smb_ctx *ctx)
  1061. {
  1062. int fd;
  1063. if (ctx->ct_dev_fd != -1) {
  1064. rpc_cleanup_smbctx(ctx);
  1065. close(ctx->ct_dev_fd);
  1066. ctx->ct_dev_fd = -1;
  1067. ctx->ct_flags &= ~SMBCF_SSNACTIVE;
  1068. }
  1069. fd = smb_open_driver();
  1070. if (fd < 0)
  1071. return (ENODEV);
  1072. ctx->ct_dev_fd = fd;
  1073. return (0);
  1074. }
  1075. /*
  1076. * Find or create a connection + logon session
  1077. */
  1078. int
  1079. smb_ctx_get_ssn(struct smb_ctx *ctx)
  1080. {
  1081. int err = 0;
  1082. if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
  1083. return (EINVAL);
  1084. if (ctx->ct_dev_fd < 0) {
  1085. if ((err = smb_ctx_gethandle(ctx)))
  1086. return (err);
  1087. }
  1088. /*
  1089. * Check whether the driver already has a VC
  1090. * we can use. If so, we're done!
  1091. */
  1092. err = smb_ctx_findvc(ctx);
  1093. if (err == 0) {
  1094. DPRINT("found an existing VC");
  1095. } else {
  1096. /*
  1097. * This calls the IOD to create a new session.
  1098. */
  1099. DPRINT("setup a new VC");
  1100. err = smb_ctx_newvc(ctx);
  1101. if (err != 0)
  1102. return (err);
  1103. /*
  1104. * Call findvc again. The new VC sould be
  1105. * found in the driver this time.
  1106. */
  1107. err = smb_ctx_findvc(ctx);
  1108. }
  1109. return (err);
  1110. }
  1111. /*
  1112. * Get the string representation of a share "use" type,
  1113. * as needed for the "service" in tree connect.
  1114. */
  1115. static const char *
  1116. smb_use_type_str(smb_use_shtype_t stype)
  1117. {
  1118. const char *pp;
  1119. switch (stype) {
  1120. default:
  1121. case USE_WILDCARD:
  1122. pp = "?????";
  1123. break;
  1124. case USE_DISKDEV:
  1125. pp = "A:";
  1126. break;
  1127. case USE_SPOOLDEV:
  1128. pp = "LPT1:";
  1129. break;
  1130. case USE_CHARDEV:
  1131. pp = "COMM";
  1132. break;
  1133. case USE_IPC:
  1134. pp = "IPC";
  1135. break;
  1136. }
  1137. return (pp);
  1138. }
  1139. /*
  1140. * Find or create a tree connection
  1141. */
  1142. int
  1143. smb_ctx_get_tree(struct smb_ctx *ctx)
  1144. {
  1145. smbioc_tcon_t *tcon = NULL;
  1146. const char *stype;
  1147. int cmd, err = 0;
  1148. if (ctx->ct_dev_fd < 0 ||
  1149. ctx->ct_origshare == NULL) {
  1150. return (EINVAL);
  1151. }
  1152. cmd = SMBIOC_TREE_CONNECT;
  1153. tcon = malloc(sizeof (*tcon));
  1154. if (tcon == NULL)
  1155. return (ENOMEM);
  1156. bzero(tcon, sizeof (*tcon));
  1157. tcon->tc_flags = SMBLK_CREATE;
  1158. tcon->tc_opt = 0;
  1159. /* The share name */
  1160. strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
  1161. sizeof (tcon->tc_sh.sh_name));
  1162. /*
  1163. * Share password (unused - no share-level security)
  1164. * MS-SMB 2.2.6 says this should be null terminated,
  1165. * and the length includes the null. Did bzero above,
  1166. * so just set length for the null.
  1167. */
  1168. tcon->tc_sh.sh_pwlen = 1;
  1169. /* The share "use" type. */
  1170. stype = smb_use_type_str(ctx->ct_shtype_req);
  1171. strlcpy(tcon->tc_sh.sh_type_req, stype,
  1172. sizeof (tcon->tc_sh.sh_type_req));
  1173. /*
  1174. * Todo: share passwords for share-level security.
  1175. *
  1176. * The driver does the actual TCON call.
  1177. */
  1178. if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
  1179. err = errno;
  1180. goto out;
  1181. }
  1182. /*
  1183. * Check the returned share type
  1184. */
  1185. DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret);
  1186. if (ctx->ct_shtype_req != USE_WILDCARD &&
  1187. 0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) {
  1188. smb_error(dgettext(TEXT_DOMAIN,
  1189. "%s: incompatible share type"),
  1190. 0, ctx->ct_origshare);
  1191. err = EINVAL;
  1192. }
  1193. out:
  1194. if (tcon != NULL)
  1195. free(tcon);
  1196. return (err);
  1197. }
  1198. /*
  1199. * Return the hflags2 word for an smb_ctx.
  1200. */
  1201. int
  1202. smb_ctx_flags2(struct smb_ctx *ctx)
  1203. {
  1204. uint16_t flags2;
  1205. if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
  1206. smb_error(dgettext(TEXT_DOMAIN,
  1207. "can't get flags2 for a session"), errno);
  1208. return (-1);
  1209. }
  1210. return (flags2);
  1211. }
  1212. /*
  1213. * Get the transport level session key.
  1214. * Must already have an active SMB session.
  1215. */
  1216. int
  1217. smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len)
  1218. {
  1219. if (len < SMBIOC_HASH_SZ)
  1220. return (EINVAL);
  1221. if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1)
  1222. return (errno);
  1223. return (0);
  1224. }
  1225. /*
  1226. * RC file parsing stuff
  1227. */
  1228. static struct nv
  1229. minauth_table[] = {
  1230. /* Allowed auth. types */
  1231. { "kerberos", SMB_AT_KRB5 },
  1232. { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 },
  1233. { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
  1234. { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
  1235. { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
  1236. SMB_AT_ANON },
  1237. { NULL }
  1238. };
  1239. /*
  1240. * level values:
  1241. * 0 - default
  1242. * 1 - server
  1243. * 2 - server:user
  1244. * 3 - server:user:share
  1245. */
  1246. static int
  1247. smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
  1248. {
  1249. char *p;
  1250. int error;
  1251. #ifdef KICONV_SUPPORT
  1252. if (level > 0) {
  1253. rc_getstringptr(smb_rc, sname, "charsets", &p);
  1254. if (p) {
  1255. error = smb_ctx_setcharset(ctx, p);
  1256. if (error)
  1257. smb_error(dgettext(TEXT_DOMAIN,
  1258. "charset specification in the section '%s' ignored"),
  1259. error, sname);
  1260. }
  1261. }
  1262. #endif
  1263. if (level <= 1) {
  1264. /* Section is: [default] or [server] */
  1265. rc_getstringptr(smb_rc, sname, "minauth", &p);
  1266. if (p) {
  1267. /*
  1268. * "minauth" was set in this section; override
  1269. * the current minimum authentication setting.
  1270. */
  1271. struct nv *nvp;
  1272. for (nvp = minauth_table; nvp->name; nvp++)
  1273. if (strcmp(p, nvp->name) == 0)
  1274. break;
  1275. if (nvp->name)
  1276. ctx->ct_minauth = nvp->value;
  1277. else {
  1278. /*
  1279. * Unknown minimum authentication level.
  1280. */
  1281. smb_error(dgettext(TEXT_DOMAIN,
  1282. "invalid minimum authentication level \"%s\" specified in the section %s"),
  1283. 0, p, sname);
  1284. return (EINVAL);
  1285. }
  1286. }
  1287. rc_getstringptr(smb_rc, sname, "signing", &p);
  1288. if (p) {
  1289. /*
  1290. * "signing" was set in this section; override
  1291. * the current signing settings. Note:
  1292. * setsigning flags are: enable, require
  1293. */
  1294. if (strcmp(p, "disabled") == 0) {
  1295. (void) smb_ctx_setsigning(ctx, FALSE, FALSE);
  1296. } else if (strcmp(p, "enabled") == 0) {
  1297. (void) smb_ctx_setsigning(ctx, TRUE, FALSE);
  1298. } else if (strcmp(p, "required") == 0) {
  1299. (void) smb_ctx_setsigning(ctx, TRUE, TRUE);
  1300. } else {
  1301. /*
  1302. * Unknown "signing" value.
  1303. */
  1304. smb_error(dgettext(TEXT_DOMAIN,
  1305. "invalid signing policy \"%s\" specified in the section %s"),
  1306. 0, p, sname);
  1307. return (EINVAL);
  1308. }
  1309. }
  1310. /*
  1311. * Domain name. Allow both keywords:
  1312. * "workgroup", "domain"
  1313. *
  1314. * Note: these are NOT marked "from CMD".
  1315. * See long comment at smb_ctx_init()
  1316. */
  1317. rc_getstringptr(smb_rc, sname, "workgroup", &p);
  1318. if (p) {
  1319. error = smb_ctx_setdomain(ctx, p, 0);
  1320. if (error)
  1321. smb_error(dgettext(TEXT_DOMAIN,
  1322. "workgroup specification in the "
  1323. "section '%s' ignored"), error, sname);
  1324. }
  1325. rc_getstringptr(smb_rc, sname, "domain", &p);
  1326. if (p) {
  1327. error = smb_ctx_setdomain(ctx, p, 0);
  1328. if (error)
  1329. smb_error(dgettext(TEXT_DOMAIN,
  1330. "domain specification in the "
  1331. "section '%s' ignored"), error, sname);
  1332. }
  1333. rc_getstringptr(smb_rc, sname, "user", &p);
  1334. if (p) {
  1335. error = smb_ctx_setuser(ctx, p, 0);
  1336. if (error)
  1337. smb_error(dgettext(TEXT_DOMAIN,
  1338. "user specification in the "
  1339. "section '%s' ignored"), error, sname);
  1340. }
  1341. }
  1342. if (level == 1) {
  1343. /* Section is: [server] */
  1344. rc_getstringptr(smb_rc, sname, "addr", &p);
  1345. if (p) {
  1346. error = smb_ctx_setsrvaddr(ctx, p);
  1347. if (error) {
  1348. smb_error(dgettext(TEXT_DOMAIN,
  1349. "invalid address specified in section %s"),
  1350. 0, sname);
  1351. return (error);
  1352. }
  1353. }
  1354. }
  1355. rc_getstringptr(smb_rc, sname, "password", &p);
  1356. if (p) {
  1357. error = smb_ctx_setpassword(ctx, p, 0);
  1358. if (error)
  1359. smb_error(dgettext(TEXT_DOMAIN,
  1360. "password specification in the section '%s' ignored"),
  1361. error, sname);
  1362. }
  1363. return (0);
  1364. }
  1365. /*
  1366. * read rc file as follows:
  1367. * 0: read [default] section
  1368. * 1: override with [server] section
  1369. * 2: override with [server:user] section
  1370. * 3: override with [server:user:share] section
  1371. * Since absence of rcfile is not fatal, silently ignore this fact.
  1372. * smb_rc file should be closed by caller.
  1373. */
  1374. int
  1375. smb_ctx_readrc(struct smb_ctx *ctx)
  1376. {
  1377. char *home;
  1378. char *sname = NULL;
  1379. int sname_max;
  1380. int err = 0;
  1381. if ((home = getenv("HOME")) == NULL)
  1382. home = ctx->ct_home;
  1383. if ((err = smb_open_rcfile(home)) != 0) {
  1384. DPRINT("smb_open_rcfile, err=%d", err);
  1385. /* ignore any error here */
  1386. return (0);
  1387. }
  1388. sname_max = 3 * SMBIOC_MAX_NAME + 4;
  1389. sname = malloc(sname_max);
  1390. if (sname == NULL) {
  1391. err = ENOMEM;
  1392. goto done;
  1393. }
  1394. /*
  1395. * default parameters (level=0)
  1396. */
  1397. smb_ctx_readrcsection(ctx, "default", 0);
  1398. nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
  1399. /*
  1400. * If we don't have a server name, we can't read any of the
  1401. * [server...] sections.
  1402. */
  1403. if (ctx->ct_fullserver == NULL)
  1404. goto done;
  1405. /*
  1406. * SERVER parameters.
  1407. */
  1408. smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
  1409. /*
  1410. * If we don't have a user name, we can't read any of the
  1411. * [server:user...] sections.
  1412. */
  1413. if (ctx->ct_user[0] == 0)
  1414. goto done;
  1415. /*
  1416. * SERVER:USER parameters
  1417. */
  1418. snprintf(sname, sname_max, "%s:%s",
  1419. ctx->ct_fullserver,
  1420. ctx->ct_user);
  1421. smb_ctx_readrcsection(ctx, sname, 2);
  1422. /*
  1423. * If we don't have a share name, we can't read any of the
  1424. * [server:user:share] sections.
  1425. */
  1426. if (ctx->ct_origshare == NULL)
  1427. goto done;
  1428. /*
  1429. * SERVER:USER:SHARE parameters
  1430. */
  1431. snprintf(sname, sname_max, "%s:%s:%s",
  1432. ctx->ct_fullserver,
  1433. ctx->ct_user,
  1434. ctx->ct_origshare);
  1435. smb_ctx_readrcsection(ctx, sname, 3);
  1436. done:
  1437. if (sname)
  1438. free(sname);
  1439. smb_close_rcfile();
  1440. if (smb_debug)
  1441. dump_ctx("after smb_ctx_readrc", ctx);
  1442. if (err)
  1443. DPRINT("err=%d\n", err);
  1444. return (err);
  1445. }