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 /*
36 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
38 */
39
40 #include <sys/param.h>
41 #include <sys/ioctl.h>
42 #include <sys/time.h>
43 #include <sys/mount.h>
44 #include <sys/types.h>
45 #include <sys/byteorder.h>
46
47 #include <fcntl.h>
48 #include <ctype.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <strings.h>
53 #include <stdlib.h>
54 #include <pwd.h>
55 #include <grp.h>
56 #include <unistd.h>
57 #include <libintl.h>
131 if (flags & SMBCF_LOCALE)
132 printf("LOCALE ");
133 if (flags & SMBCF_CMD_DOM)
134 printf("CMD_DOM ");
135 if (flags & SMBCF_CMD_USR)
136 printf("CMD_USR ");
137 if (flags & SMBCF_CMD_PW)
138 printf("CMD_PW ");
139 if (flags & SMBCF_RESOLVED)
140 printf("RESOLVED ");
141 if (flags & SMBCF_KCBAD)
142 printf("KCBAD ");
143 if (flags & SMBCF_KCFOUND)
144 printf("KCFOUND ");
145 if (flags & SMBCF_BROWSEOK)
146 printf("BROWSEOK ");
147 if (flags & SMBCF_AUTHREQ)
148 printf("AUTHREQ ");
149 if (flags & SMBCF_KCSAVE)
150 printf("KCSAVE ");
151 if (flags & SMBCF_XXX)
152 printf("XXX ");
153 if (flags & SMBCF_SSNACTIVE)
154 printf("SSNACTIVE ");
155 if (flags & SMBCF_KCDOMAIN)
156 printf("KCDOMAIN ");
157 printf("\n");
158 }
159
160 void
161 dump_iod_ssn(smb_iod_ssn_t *is)
162 {
163 static const char zeros[NTLM_HASH_SZ] = {0};
164 struct smbioc_ossn *ssn = &is->iod_ossn;
165
166 printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
167 dump_sockaddr(&ssn->ssn_srvaddr.sa);
168 printf(" dom=\"%s\", user=\"%s\"\n",
169 ssn->ssn_domain, ssn->ssn_user);
170 printf(" ct_vopt=0x%x, ct_owner=%d\n",
171 ssn->ssn_vopt, ssn->ssn_owner);
172 printf(" ct_authflags=0x%x\n", is->iod_authflags);
173
174 printf(" ct_nthash:");
175 if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
176 smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
177 else
178 printf(" {0}\n");
179
180 printf(" ct_lmhash:");
181 if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
182 smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
183 else
184 printf(" {0}\n");
185 }
186
187 void
188 dump_ctx(char *where, struct smb_ctx *ctx)
189 {
190 printf("context %s:\n", where);
191 dump_ctx_flags(ctx->ct_flags);
237 *ctx_pp = ctx;
238 return (0);
239 }
240
241 /*
242 * Initialize an smb_ctx struct (defaults)
243 */
244 int
245 smb_ctx_init(struct smb_ctx *ctx)
246 {
247 int error;
248
249 bzero(ctx, sizeof (*ctx));
250
251 error = nb_ctx_create(&ctx->ct_nb);
252 if (error)
253 return (error);
254
255 ctx->ct_dev_fd = -1;
256 ctx->ct_door_fd = -1;
257 ctx->ct_tran_fd = -1;
258 ctx->ct_parsedlevel = SMBL_NONE;
259 ctx->ct_minlevel = SMBL_NONE;
260 ctx->ct_maxlevel = SMBL_PATH;
261
262 /* Fill in defaults */
263 ctx->ct_vopt = SMBVOPT_EXT_SEC;
264 ctx->ct_owner = SMBM_ANY_OWNER;
265 ctx->ct_authflags = SMB_AT_DEFAULT;
266 ctx->ct_minauth = SMB_AT_MINAUTH;
267
268 /*
269 * Default domain, user, ...
270 */
271 strlcpy(ctx->ct_domain, default_domain,
272 sizeof (ctx->ct_domain));
273 strlcpy(ctx->ct_user, default_user,
274 sizeof (ctx->ct_user));
275
276 return (0);
277 }
278
279 /*
280 * "Scan" the command line args to find the server name,
281 * user name, and share name, as needed. We need these
282 * before reading the RC files and/or sharectl values.
283 *
284 * The sequence for getting all the members filled in
285 * has some tricky aspects. Here's how it works:
286 *
316 int minlevel, int maxlevel, int sharetype)
317 {
318 int ind, opt, error = 0;
319 int aflg = 0, uflg = 0;
320 const char *arg;
321
322 /*
323 * Parse options, if any. Values from here too
324 * are marked as "from CMD".
325 */
326 if (argv == NULL)
327 return (0);
328
329 ctx->ct_minlevel = minlevel;
330 ctx->ct_maxlevel = maxlevel;
331 ctx->ct_shtype_req = sharetype;
332
333 cf_opt_lock();
334 /* Careful: no return/goto before cf_opt_unlock! */
335 while (error == 0) {
336 opt = cf_getopt(argc, argv, STDPARAM_OPT);
337 if (opt == -1)
338 break;
339 arg = cf_optarg;
340 /* NB: handle most in smb_ctx_opt */
341 switch (opt) {
342 case 'A':
343 aflg = 1;
344 error = smb_ctx_setuser(ctx, "", TRUE);
345 ctx->ct_flags |= SMBCF_NOPWD;
346 break;
347 case 'U':
348 uflg = 1;
349 error = smb_ctx_setuser(ctx, arg, TRUE);
350 break;
351 default:
352 DPRINT("skip opt=%c", opt);
353 break;
354 }
355 }
356 ind = cf_optind;
381 break;
382 }
383
384 return (error);
385 }
386
387 void
388 smb_ctx_free(smb_ctx_t *ctx)
389 {
390 smb_ctx_done(ctx);
391 free(ctx);
392 }
393
394 void
395 smb_ctx_done(struct smb_ctx *ctx)
396 {
397
398 rpc_cleanup_smbctx(ctx);
399
400 if (ctx->ct_dev_fd != -1) {
401 close(ctx->ct_dev_fd);
402 ctx->ct_dev_fd = -1;
403 }
404 if (ctx->ct_door_fd != -1) {
405 close(ctx->ct_door_fd);
406 ctx->ct_door_fd = -1;
407 }
408 if (ctx->ct_tran_fd != -1) {
409 close(ctx->ct_tran_fd);
410 ctx->ct_tran_fd = -1;
411 }
412 if (ctx->ct_srvaddr_s) {
413 free(ctx->ct_srvaddr_s);
414 ctx->ct_srvaddr_s = NULL;
415 }
416 if (ctx->ct_nb) {
417 nb_ctx_done(ctx->ct_nb);
418 ctx->ct_nb = NULL;
419 }
420 if (ctx->ct_locname) {
421 free(ctx->ct_locname);
422 ctx->ct_locname = NULL;
423 }
424 if (ctx->ct_origshare) {
425 free(ctx->ct_origshare);
426 ctx->ct_origshare = NULL;
427 }
428 if (ctx->ct_fullserver) {
429 free(ctx->ct_fullserver);
430 ctx->ct_fullserver = NULL;
431 }
432 if (ctx->ct_addrinfo) {
433 freeaddrinfo(ctx->ct_addrinfo);
434 ctx->ct_addrinfo = NULL;
435 }
436 if (ctx->ct_home) {
437 free(ctx->ct_home);
438 ctx->ct_home = NULL;
439 }
440 if (ctx->ct_rpath) {
441 free(ctx->ct_rpath);
442 ctx->ct_rpath = NULL;
443 }
444 if (ctx->ct_srv_OS) {
445 free(ctx->ct_srv_OS);
446 ctx->ct_srv_OS = NULL;
447 }
448 if (ctx->ct_srv_LM) {
449 free(ctx->ct_srv_LM);
450 ctx->ct_srv_LM = NULL;
451 }
452 if (ctx->ct_mackey) {
453 free(ctx->ct_mackey);
454 ctx->ct_mackey = NULL;
455 }
456 }
457
458 /*
459 * Parse the UNC path. Here we expect something like
460 * "//[[domain;]user[:password]@]host[/share[/path]]"
461 * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
462 * Values found here are marked as "from CMD".
463 */
464 int
465 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
466 int minlevel, int maxlevel, int sharetype,
467 const char **next)
468 {
469 char tmp[1024];
470 char *host, *share, *path;
471 char *dom, *usr, *pw, *p;
472 int error;
473
474 /*
475 * This may be called outside of _scan_argv,
851 return (ENOMEM);
852 return (0);
853 }
854
855 /*
856 * API for library caller to set signing enabled, required
857 * Note: if not enable, ignore require
858 */
859 int
860 smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
861 {
862 ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
863 if (enable) {
864 ctx->ct_vopt |= SMBVOPT_SIGNING_ENABLED;
865 if (require)
866 ctx->ct_vopt |= SMBVOPT_SIGNING_REQUIRED;
867 }
868 return (0);
869 }
870
871 static int
872 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
873 {
874 struct group gr;
875 struct passwd pw;
876 char buf[NSS_BUFLEN_PASSWD];
877 char *cp;
878
879 cp = strchr(pair, ':');
880 if (cp) {
881 *cp++ = '\0';
882 if (*cp && gid) {
883 if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
884 *gid = gr.gr_gid;
885 } else
886 smb_error(dgettext(TEXT_DOMAIN,
887 "Invalid group name %s, ignored"), 0, cp);
888 }
889 }
890 if (*pair) {
891 if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
892 *uid = pw.pw_uid;
893 } else
894 smb_error(dgettext(TEXT_DOMAIN,
895 "Invalid user name %s, ignored"), 0, pair);
896 }
897
898 return (0);
899 }
900
901 /*
902 * Suport a securty options arg, i.e. -S noext,lm,ntlm
903 * for testing various type of authenticators.
904 */
905 static struct nv
906 sectype_table[] = {
907 /* noext - handled below */
908 { "anon", SMB_AT_ANON },
909 { "lm", SMB_AT_LM1 },
910 { "ntlm", SMB_AT_NTLM1 },
911 { "ntlm2", SMB_AT_NTLM2 },
912 { "krb5", SMB_AT_KRB5 },
913 { NULL, 0 },
914 };
915 int
916 smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
917 {
918 const char *sep = ":;,";
919 const char *p = arg;
920 struct nv *nv;
921 int nlen, tlen;
922 int authflags = 0;
923
924 for (;;) {
925 /* skip separators */
926 tlen = strspn(p, sep);
927 p += tlen;
928
929 nlen = strcspn(p, sep);
930 if (nlen == 0)
931 break;
932
933 if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) {
934 /* Don't offer extended security. */
935 ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
936 p += nlen;
937 continue;
938 }
939
940 /* This is rarely called, so not optimized. */
941 for (nv = sectype_table; nv->name; nv++) {
942 tlen = strlen(nv->name);
943 if (tlen == nlen && 0 == strncmp(p, nv->name, tlen))
944 break;
945 }
946 if (nv->name == NULL) {
947 smb_error(dgettext(TEXT_DOMAIN,
948 "%s: invalid security options"), 0, p);
949 return (EINVAL);
950 }
951 authflags |= nv->value;
952 p += nlen;
953 }
954
955 if (authflags)
956 ctx->ct_authflags = authflags;
957
958 return (0);
959 }
1100 #endif /* KICONV_SUPPORT */
1101
1102 /*
1103 * Lookup the IP address and fill in ct_addrinfo.
1104 *
1105 * Note: smb_ctx_getaddr() returns a EAI_xxx
1106 * error value like getaddrinfo(3), but this
1107 * function needs to return an errno value.
1108 */
1109 error = smb_ctx_getaddr(ctx);
1110 if (error) {
1111 const char *ais = gai_strerror(error);
1112 smb_error(dgettext(TEXT_DOMAIN,
1113 "can't resolve name\"%s\", %s"),
1114 0, ctx->ct_fullserver, ais);
1115 return (ENODATA);
1116 }
1117 assert(ctx->ct_addrinfo != NULL);
1118
1119 /*
1120 * If we have a user name but no password,
1121 * check for a keychain entry.
1122 * XXX: Only for auth NTLM?
1123 */
1124 if (ctx->ct_user[0] != '\0') {
1125 /*
1126 * Have a user name.
1127 * If we don't have a p/w yet,
1128 * try the keychain.
1129 */
1130 if (ctx->ct_password[0] == '\0')
1131 (void) smb_get_keychain(ctx);
1132 /*
1133 * Mask out disallowed auth types.
1134 */
1135 ctx->ct_authflags &= ctx->ct_minauth;
1136 }
1137 if (ctx->ct_authflags == 0) {
1138 smb_error(dgettext(TEXT_DOMAIN,
1139 "no valid auth. types"), 0);
1140 return (ENOTSUP);
1141 }
1142
1143 ctx->ct_flags |= SMBCF_RESOLVED;
1144 if (smb_debug)
1145 dump_ctx("after smb_ctx_resolve", ctx);
1146
1147 return (0);
1148 }
1149
1150 int
1151 smb_open_driver()
1152 {
1153 int fd;
1154
1155 fd = open("/dev/"NSMB_NAME, O_RDWR);
1156 if (fd < 0) {
1157 return (-1);
1158 }
1159
1160 /* This handle controls per-process resources. */
1161 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1162
1163 return (fd);
1164 }
1165
1166 int
1167 smb_ctx_gethandle(struct smb_ctx *ctx)
1168 {
1169 int fd, err;
1170 uint32_t version;
1171
1172 if (ctx->ct_dev_fd != -1) {
1173 rpc_cleanup_smbctx(ctx);
1174 close(ctx->ct_dev_fd);
1175 ctx->ct_dev_fd = -1;
1176 ctx->ct_flags &= ~SMBCF_SSNACTIVE;
1177 }
1178
1179 fd = smb_open_driver();
1180 if (fd < 0) {
1181 err = errno;
1182 smb_error(dgettext(TEXT_DOMAIN,
1183 "failed to open driver"), err);
1184 return (err);
1185 }
1186
1187 /*
1188 * Check the driver version (paranoia)
1189 */
1190 if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
1191 version = 0;
1192 if (version != NSMB_VERSION) {
1193 smb_error(dgettext(TEXT_DOMAIN,
1194 "incorrect driver version"), 0);
1195 close(fd);
1196 return (ENODEV);
1197 }
1198
1199 ctx->ct_dev_fd = fd;
1200 return (0);
1201 }
1202
1203
1204 /*
1205 * Find or create a connection + logon session
1206 */
1207 int
1208 smb_ctx_get_ssn(struct smb_ctx *ctx)
1209 {
1210 int err = 0;
1211
1212 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
1213 return (EINVAL);
1214
1215 if (ctx->ct_dev_fd < 0) {
1216 if ((err = smb_ctx_gethandle(ctx)))
1217 return (err);
1218 }
1219
1220 /*
1221 * Check whether the driver already has a VC
1222 * we can use. If so, we're done!
1223 */
1224 err = smb_ctx_findvc(ctx);
1225 if (err == 0) {
1226 DPRINT("found an existing VC");
1227 } else {
1228 /*
1229 * This calls the IOD to create a new session.
1230 */
1231 DPRINT("setup a new VC");
1232 err = smb_ctx_newvc(ctx);
1233 if (err != 0)
1234 return (err);
1235
1236 /*
1237 * Call findvc again. The new VC sould be
1238 * found in the driver this time.
1239 */
1240 err = smb_ctx_findvc(ctx);
1241 }
1242
1243 return (err);
1244 }
1245
1246 /*
1247 * Find or create a tree connection
1248 */
1260 cmd = SMBIOC_TREE_CONNECT;
1261 tcon = malloc(sizeof (*tcon));
1262 if (tcon == NULL)
1263 return (ENOMEM);
1264 bzero(tcon, sizeof (*tcon));
1265 tcon->tc_flags = SMBLK_CREATE;
1266 tcon->tc_opt = 0;
1267
1268 /* The share name */
1269 strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
1270 sizeof (tcon->tc_sh.sh_name));
1271
1272 /* The share "use" type. */
1273 tcon->tc_sh.sh_use = ctx->ct_shtype_req;
1274
1275 /*
1276 * Todo: share passwords for share-level security.
1277 *
1278 * The driver does the actual TCON call.
1279 */
1280 if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
1281 err = errno;
1282 goto out;
1283 }
1284
1285 /*
1286 * Check the returned share type
1287 */
1288 DPRINT("ret. sh_type: \"%d\"", tcon->tc_sh.sh_type);
1289 if (ctx->ct_shtype_req != USE_WILDCARD &&
1290 ctx->ct_shtype_req != tcon->tc_sh.sh_type) {
1291 smb_error(dgettext(TEXT_DOMAIN,
1292 "%s: incompatible share type"),
1293 0, ctx->ct_origshare);
1294 }
1295
1296 out:
1297 if (tcon != NULL)
1298 free(tcon);
1299
1300 return (err);
1301 }
1302
1303 /*
1304 * Return the hflags2 word for an smb_ctx.
1305 */
1306 int
1307 smb_ctx_flags2(struct smb_ctx *ctx)
1308 {
1309 uint16_t flags2;
1310
1311 if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
1312 smb_error(dgettext(TEXT_DOMAIN,
1313 "can't get flags2 for a session"), errno);
1314 return (-1);
1315 }
1316 return (flags2);
1317 }
1318
1319 /*
1320 * Get the transport level session key.
1321 * Must already have an active SMB session.
1322 */
1323 int
1324 smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len)
1325 {
1326 if (len < SMBIOC_HASH_SZ)
1327 return (EINVAL);
1328
1329 if (ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
1330 return (errno);
1331
1332 return (0);
1333 }
1334
1335 /*
1336 * RC file parsing stuff
1337 */
1338
1339 static struct nv
1340 minauth_table[] = {
1341 /* Allowed auth. types */
1342 { "kerberos", SMB_AT_KRB5 },
1343 { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 },
1344 { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
1345 { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
1346 { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
1347 SMB_AT_ANON },
1348 { NULL }
1349 };
1350
1351
1352 /*
1353 * level values:
1354 * 0 - default
1355 * 1 - server
1356 * 2 - server:user
1357 * 3 - server:user:share
1358 */
1359 static int
1360 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
1361 {
1362 char *p;
1363 int error;
1364
1365 #ifdef KICONV_SUPPORT
1366 if (level > 0) {
1367 rc_getstringptr(smb_rc, sname, "charsets", &p);
1368 if (p) {
1369 error = smb_ctx_setcharset(ctx, p);
1370 if (error)
1371 smb_error(dgettext(TEXT_DOMAIN,
1372 "charset specification in the section '%s' ignored"),
1373 error, sname);
1374 }
1375 }
1376 #endif
1377
1378 if (level <= 1) {
1379 /* Section is: [default] or [server] */
1380
1381 rc_getstringptr(smb_rc, sname, "minauth", &p);
1382 if (p) {
1383 /*
1384 * "minauth" was set in this section; override
1385 * the current minimum authentication setting.
1386 */
1387 struct nv *nvp;
1388 for (nvp = minauth_table; nvp->name; nvp++)
1389 if (strcmp(p, nvp->name) == 0)
1390 break;
1391 if (nvp->name)
1392 ctx->ct_minauth = nvp->value;
1393 else {
1394 /*
1395 * Unknown minimum authentication level.
1396 */
1397 smb_error(dgettext(TEXT_DOMAIN,
1398 "invalid minimum authentication level \"%s\" specified in the section %s"),
1399 0, p, sname);
1400 return (EINVAL);
1401 }
1402 }
1403
1404 rc_getstringptr(smb_rc, sname, "signing", &p);
1405 if (p) {
1406 /*
1407 * "signing" was set in this section; override
1408 * the current signing settings. Note:
1409 * setsigning flags are: enable, require
1410 */
1411 if (strcmp(p, "disabled") == 0) {
1412 (void) smb_ctx_setsigning(ctx, FALSE, FALSE);
1413 } else if (strcmp(p, "enabled") == 0) {
|
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 /*
36 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
38 */
39
40 #include <sys/param.h>
41 #include <sys/ioctl.h>
42 #include <sys/time.h>
43 #include <sys/mount.h>
44 #include <sys/types.h>
45 #include <sys/byteorder.h>
46
47 #include <fcntl.h>
48 #include <ctype.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <strings.h>
53 #include <stdlib.h>
54 #include <pwd.h>
55 #include <grp.h>
56 #include <unistd.h>
57 #include <libintl.h>
131 if (flags & SMBCF_LOCALE)
132 printf("LOCALE ");
133 if (flags & SMBCF_CMD_DOM)
134 printf("CMD_DOM ");
135 if (flags & SMBCF_CMD_USR)
136 printf("CMD_USR ");
137 if (flags & SMBCF_CMD_PW)
138 printf("CMD_PW ");
139 if (flags & SMBCF_RESOLVED)
140 printf("RESOLVED ");
141 if (flags & SMBCF_KCBAD)
142 printf("KCBAD ");
143 if (flags & SMBCF_KCFOUND)
144 printf("KCFOUND ");
145 if (flags & SMBCF_BROWSEOK)
146 printf("BROWSEOK ");
147 if (flags & SMBCF_AUTHREQ)
148 printf("AUTHREQ ");
149 if (flags & SMBCF_KCSAVE)
150 printf("KCSAVE ");
151 if (flags & SMBCF_KCDOMAIN)
152 printf("KCDOMAIN ");
153 printf("\n");
154 }
155
156 void
157 dump_iod_ssn(smb_iod_ssn_t *is)
158 {
159 static const char zeros[NTLM_HASH_SZ] = {0};
160 struct smbioc_ossn *ssn = &is->iod_ossn;
161
162 printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
163 dump_sockaddr(&ssn->ssn_srvaddr.sa);
164 printf(" dom=\"%s\", user=\"%s\"\n",
165 ssn->ssn_domain, ssn->ssn_user);
166 printf(" ct_vopt=0x%x, ct_owner=%d\n",
167 ssn->ssn_vopt, ssn->ssn_owner);
168 printf(" ct_minver=0x%x, ct_maxver=0x%x\n",
169 ssn->ssn_minver, ssn->ssn_maxver);
170 printf(" ct_authflags=0x%x\n", is->iod_authflags);
171
172 printf(" ct_nthash:");
173 if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
174 smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
175 else
176 printf(" {0}\n");
177
178 printf(" ct_lmhash:");
179 if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
180 smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
181 else
182 printf(" {0}\n");
183 }
184
185 void
186 dump_ctx(char *where, struct smb_ctx *ctx)
187 {
188 printf("context %s:\n", where);
189 dump_ctx_flags(ctx->ct_flags);
235 *ctx_pp = ctx;
236 return (0);
237 }
238
239 /*
240 * Initialize an smb_ctx struct (defaults)
241 */
242 int
243 smb_ctx_init(struct smb_ctx *ctx)
244 {
245 int error;
246
247 bzero(ctx, sizeof (*ctx));
248
249 error = nb_ctx_create(&ctx->ct_nb);
250 if (error)
251 return (error);
252
253 ctx->ct_dev_fd = -1;
254 ctx->ct_door_fd = -1;
255 ctx->ct_parsedlevel = SMBL_NONE;
256 ctx->ct_minlevel = SMBL_NONE;
257 ctx->ct_maxlevel = SMBL_PATH;
258
259 /* Fill in defaults */
260 ctx->ct_vopt = SMBVOPT_SIGNING_ENABLED;
261 ctx->ct_owner = SMBM_ANY_OWNER;
262 ctx->ct_authflags = SMB_AT_DEFAULT;
263 ctx->ct_minauth = SMB_AT_MINAUTH;
264 ctx->ct_maxver = SMB2_DIALECT_MAX;
265
266 /*
267 * Default domain, user, ...
268 */
269 strlcpy(ctx->ct_domain, default_domain,
270 sizeof (ctx->ct_domain));
271 strlcpy(ctx->ct_user, default_user,
272 sizeof (ctx->ct_user));
273
274 return (0);
275 }
276
277 /*
278 * "Scan" the command line args to find the server name,
279 * user name, and share name, as needed. We need these
280 * before reading the RC files and/or sharectl values.
281 *
282 * The sequence for getting all the members filled in
283 * has some tricky aspects. Here's how it works:
284 *
314 int minlevel, int maxlevel, int sharetype)
315 {
316 int ind, opt, error = 0;
317 int aflg = 0, uflg = 0;
318 const char *arg;
319
320 /*
321 * Parse options, if any. Values from here too
322 * are marked as "from CMD".
323 */
324 if (argv == NULL)
325 return (0);
326
327 ctx->ct_minlevel = minlevel;
328 ctx->ct_maxlevel = maxlevel;
329 ctx->ct_shtype_req = sharetype;
330
331 cf_opt_lock();
332 /* Careful: no return/goto before cf_opt_unlock! */
333 while (error == 0) {
334 /*
335 * Leading ':' tells this to skip unknown opts.
336 * Just get -A and -U here so we know the user
337 * for config file parsing.
338 */
339 opt = cf_getopt(argc, argv, ":AU:");
340 if (opt == -1)
341 break;
342 arg = cf_optarg;
343 /* NB: handle most in smb_ctx_opt */
344 switch (opt) {
345 case 'A':
346 aflg = 1;
347 error = smb_ctx_setuser(ctx, "", TRUE);
348 ctx->ct_flags |= SMBCF_NOPWD;
349 break;
350 case 'U':
351 uflg = 1;
352 error = smb_ctx_setuser(ctx, arg, TRUE);
353 break;
354 default:
355 DPRINT("skip opt=%c", opt);
356 break;
357 }
358 }
359 ind = cf_optind;
384 break;
385 }
386
387 return (error);
388 }
389
390 void
391 smb_ctx_free(smb_ctx_t *ctx)
392 {
393 smb_ctx_done(ctx);
394 free(ctx);
395 }
396
397 void
398 smb_ctx_done(struct smb_ctx *ctx)
399 {
400
401 rpc_cleanup_smbctx(ctx);
402
403 if (ctx->ct_dev_fd != -1) {
404 nsmb_close(ctx->ct_dev_fd);
405 ctx->ct_dev_fd = -1;
406 }
407 if (ctx->ct_door_fd != -1) {
408 close(ctx->ct_door_fd);
409 ctx->ct_door_fd = -1;
410 }
411 if (ctx->ct_srvaddr_s) {
412 free(ctx->ct_srvaddr_s);
413 ctx->ct_srvaddr_s = NULL;
414 }
415 if (ctx->ct_nb) {
416 nb_ctx_done(ctx->ct_nb);
417 ctx->ct_nb = NULL;
418 }
419 if (ctx->ct_locname) {
420 free(ctx->ct_locname);
421 ctx->ct_locname = NULL;
422 }
423 if (ctx->ct_origshare) {
424 free(ctx->ct_origshare);
425 ctx->ct_origshare = NULL;
426 }
427 if (ctx->ct_fullserver) {
428 free(ctx->ct_fullserver);
429 ctx->ct_fullserver = NULL;
430 }
431 if (ctx->ct_addrinfo) {
432 freeaddrinfo(ctx->ct_addrinfo);
433 ctx->ct_addrinfo = NULL;
434 }
435 if (ctx->ct_home) {
436 free(ctx->ct_home);
437 ctx->ct_home = NULL;
438 }
439 if (ctx->ct_rpath) {
440 free(ctx->ct_rpath);
441 ctx->ct_rpath = NULL;
442 }
443 if (ctx->ct_ssnkey_buf) {
444 free(ctx->ct_ssnkey_buf);
445 ctx->ct_ssnkey_buf = NULL;
446 }
447 }
448
449 /*
450 * Parse the UNC path. Here we expect something like
451 * "//[[domain;]user[:password]@]host[/share[/path]]"
452 * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
453 * Values found here are marked as "from CMD".
454 */
455 int
456 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
457 int minlevel, int maxlevel, int sharetype,
458 const char **next)
459 {
460 char tmp[1024];
461 char *host, *share, *path;
462 char *dom, *usr, *pw, *p;
463 int error;
464
465 /*
466 * This may be called outside of _scan_argv,
842 return (ENOMEM);
843 return (0);
844 }
845
846 /*
847 * API for library caller to set signing enabled, required
848 * Note: if not enable, ignore require
849 */
850 int
851 smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
852 {
853 ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
854 if (enable) {
855 ctx->ct_vopt |= SMBVOPT_SIGNING_ENABLED;
856 if (require)
857 ctx->ct_vopt |= SMBVOPT_SIGNING_REQUIRED;
858 }
859 return (0);
860 }
861
862 /*
863 * Handle .nsmbrc "minver" option.
864 * Must be <= maxver
865 */
866 int
867 smb_ctx_setminver(struct smb_ctx *ctx, int ver)
868 {
869 if (ver < 0 || ver > ctx->ct_maxver)
870 return (EINVAL);
871 ctx->ct_minver = (uint16_t)ver;
872 return (0);
873 }
874
875 /*
876 * Handle .nsmbrc "maxver" option.
877 * Must be >= minver
878 *
879 * Any "too high" value is just clamped, so the caller
880 * doesn't need to know what's the highest we support.
881 */
882 int
883 smb_ctx_setmaxver(struct smb_ctx *ctx, int ver)
884 {
885 if (ver < 1 || ver < ctx->ct_minver)
886 return (EINVAL);
887 if (ver > SMB2_DIALECT_MAX)
888 ver = SMB2_DIALECT_MAX;
889 ctx->ct_maxver = (uint16_t)ver;
890 return (0);
891 }
892
893 static int
894 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
895 {
896 struct group gr;
897 struct passwd pw;
898 char buf[NSS_BUFLEN_PASSWD];
899 char *cp;
900
901 cp = strchr(pair, ':');
902 if (cp) {
903 *cp++ = '\0';
904 if (*cp && gid) {
905 if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
906 *gid = gr.gr_gid;
907 } else
908 smb_error(dgettext(TEXT_DOMAIN,
909 "Invalid group name %s, ignored"), 0, cp);
910 }
911 }
912 if (*pair) {
913 if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
914 *uid = pw.pw_uid;
915 } else
916 smb_error(dgettext(TEXT_DOMAIN,
917 "Invalid user name %s, ignored"), 0, pair);
918 }
919
920 return (0);
921 }
922
923 /*
924 * Suport a securty options arg, i.e. -S lm,ntlm
925 * for testing various type of authenticators.
926 */
927 static struct nv
928 sectype_table[] = {
929 { "anon", SMB_AT_ANON },
930 { "lm", SMB_AT_LM1 },
931 { "ntlm", SMB_AT_NTLM1 },
932 { "ntlm2", SMB_AT_NTLM2 },
933 { "krb5", SMB_AT_KRB5 },
934 { NULL, 0 },
935 };
936 int
937 smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
938 {
939 const char *sep = ":;,";
940 const char *p = arg;
941 struct nv *nv;
942 int nlen, tlen;
943 int authflags = 0;
944
945 for (;;) {
946 /* skip separators */
947 tlen = strspn(p, sep);
948 p += tlen;
949
950 nlen = strcspn(p, sep);
951 if (nlen == 0)
952 break;
953
954 /* This is rarely called, so not optimized. */
955 for (nv = sectype_table; nv->name; nv++) {
956 tlen = strlen(nv->name);
957 if (tlen == nlen && 0 == strncmp(p, nv->name, tlen))
958 break;
959 }
960 if (nv->name == NULL) {
961 smb_error(dgettext(TEXT_DOMAIN,
962 "%s: invalid security options"), 0, p);
963 return (EINVAL);
964 }
965 authflags |= nv->value;
966 p += nlen;
967 }
968
969 if (authflags)
970 ctx->ct_authflags = authflags;
971
972 return (0);
973 }
1114 #endif /* KICONV_SUPPORT */
1115
1116 /*
1117 * Lookup the IP address and fill in ct_addrinfo.
1118 *
1119 * Note: smb_ctx_getaddr() returns a EAI_xxx
1120 * error value like getaddrinfo(3), but this
1121 * function needs to return an errno value.
1122 */
1123 error = smb_ctx_getaddr(ctx);
1124 if (error) {
1125 const char *ais = gai_strerror(error);
1126 smb_error(dgettext(TEXT_DOMAIN,
1127 "can't resolve name\"%s\", %s"),
1128 0, ctx->ct_fullserver, ais);
1129 return (ENODATA);
1130 }
1131 assert(ctx->ct_addrinfo != NULL);
1132
1133 /*
1134 * Empty user name means an explicit request for
1135 * NULL session setup, which is a special case.
1136 * (No SMB signing, per [MS-SMB] 3.3.5.3)
1137 */
1138 if (ctx->ct_user[0] == '\0') {
1139 /* Null user should have null domain too. */
1140 ctx->ct_domain[0] = '\0';
1141 ctx->ct_authflags = SMB_AT_ANON;
1142 ctx->ct_vopt |= SMBVOPT_ANONYMOUS;
1143 ctx->ct_vopt &= ~SMBVOPT_SIGNING_REQUIRED;
1144 }
1145
1146 /*
1147 * If we have a user name but no password,
1148 * check for a keychain entry.
1149 * XXX: Only for auth NTLM?
1150 */
1151 if (ctx->ct_user[0] != '\0') {
1152 /*
1153 * Have a user name.
1154 * If we don't have a p/w yet,
1155 * try the keychain.
1156 */
1157 if (ctx->ct_password[0] == '\0' &&
1158 smb_get_keychain(ctx) == 0) {
1159 strlcpy(ctx->ct_password, "$HASH",
1160 sizeof (ctx->ct_password));
1161 }
1162
1163 /*
1164 * Mask out disallowed auth types.
1165 */
1166 ctx->ct_authflags &= ctx->ct_minauth;
1167 }
1168
1169 if (ctx->ct_authflags == 0) {
1170 smb_error(dgettext(TEXT_DOMAIN,
1171 "no valid auth. types"), 0);
1172 return (ENOTSUP);
1173 }
1174
1175 ctx->ct_flags |= SMBCF_RESOLVED;
1176 if (smb_debug)
1177 dump_ctx("after smb_ctx_resolve", ctx);
1178
1179 return (0);
1180 }
1181
1182 /*
1183 * Note: The next three have NODIRECT binding so the
1184 * "fksmbcl" development tool can provide its own.
1185 */
1186 int
1187 smb_open_driver()
1188 {
1189 int fd;
1190
1191 fd = open("/dev/"NSMB_NAME, O_RDWR);
1192 if (fd < 0) {
1193 return (-1);
1194 }
1195
1196 /* This handle controls per-process resources. */
1197 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1198
1199 return (fd);
1200 }
1201
1202 int
1203 nsmb_close(int fd)
1204 {
1205 return (close(fd));
1206 }
1207
1208 int
1209 nsmb_ioctl(int fd, int cmd, void *arg)
1210 {
1211 return (ioctl(fd, cmd, arg));
1212 }
1213
1214
1215 int
1216 smb_ctx_gethandle(struct smb_ctx *ctx)
1217 {
1218 int fd, err;
1219 uint32_t version;
1220
1221 if (ctx->ct_dev_fd != -1) {
1222 rpc_cleanup_smbctx(ctx);
1223 nsmb_close(ctx->ct_dev_fd);
1224 ctx->ct_dev_fd = -1;
1225 }
1226
1227 fd = smb_open_driver();
1228 if (fd < 0) {
1229 err = errno;
1230 smb_error(dgettext(TEXT_DOMAIN,
1231 "failed to open driver"), err);
1232 return (err);
1233 }
1234
1235 /*
1236 * Check the driver version (paranoia)
1237 */
1238 if (nsmb_ioctl(fd, SMBIOC_GETVERS, &version) < 0)
1239 version = 0;
1240 if (version != NSMB_VERSION) {
1241 smb_error(dgettext(TEXT_DOMAIN,
1242 "incorrect driver version"), 0);
1243 nsmb_close(fd);
1244 return (ENODEV);
1245 }
1246
1247 ctx->ct_dev_fd = fd;
1248 return (0);
1249 }
1250
1251
1252 /*
1253 * Find or create a connection + logon session
1254 */
1255 int
1256 smb_ctx_get_ssn(struct smb_ctx *ctx)
1257 {
1258 int err = 0;
1259
1260 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
1261 return (EINVAL);
1262
1263 /*
1264 * Check whether the driver already has a VC
1265 * we can use. If so, we're done!
1266 */
1267 err = smb_ctx_findvc(ctx);
1268 if (err == 0) {
1269 DPRINT("found an existing VC");
1270 } else {
1271 /*
1272 * If we're authenticating (real user, not NULL session)
1273 * and we don't yet have a password, return EAUTH and
1274 * the caller will prompt for it and call again.
1275 */
1276 if (ctx->ct_user[0] != '\0' &&
1277 ctx->ct_password[0] == '\0')
1278 return (EAUTH);
1279
1280 /*
1281 * This calls the IOD to create a new session.
1282 */
1283 DPRINT("setup a new VC");
1284 err = smb_ctx_newvc(ctx);
1285 if (err != 0)
1286 return (err);
1287
1288 /*
1289 * Call findvc again. The new VC sould be
1290 * found in the driver this time.
1291 */
1292 err = smb_ctx_findvc(ctx);
1293 }
1294
1295 return (err);
1296 }
1297
1298 /*
1299 * Find or create a tree connection
1300 */
1312 cmd = SMBIOC_TREE_CONNECT;
1313 tcon = malloc(sizeof (*tcon));
1314 if (tcon == NULL)
1315 return (ENOMEM);
1316 bzero(tcon, sizeof (*tcon));
1317 tcon->tc_flags = SMBLK_CREATE;
1318 tcon->tc_opt = 0;
1319
1320 /* The share name */
1321 strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
1322 sizeof (tcon->tc_sh.sh_name));
1323
1324 /* The share "use" type. */
1325 tcon->tc_sh.sh_use = ctx->ct_shtype_req;
1326
1327 /*
1328 * Todo: share passwords for share-level security.
1329 *
1330 * The driver does the actual TCON call.
1331 */
1332 if (nsmb_ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
1333 err = errno;
1334 goto out;
1335 }
1336
1337 /*
1338 * Check the returned share type
1339 */
1340 DPRINT("ret. sh_type: \"%d\"", tcon->tc_sh.sh_type);
1341 if (ctx->ct_shtype_req != USE_WILDCARD &&
1342 ctx->ct_shtype_req != tcon->tc_sh.sh_type) {
1343 smb_error(dgettext(TEXT_DOMAIN,
1344 "%s: incompatible share type"),
1345 0, ctx->ct_origshare);
1346 }
1347
1348 out:
1349 if (tcon != NULL)
1350 free(tcon);
1351
1352 return (err);
1353 }
1354
1355 /*
1356 * Return the hflags2 word for an smb_ctx.
1357 */
1358 int
1359 smb_ctx_flags2(struct smb_ctx *ctx)
1360 {
1361 uint16_t flags2;
1362
1363 if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
1364 smb_error(dgettext(TEXT_DOMAIN,
1365 "can't get flags2 for a session"), errno);
1366 return (-1);
1367 }
1368 return (flags2);
1369 }
1370
1371 /*
1372 * Get the transport level session key.
1373 * Must already have an active SMB session.
1374 */
1375 int
1376 smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len)
1377 {
1378 if (len < SMBIOC_HASH_SZ)
1379 return (EINVAL);
1380
1381 if (nsmb_ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
1382 return (errno);
1383
1384 return (0);
1385 }
1386
1387 /*
1388 * RC file parsing stuff
1389 */
1390
1391 static struct nv
1392 minauth_table[] = {
1393 /* Allowed auth. types */
1394 { "kerberos", SMB_AT_KRB5 },
1395 { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 },
1396 { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
1397 { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
1398 { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
1399 SMB_AT_ANON },
1400 { NULL }
1401 };
1402
1403 int
1404 smb_cf_minauth_from_str(char *str)
1405 {
1406 struct nv *nvp;
1407
1408 for (nvp = minauth_table; nvp->name; nvp++)
1409 if (strcmp(nvp->name, str) == 0)
1410 return (nvp->value);
1411 return (-1);
1412 }
1413
1414
1415 static struct nv
1416 smbver_table[] = {
1417 { "2.1", SMB2_DIALECT_0210 },
1418 { "1", 1 },
1419 { NULL, 0 }
1420 };
1421
1422 int
1423 smb_cf_version_from_str(char *str)
1424 {
1425 struct nv *nvp;
1426
1427 for (nvp = smbver_table; nvp->name; nvp++)
1428 if (strcmp(nvp->name, str) == 0)
1429 return (nvp->value);
1430 return (-1);
1431 }
1432
1433 /*
1434 * level values:
1435 * 0 - default
1436 * 1 - server
1437 * 2 - server:user
1438 * 3 - server:user:share
1439 */
1440 static int
1441 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
1442 {
1443 char *p;
1444 int ival;
1445 int error;
1446 int minver, maxver;
1447
1448 #ifdef KICONV_SUPPORT
1449 if (level > 0) {
1450 rc_getstringptr(smb_rc, sname, "charsets", &p);
1451 if (p) {
1452 error = smb_ctx_setcharset(ctx, p);
1453 if (error)
1454 smb_error(dgettext(TEXT_DOMAIN,
1455 "charset specification in the section '%s' ignored"),
1456 error, sname);
1457 }
1458 }
1459 #endif
1460
1461 if (level <= 1) {
1462 /* Section is: [default] or [server] */
1463
1464 /*
1465 * Handle min_protocol, max_protocol
1466 * (SMB protocol versions)
1467 */
1468 minver = -1;
1469 rc_getstringptr(smb_rc, sname, "min_protocol", &p);
1470 if (p != NULL) {
1471 minver = smb_cf_version_from_str(p);
1472 if (minver == -1) {
1473 smb_error(dgettext(TEXT_DOMAIN,
1474 "invalid min_protocol value \"%s\" specified in the section %s"),
1475 0, p, sname);
1476 }
1477 }
1478 maxver = -1;
1479 rc_getstringptr(smb_rc, sname, "max_protocol", &p);
1480 if (p != NULL) {
1481 maxver = smb_cf_version_from_str(p);
1482 if (maxver == -1) {
1483 smb_error(dgettext(TEXT_DOMAIN,
1484 "invalid max_protocol value \"%s\" specified in the section %s"),
1485 0, p, sname);
1486 }
1487 }
1488
1489 /*
1490 * If setting both min/max protocol,
1491 * validate against each other
1492 */
1493 if (minver != -1 && maxver != -1) {
1494 if (minver > maxver) {
1495 smb_error(dgettext(TEXT_DOMAIN,
1496 "invalid min/max protocol combination in the section %s"),
1497 0, sname);
1498 } else {
1499 ctx->ct_minver = minver;
1500 ctx->ct_maxver = maxver;
1501 }
1502 }
1503
1504 /*
1505 * Setting just min or max, validate against
1506 * current settings
1507 */
1508 if (minver != -1) {
1509 if (minver > ctx->ct_maxver) {
1510 smb_error(dgettext(TEXT_DOMAIN,
1511 "invalid min/max protocol combination in the section %s"),
1512 0, sname);
1513 } else {
1514 ctx->ct_minver = minver;
1515 }
1516 }
1517 if (maxver != -1) {
1518 if (maxver < ctx->ct_minver) {
1519 smb_error(dgettext(TEXT_DOMAIN,
1520 "invalid min/max protocol combination in the section %s"),
1521 0, sname);
1522 } else {
1523 ctx->ct_maxver = maxver;
1524 }
1525 }
1526
1527 rc_getstringptr(smb_rc, sname, "minauth", &p);
1528 if (p) {
1529 /*
1530 * "minauth" was set in this section; override
1531 * the current minimum authentication setting.
1532 */
1533 ival = smb_cf_minauth_from_str(p);
1534 if (ival != -1) {
1535 ctx->ct_minauth = ival;
1536 } else {
1537 /*
1538 * Unknown minimum authentication level.
1539 */
1540 smb_error(dgettext(TEXT_DOMAIN,
1541 "invalid minimum authentication level \"%s\" specified in the section %s"),
1542 0, p, sname);
1543 return (EINVAL);
1544 }
1545 }
1546
1547 rc_getstringptr(smb_rc, sname, "signing", &p);
1548 if (p) {
1549 /*
1550 * "signing" was set in this section; override
1551 * the current signing settings. Note:
1552 * setsigning flags are: enable, require
1553 */
1554 if (strcmp(p, "disabled") == 0) {
1555 (void) smb_ctx_setsigning(ctx, FALSE, FALSE);
1556 } else if (strcmp(p, "enabled") == 0) {
|