1142 error: |
1223 error: |
1143 nvlist_free(ret); |
1224 nvlist_free(ret); |
1144 return (NULL); |
1225 return (NULL); |
1145 } |
1226 } |
1146 |
1227 |
1147 static int |
|
1148 zfs_get_perm_who(const char *who, zfs_deleg_who_type_t *who_type, |
|
1149 uint64_t *ret_who) |
|
1150 { |
|
1151 struct passwd *pwd; |
|
1152 struct group *grp; |
|
1153 uid_t id; |
|
1154 |
|
1155 if (*who_type == ZFS_DELEG_EVERYONE || *who_type == ZFS_DELEG_CREATE || |
|
1156 *who_type == ZFS_DELEG_NAMED_SET) { |
|
1157 *ret_who = -1; |
|
1158 return (0); |
|
1159 } |
|
1160 if (who == NULL && !(*who_type == ZFS_DELEG_EVERYONE)) |
|
1161 return (EZFS_BADWHO); |
|
1162 |
|
1163 if (*who_type == ZFS_DELEG_WHO_UNKNOWN && |
|
1164 strcmp(who, "everyone") == 0) { |
|
1165 *ret_who = -1; |
|
1166 *who_type = ZFS_DELEG_EVERYONE; |
|
1167 return (0); |
|
1168 } |
|
1169 |
|
1170 pwd = getpwnam(who); |
|
1171 grp = getgrnam(who); |
|
1172 |
|
1173 if ((*who_type == ZFS_DELEG_USER) && pwd) { |
|
1174 *ret_who = pwd->pw_uid; |
|
1175 } else if ((*who_type == ZFS_DELEG_GROUP) && grp) { |
|
1176 *ret_who = grp->gr_gid; |
|
1177 } else if (pwd) { |
|
1178 *ret_who = pwd->pw_uid; |
|
1179 *who_type = ZFS_DELEG_USER; |
|
1180 } else if (grp) { |
|
1181 *ret_who = grp->gr_gid; |
|
1182 *who_type = ZFS_DELEG_GROUP; |
|
1183 } else { |
|
1184 char *end; |
|
1185 |
|
1186 id = strtol(who, &end, 10); |
|
1187 if (errno != 0 || *end != '\0') { |
|
1188 return (EZFS_BADWHO); |
|
1189 } else { |
|
1190 *ret_who = id; |
|
1191 if (*who_type == ZFS_DELEG_WHO_UNKNOWN) |
|
1192 *who_type = ZFS_DELEG_USER; |
|
1193 } |
|
1194 } |
|
1195 |
|
1196 return (0); |
|
1197 } |
|
1198 |
|
1199 static void |
|
1200 zfs_perms_add_to_nvlist(nvlist_t *who_nvp, char *name, nvlist_t *perms_nvp) |
|
1201 { |
|
1202 if (perms_nvp != NULL) { |
|
1203 verify(nvlist_add_nvlist(who_nvp, |
|
1204 name, perms_nvp) == 0); |
|
1205 } else { |
|
1206 verify(nvlist_add_boolean(who_nvp, name) == 0); |
|
1207 } |
|
1208 } |
|
1209 |
|
1210 static void |
|
1211 helper(zfs_deleg_who_type_t who_type, uint64_t whoid, char *whostr, |
|
1212 zfs_deleg_inherit_t inherit, nvlist_t *who_nvp, nvlist_t *perms_nvp, |
|
1213 nvlist_t *sets_nvp) |
|
1214 { |
|
1215 boolean_t do_perms, do_sets; |
|
1216 char name[ZFS_MAX_DELEG_NAME]; |
|
1217 |
|
1218 do_perms = (nvlist_next_nvpair(perms_nvp, NULL) != NULL); |
|
1219 do_sets = (nvlist_next_nvpair(sets_nvp, NULL) != NULL); |
|
1220 |
|
1221 if (!do_perms && !do_sets) |
|
1222 do_perms = do_sets = B_TRUE; |
|
1223 |
|
1224 if (do_perms) { |
|
1225 zfs_deleg_whokey(name, who_type, inherit, |
|
1226 (who_type == ZFS_DELEG_NAMED_SET) ? |
|
1227 whostr : (void *)&whoid); |
|
1228 zfs_perms_add_to_nvlist(who_nvp, name, perms_nvp); |
|
1229 } |
|
1230 if (do_sets) { |
|
1231 zfs_deleg_whokey(name, toupper(who_type), inherit, |
|
1232 (who_type == ZFS_DELEG_NAMED_SET) ? |
|
1233 whostr : (void *)&whoid); |
|
1234 zfs_perms_add_to_nvlist(who_nvp, name, sets_nvp); |
|
1235 } |
|
1236 } |
|
1237 |
|
1238 static void |
|
1239 zfs_perms_add_who_nvlist(nvlist_t *who_nvp, uint64_t whoid, void *whostr, |
|
1240 nvlist_t *perms_nvp, nvlist_t *sets_nvp, |
|
1241 zfs_deleg_who_type_t who_type, zfs_deleg_inherit_t inherit) |
|
1242 { |
|
1243 if (who_type == ZFS_DELEG_NAMED_SET || who_type == ZFS_DELEG_CREATE) { |
|
1244 helper(who_type, whoid, whostr, 0, |
|
1245 who_nvp, perms_nvp, sets_nvp); |
|
1246 } else { |
|
1247 if (inherit & ZFS_DELEG_PERM_LOCAL) { |
|
1248 helper(who_type, whoid, whostr, ZFS_DELEG_LOCAL, |
|
1249 who_nvp, perms_nvp, sets_nvp); |
|
1250 } |
|
1251 if (inherit & ZFS_DELEG_PERM_DESCENDENT) { |
|
1252 helper(who_type, whoid, whostr, ZFS_DELEG_DESCENDENT, |
|
1253 who_nvp, perms_nvp, sets_nvp); |
|
1254 } |
|
1255 } |
|
1256 } |
|
1257 |
|
1258 /* |
|
1259 * Construct nvlist to pass down to kernel for setting/removing permissions. |
|
1260 * |
|
1261 * The nvlist is constructed as a series of nvpairs with an optional embedded |
|
1262 * nvlist of permissions to remove or set. The topmost nvpairs are the actual |
|
1263 * base attribute named stored in the dsl. |
|
1264 * Arguments: |
|
1265 * |
|
1266 * whostr: is a comma separated list of users, groups, or a single set name. |
|
1267 * whostr may be null for everyone or create perms. |
|
1268 * who_type: is the type of entry in whostr. Typically this will be |
|
1269 * ZFS_DELEG_WHO_UNKNOWN. |
|
1270 * perms: common separated list of permissions. May be null if user |
|
1271 * is requested to remove permissions by who. |
|
1272 * inherit: Specifies the inheritance of the permissions. Will be either |
|
1273 * ZFS_DELEG_PERM_LOCAL and/or ZFS_DELEG_PERM_DESCENDENT. |
|
1274 * nvp The constructed nvlist to pass to zfs_perm_set(). |
|
1275 * The output nvp will look something like this. |
|
1276 * ul$1234 -> {create ; destroy } |
|
1277 * Ul$1234 -> { @myset } |
|
1278 * s-$@myset - { snapshot; checksum; compression } |
|
1279 */ |
|
1280 int |
|
1281 zfs_build_perms(zfs_handle_t *zhp, char *whostr, char *perms, |
|
1282 zfs_deleg_who_type_t who_type, zfs_deleg_inherit_t inherit, nvlist_t **nvp) |
|
1283 { |
|
1284 nvlist_t *who_nvp; |
|
1285 nvlist_t *perms_nvp = NULL; |
|
1286 nvlist_t *sets_nvp = NULL; |
|
1287 char errbuf[1024]; |
|
1288 char *who_tok, *perm; |
|
1289 int error; |
|
1290 |
|
1291 *nvp = NULL; |
|
1292 |
|
1293 if (perms) { |
|
1294 if ((error = nvlist_alloc(&perms_nvp, |
|
1295 NV_UNIQUE_NAME, 0)) != 0) { |
|
1296 return (1); |
|
1297 } |
|
1298 if ((error = nvlist_alloc(&sets_nvp, |
|
1299 NV_UNIQUE_NAME, 0)) != 0) { |
|
1300 nvlist_free(perms_nvp); |
|
1301 return (1); |
|
1302 } |
|
1303 } |
|
1304 |
|
1305 if ((error = nvlist_alloc(&who_nvp, NV_UNIQUE_NAME, 0)) != 0) { |
|
1306 if (perms_nvp) |
|
1307 nvlist_free(perms_nvp); |
|
1308 if (sets_nvp) |
|
1309 nvlist_free(sets_nvp); |
|
1310 return (1); |
|
1311 } |
|
1312 |
|
1313 if (who_type == ZFS_DELEG_NAMED_SET) { |
|
1314 namecheck_err_t why; |
|
1315 char what; |
|
1316 |
|
1317 if ((error = permset_namecheck(whostr, &why, &what)) != 0) { |
|
1318 nvlist_free(who_nvp); |
|
1319 if (perms_nvp) |
|
1320 nvlist_free(perms_nvp); |
|
1321 if (sets_nvp) |
|
1322 nvlist_free(sets_nvp); |
|
1323 |
|
1324 switch (why) { |
|
1325 case NAME_ERR_NO_AT: |
|
1326 zfs_error_aux(zhp->zfs_hdl, |
|
1327 dgettext(TEXT_DOMAIN, |
|
1328 "set definition must begin with an '@' " |
|
1329 "character")); |
|
1330 } |
|
1331 return (zfs_error(zhp->zfs_hdl, |
|
1332 EZFS_BADPERMSET, whostr)); |
|
1333 } |
|
1334 } |
|
1335 |
|
1336 /* |
|
1337 * Build up nvlist(s) of permissions. Two nvlists are maintained. |
|
1338 * The first nvlist perms_nvp will have normal permissions and the |
|
1339 * other sets_nvp will have only permssion set names in it. |
|
1340 */ |
|
1341 for (perm = strtok(perms, ","); perm; perm = strtok(NULL, ",")) { |
|
1342 const char *perm_canonical = zfs_deleg_canonicalize_perm(perm); |
|
1343 |
|
1344 if (perm_canonical) { |
|
1345 verify(nvlist_add_boolean(perms_nvp, |
|
1346 perm_canonical) == 0); |
|
1347 } else if (perm[0] == '@') { |
|
1348 verify(nvlist_add_boolean(sets_nvp, perm) == 0); |
|
1349 } else { |
|
1350 nvlist_free(who_nvp); |
|
1351 nvlist_free(perms_nvp); |
|
1352 nvlist_free(sets_nvp); |
|
1353 return (zfs_error(zhp->zfs_hdl, EZFS_BADPERM, perm)); |
|
1354 } |
|
1355 } |
|
1356 |
|
1357 if (whostr && who_type != ZFS_DELEG_CREATE) { |
|
1358 who_tok = strtok(whostr, ","); |
|
1359 if (who_tok == NULL) { |
|
1360 nvlist_free(who_nvp); |
|
1361 if (perms_nvp) |
|
1362 nvlist_free(perms_nvp); |
|
1363 if (sets_nvp) |
|
1364 nvlist_free(sets_nvp); |
|
1365 (void) snprintf(errbuf, sizeof (errbuf), |
|
1366 dgettext(TEXT_DOMAIN, "Who string is NULL"), |
|
1367 whostr); |
|
1368 return (zfs_error(zhp->zfs_hdl, EZFS_BADWHO, errbuf)); |
|
1369 } |
|
1370 } |
|
1371 |
|
1372 /* |
|
1373 * Now create the nvlist(s) |
|
1374 */ |
|
1375 do { |
|
1376 uint64_t who_id; |
|
1377 |
|
1378 error = zfs_get_perm_who(who_tok, &who_type, |
|
1379 &who_id); |
|
1380 if (error) { |
|
1381 nvlist_free(who_nvp); |
|
1382 if (perms_nvp) |
|
1383 nvlist_free(perms_nvp); |
|
1384 if (sets_nvp) |
|
1385 nvlist_free(sets_nvp); |
|
1386 (void) snprintf(errbuf, sizeof (errbuf), |
|
1387 dgettext(TEXT_DOMAIN, |
|
1388 "Unable to determine uid/gid for " |
|
1389 "%s "), who_tok); |
|
1390 return (zfs_error(zhp->zfs_hdl, EZFS_BADWHO, errbuf)); |
|
1391 } |
|
1392 |
|
1393 /* |
|
1394 * add entries for both local and descendent when required |
|
1395 */ |
|
1396 zfs_perms_add_who_nvlist(who_nvp, who_id, who_tok, |
|
1397 perms_nvp, sets_nvp, who_type, inherit); |
|
1398 |
|
1399 } while (who_tok = strtok(NULL, ",")); |
|
1400 *nvp = who_nvp; |
|
1401 return (0); |
|
1402 } |
|
1403 |
|
1404 static int |
|
1405 zfs_perm_set_common(zfs_handle_t *zhp, nvlist_t *nvp, boolean_t unset) |
|
1406 { |
|
1407 zfs_cmd_t zc = { 0 }; |
|
1408 int error; |
|
1409 char errbuf[1024]; |
|
1410 |
|
1411 (void) snprintf(errbuf, sizeof (errbuf), |
|
1412 dgettext(TEXT_DOMAIN, "Cannot update 'allows' for '%s'"), |
|
1413 zhp->zfs_name); |
|
1414 |
|
1415 if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, nvp)) |
|
1416 return (-1); |
|
1417 |
|
1418 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); |
|
1419 zc.zc_perm_action = unset; |
|
1420 |
|
1421 error = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SET_FSACL, &zc); |
|
1422 if (error && errno == ENOTSUP) { |
|
1423 (void) snprintf(errbuf, sizeof (errbuf), |
|
1424 gettext("Pool must be upgraded to use 'allow/unallow'")); |
|
1425 zcmd_free_nvlists(&zc); |
|
1426 return (zfs_error(zhp->zfs_hdl, EZFS_BADVERSION, errbuf)); |
|
1427 } else if (error) { |
|
1428 return (zfs_standard_error(zhp->zfs_hdl, errno, errbuf)); |
|
1429 } |
|
1430 zcmd_free_nvlists(&zc); |
|
1431 |
|
1432 return (error); |
|
1433 } |
|
1434 |
|
1435 int |
|
1436 zfs_perm_set(zfs_handle_t *zhp, nvlist_t *nvp) |
|
1437 { |
|
1438 return (zfs_perm_set_common(zhp, nvp, B_FALSE)); |
|
1439 } |
|
1440 |
|
1441 int |
|
1442 zfs_perm_remove(zfs_handle_t *zhp, nvlist_t *perms) |
|
1443 { |
|
1444 return (zfs_perm_set_common(zhp, perms, B_TRUE)); |
|
1445 } |
|
1446 |
|
1447 static int |
|
1448 perm_compare(const void *arg1, const void *arg2) |
|
1449 { |
|
1450 const zfs_perm_node_t *node1 = arg1; |
|
1451 const zfs_perm_node_t *node2 = arg2; |
|
1452 int ret; |
|
1453 |
|
1454 ret = strcmp(node1->z_pname, node2->z_pname); |
|
1455 |
|
1456 if (ret > 0) |
|
1457 return (1); |
|
1458 if (ret < 0) |
|
1459 return (-1); |
|
1460 else |
|
1461 return (0); |
|
1462 } |
|
1463 |
|
1464 static void |
|
1465 zfs_destroy_perm_tree(avl_tree_t *tree) |
|
1466 { |
|
1467 zfs_perm_node_t *permnode; |
|
1468 void *cookie = NULL; |
|
1469 |
|
1470 while ((permnode = avl_destroy_nodes(tree, &cookie)) != NULL) |
|
1471 free(permnode); |
|
1472 avl_destroy(tree); |
|
1473 } |
|
1474 |
|
1475 static void |
|
1476 zfs_destroy_tree(avl_tree_t *tree) |
|
1477 { |
|
1478 zfs_allow_node_t *allownode; |
|
1479 void *cookie = NULL; |
|
1480 |
|
1481 while ((allownode = avl_destroy_nodes(tree, &cookie)) != NULL) { |
|
1482 zfs_destroy_perm_tree(&allownode->z_localdescend); |
|
1483 zfs_destroy_perm_tree(&allownode->z_local); |
|
1484 zfs_destroy_perm_tree(&allownode->z_descend); |
|
1485 free(allownode); |
|
1486 } |
|
1487 avl_destroy(tree); |
|
1488 } |
|
1489 |
|
1490 void |
|
1491 zfs_free_allows(zfs_allow_t *allow) |
|
1492 { |
|
1493 zfs_allow_t *allownext; |
|
1494 zfs_allow_t *freeallow; |
|
1495 |
|
1496 allownext = allow; |
|
1497 while (allownext) { |
|
1498 zfs_destroy_tree(&allownext->z_sets); |
|
1499 zfs_destroy_tree(&allownext->z_crperms); |
|
1500 zfs_destroy_tree(&allownext->z_user); |
|
1501 zfs_destroy_tree(&allownext->z_group); |
|
1502 zfs_destroy_tree(&allownext->z_everyone); |
|
1503 freeallow = allownext; |
|
1504 allownext = allownext->z_next; |
|
1505 free(freeallow); |
|
1506 } |
|
1507 } |
|
1508 |
|
1509 static zfs_allow_t * |
|
1510 zfs_alloc_perm_tree(zfs_handle_t *zhp, zfs_allow_t *prev, char *setpoint) |
|
1511 { |
|
1512 zfs_allow_t *ptree; |
|
1513 |
|
1514 if ((ptree = zfs_alloc(zhp->zfs_hdl, |
|
1515 sizeof (zfs_allow_t))) == NULL) { |
|
1516 return (NULL); |
|
1517 } |
|
1518 |
|
1519 (void) strlcpy(ptree->z_setpoint, setpoint, sizeof (ptree->z_setpoint)); |
|
1520 avl_create(&ptree->z_sets, |
|
1521 perm_compare, sizeof (zfs_allow_node_t), |
|
1522 offsetof(zfs_allow_node_t, z_node)); |
|
1523 avl_create(&ptree->z_crperms, |
|
1524 perm_compare, sizeof (zfs_allow_node_t), |
|
1525 offsetof(zfs_allow_node_t, z_node)); |
|
1526 avl_create(&ptree->z_user, |
|
1527 perm_compare, sizeof (zfs_allow_node_t), |
|
1528 offsetof(zfs_allow_node_t, z_node)); |
|
1529 avl_create(&ptree->z_group, |
|
1530 perm_compare, sizeof (zfs_allow_node_t), |
|
1531 offsetof(zfs_allow_node_t, z_node)); |
|
1532 avl_create(&ptree->z_everyone, |
|
1533 perm_compare, sizeof (zfs_allow_node_t), |
|
1534 offsetof(zfs_allow_node_t, z_node)); |
|
1535 |
|
1536 if (prev) |
|
1537 prev->z_next = ptree; |
|
1538 ptree->z_next = NULL; |
|
1539 return (ptree); |
|
1540 } |
|
1541 |
|
1542 /* |
|
1543 * Add permissions to the appropriate AVL permission tree. |
|
1544 * The appropriate tree may not be the requested tree. |
|
1545 * For example if ld indicates a local permission, but |
|
1546 * same permission also exists as a descendent permission |
|
1547 * then the permission will be removed from the descendent |
|
1548 * tree and add the the local+descendent tree. |
|
1549 */ |
|
1550 static int |
|
1551 zfs_coalesce_perm(zfs_handle_t *zhp, zfs_allow_node_t *allownode, |
|
1552 char *perm, char ld) |
|
1553 { |
|
1554 zfs_perm_node_t pnode, *permnode, *permnode2; |
|
1555 zfs_perm_node_t *newnode; |
|
1556 avl_index_t where, where2; |
|
1557 avl_tree_t *tree, *altree; |
|
1558 |
|
1559 (void) strlcpy(pnode.z_pname, perm, sizeof (pnode.z_pname)); |
|
1560 |
|
1561 if (ld == ZFS_DELEG_NA) { |
|
1562 tree = &allownode->z_localdescend; |
|
1563 altree = &allownode->z_descend; |
|
1564 } else if (ld == ZFS_DELEG_LOCAL) { |
|
1565 tree = &allownode->z_local; |
|
1566 altree = &allownode->z_descend; |
|
1567 } else { |
|
1568 tree = &allownode->z_descend; |
|
1569 altree = &allownode->z_local; |
|
1570 } |
|
1571 permnode = avl_find(tree, &pnode, &where); |
|
1572 permnode2 = avl_find(altree, &pnode, &where2); |
|
1573 |
|
1574 if (permnode2) { |
|
1575 avl_remove(altree, permnode2); |
|
1576 free(permnode2); |
|
1577 if (permnode == NULL) { |
|
1578 tree = &allownode->z_localdescend; |
|
1579 } |
|
1580 } |
|
1581 |
|
1582 /* |
|
1583 * Now insert new permission in either requested location |
|
1584 * local/descendent or into ld when perm will exist in both. |
|
1585 */ |
|
1586 if (permnode == NULL) { |
|
1587 if ((newnode = zfs_alloc(zhp->zfs_hdl, |
|
1588 sizeof (zfs_perm_node_t))) == NULL) { |
|
1589 return (-1); |
|
1590 } |
|
1591 *newnode = pnode; |
|
1592 avl_add(tree, newnode); |
|
1593 } |
|
1594 return (0); |
|
1595 } |
|
1596 |
|
1597 /* |
|
1598 * Uggh, this is going to be a bit complicated. |
|
1599 * we have an nvlist coming out of the kernel that |
|
1600 * will indicate where the permission is set and then |
|
1601 * it will contain allow of the various "who's", and what |
|
1602 * their permissions are. To further complicate this |
|
1603 * we will then have to coalesce the local,descendent |
|
1604 * and local+descendent permissions where appropriate. |
|
1605 * The kernel only knows about a permission as being local |
|
1606 * or descendent, but not both. |
|
1607 * |
|
1608 * In order to make this easier for zfs_main to deal with |
|
1609 * a series of AVL trees will be used to maintain |
|
1610 * all of this, primarily for sorting purposes as well |
|
1611 * as the ability to quickly locate a specific entry. |
|
1612 * |
|
1613 * What we end up with are tree's for sets, create perms, |
|
1614 * user, groups and everyone. With each of those trees |
|
1615 * we have subtrees for local, descendent and local+descendent |
|
1616 * permissions. |
|
1617 */ |
|
1618 int |
|
1619 zfs_perm_get(zfs_handle_t *zhp, zfs_allow_t **zfs_perms) |
|
1620 { |
|
1621 zfs_cmd_t zc = { 0 }; |
|
1622 int error; |
|
1623 nvlist_t *nvlist; |
|
1624 nvlist_t *permnv, *sourcenv; |
|
1625 nvpair_t *who_pair, *source_pair; |
|
1626 nvpair_t *perm_pair; |
|
1627 char errbuf[1024]; |
|
1628 zfs_allow_t *zallowp, *newallowp; |
|
1629 char ld; |
|
1630 char *nvpname; |
|
1631 uid_t uid; |
|
1632 gid_t gid; |
|
1633 avl_tree_t *tree; |
|
1634 avl_index_t where; |
|
1635 |
|
1636 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); |
|
1637 |
|
1638 if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) |
|
1639 return (-1); |
|
1640 |
|
1641 while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { |
|
1642 if (errno == ENOMEM) { |
|
1643 if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, &zc) != 0) { |
|
1644 zcmd_free_nvlists(&zc); |
|
1645 return (-1); |
|
1646 } |
|
1647 } else if (errno == ENOTSUP) { |
|
1648 zcmd_free_nvlists(&zc); |
|
1649 (void) snprintf(errbuf, sizeof (errbuf), |
|
1650 gettext("Pool must be upgraded to use 'allow'")); |
|
1651 return (zfs_error(zhp->zfs_hdl, |
|
1652 EZFS_BADVERSION, errbuf)); |
|
1653 } else { |
|
1654 zcmd_free_nvlists(&zc); |
|
1655 return (-1); |
|
1656 } |
|
1657 } |
|
1658 |
|
1659 if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &nvlist) != 0) { |
|
1660 zcmd_free_nvlists(&zc); |
|
1661 return (-1); |
|
1662 } |
|
1663 |
|
1664 zcmd_free_nvlists(&zc); |
|
1665 |
|
1666 source_pair = nvlist_next_nvpair(nvlist, NULL); |
|
1667 |
|
1668 if (source_pair == NULL) { |
|
1669 *zfs_perms = NULL; |
|
1670 return (0); |
|
1671 } |
|
1672 |
|
1673 *zfs_perms = zfs_alloc_perm_tree(zhp, NULL, nvpair_name(source_pair)); |
|
1674 if (*zfs_perms == NULL) { |
|
1675 return (0); |
|
1676 } |
|
1677 |
|
1678 zallowp = *zfs_perms; |
|
1679 |
|
1680 for (;;) { |
|
1681 struct passwd *pwd; |
|
1682 struct group *grp; |
|
1683 zfs_allow_node_t *allownode; |
|
1684 zfs_allow_node_t findallownode; |
|
1685 zfs_allow_node_t *newallownode; |
|
1686 |
|
1687 (void) strlcpy(zallowp->z_setpoint, |
|
1688 nvpair_name(source_pair), |
|
1689 sizeof (zallowp->z_setpoint)); |
|
1690 |
|
1691 if ((error = nvpair_value_nvlist(source_pair, &sourcenv)) != 0) |
|
1692 goto abort; |
|
1693 |
|
1694 /* |
|
1695 * Make sure nvlist is composed correctly |
|
1696 */ |
|
1697 if (zfs_deleg_verify_nvlist(sourcenv)) { |
|
1698 goto abort; |
|
1699 } |
|
1700 |
|
1701 who_pair = nvlist_next_nvpair(sourcenv, NULL); |
|
1702 if (who_pair == NULL) { |
|
1703 goto abort; |
|
1704 } |
|
1705 |
|
1706 do { |
|
1707 error = nvpair_value_nvlist(who_pair, &permnv); |
|
1708 if (error) { |
|
1709 goto abort; |
|
1710 } |
|
1711 |
|
1712 /* |
|
1713 * First build up the key to use |
|
1714 * for looking up in the various |
|
1715 * who trees. |
|
1716 */ |
|
1717 ld = nvpair_name(who_pair)[1]; |
|
1718 nvpname = nvpair_name(who_pair); |
|
1719 switch (nvpair_name(who_pair)[0]) { |
|
1720 case ZFS_DELEG_USER: |
|
1721 case ZFS_DELEG_USER_SETS: |
|
1722 tree = &zallowp->z_user; |
|
1723 uid = atol(&nvpname[3]); |
|
1724 pwd = getpwuid(uid); |
|
1725 (void) snprintf(findallownode.z_key, |
|
1726 sizeof (findallownode.z_key), "user %s", |
|
1727 (pwd) ? pwd->pw_name : |
|
1728 &nvpair_name(who_pair)[3]); |
|
1729 break; |
|
1730 case ZFS_DELEG_GROUP: |
|
1731 case ZFS_DELEG_GROUP_SETS: |
|
1732 tree = &zallowp->z_group; |
|
1733 gid = atol(&nvpname[3]); |
|
1734 grp = getgrgid(gid); |
|
1735 (void) snprintf(findallownode.z_key, |
|
1736 sizeof (findallownode.z_key), "group %s", |
|
1737 (grp) ? grp->gr_name : |
|
1738 &nvpair_name(who_pair)[3]); |
|
1739 break; |
|
1740 case ZFS_DELEG_CREATE: |
|
1741 case ZFS_DELEG_CREATE_SETS: |
|
1742 tree = &zallowp->z_crperms; |
|
1743 (void) strlcpy(findallownode.z_key, "", |
|
1744 sizeof (findallownode.z_key)); |
|
1745 break; |
|
1746 case ZFS_DELEG_EVERYONE: |
|
1747 case ZFS_DELEG_EVERYONE_SETS: |
|
1748 (void) snprintf(findallownode.z_key, |
|
1749 sizeof (findallownode.z_key), "everyone"); |
|
1750 tree = &zallowp->z_everyone; |
|
1751 break; |
|
1752 case ZFS_DELEG_NAMED_SET: |
|
1753 case ZFS_DELEG_NAMED_SET_SETS: |
|
1754 (void) snprintf(findallownode.z_key, |
|
1755 sizeof (findallownode.z_key), "%s", |
|
1756 &nvpair_name(who_pair)[3]); |
|
1757 tree = &zallowp->z_sets; |
|
1758 break; |
|
1759 } |
|
1760 |
|
1761 /* |
|
1762 * Place who in tree |
|
1763 */ |
|
1764 allownode = avl_find(tree, &findallownode, &where); |
|
1765 if (allownode == NULL) { |
|
1766 if ((newallownode = zfs_alloc(zhp->zfs_hdl, |
|
1767 sizeof (zfs_allow_node_t))) == NULL) { |
|
1768 goto abort; |
|
1769 } |
|
1770 avl_create(&newallownode->z_localdescend, |
|
1771 perm_compare, |
|
1772 sizeof (zfs_perm_node_t), |
|
1773 offsetof(zfs_perm_node_t, z_node)); |
|
1774 avl_create(&newallownode->z_local, |
|
1775 perm_compare, |
|
1776 sizeof (zfs_perm_node_t), |
|
1777 offsetof(zfs_perm_node_t, z_node)); |
|
1778 avl_create(&newallownode->z_descend, |
|
1779 perm_compare, |
|
1780 sizeof (zfs_perm_node_t), |
|
1781 offsetof(zfs_perm_node_t, z_node)); |
|
1782 (void) strlcpy(newallownode->z_key, |
|
1783 findallownode.z_key, |
|
1784 sizeof (findallownode.z_key)); |
|
1785 avl_insert(tree, newallownode, where); |
|
1786 allownode = newallownode; |
|
1787 } |
|
1788 |
|
1789 /* |
|
1790 * Now iterate over the permissions and |
|
1791 * place them in the appropriate local, |
|
1792 * descendent or local+descendent tree. |
|
1793 * |
|
1794 * The permissions are added to the tree |
|
1795 * via zfs_coalesce_perm(). |
|
1796 */ |
|
1797 perm_pair = nvlist_next_nvpair(permnv, NULL); |
|
1798 if (perm_pair == NULL) |
|
1799 goto abort; |
|
1800 do { |
|
1801 if (zfs_coalesce_perm(zhp, allownode, |
|
1802 nvpair_name(perm_pair), ld) != 0) |
|
1803 goto abort; |
|
1804 } while (perm_pair = nvlist_next_nvpair(permnv, |
|
1805 perm_pair)); |
|
1806 } while (who_pair = nvlist_next_nvpair(sourcenv, who_pair)); |
|
1807 |
|
1808 source_pair = nvlist_next_nvpair(nvlist, source_pair); |
|
1809 if (source_pair == NULL) |
|
1810 break; |
|
1811 |
|
1812 /* |
|
1813 * allocate another node from the link list of |
|
1814 * zfs_allow_t structures |
|
1815 */ |
|
1816 newallowp = zfs_alloc_perm_tree(zhp, zallowp, |
|
1817 nvpair_name(source_pair)); |
|
1818 if (newallowp == NULL) { |
|
1819 goto abort; |
|
1820 } |
|
1821 zallowp = newallowp; |
|
1822 } |
|
1823 nvlist_free(nvlist); |
|
1824 return (0); |
|
1825 abort: |
|
1826 zfs_free_allows(*zfs_perms); |
|
1827 nvlist_free(nvlist); |
|
1828 return (-1); |
|
1829 } |
|
1830 |
|
1831 static char * |
|
1832 zfs_deleg_perm_note(zfs_deleg_note_t note) |
|
1833 { |
|
1834 /* |
|
1835 * Don't put newlines on end of lines |
|
1836 */ |
|
1837 switch (note) { |
|
1838 case ZFS_DELEG_NOTE_CREATE: |
|
1839 return (dgettext(TEXT_DOMAIN, |
|
1840 "Must also have the 'mount' ability")); |
|
1841 case ZFS_DELEG_NOTE_DESTROY: |
|
1842 return (dgettext(TEXT_DOMAIN, |
|
1843 "Must also have the 'mount' ability")); |
|
1844 case ZFS_DELEG_NOTE_SNAPSHOT: |
|
1845 return (dgettext(TEXT_DOMAIN, |
|
1846 "Must also have the 'mount' ability")); |
|
1847 case ZFS_DELEG_NOTE_ROLLBACK: |
|
1848 return (dgettext(TEXT_DOMAIN, |
|
1849 "Must also have the 'mount' ability")); |
|
1850 case ZFS_DELEG_NOTE_CLONE: |
|
1851 return (dgettext(TEXT_DOMAIN, "Must also have the 'create' " |
|
1852 "ability and 'mount'\n" |
|
1853 "\t\t\t\tability in the origin file system")); |
|
1854 case ZFS_DELEG_NOTE_PROMOTE: |
|
1855 return (dgettext(TEXT_DOMAIN, "Must also have the 'mount'\n" |
|
1856 "\t\t\t\tand 'promote' ability in the origin file system")); |
|
1857 case ZFS_DELEG_NOTE_RENAME: |
|
1858 return (dgettext(TEXT_DOMAIN, "Must also have the 'mount' " |
|
1859 "and 'create' \n\t\t\t\tability in the new parent")); |
|
1860 case ZFS_DELEG_NOTE_RECEIVE: |
|
1861 return (dgettext(TEXT_DOMAIN, "Must also have the 'mount'" |
|
1862 " and 'create' ability")); |
|
1863 case ZFS_DELEG_NOTE_USERPROP: |
|
1864 return (dgettext(TEXT_DOMAIN, |
|
1865 "Allows changing any user property")); |
|
1866 case ZFS_DELEG_NOTE_ALLOW: |
|
1867 return (dgettext(TEXT_DOMAIN, |
|
1868 "Must also have the permission that is being\n" |
|
1869 "\t\t\t\tallowed")); |
|
1870 case ZFS_DELEG_NOTE_MOUNT: |
|
1871 return (dgettext(TEXT_DOMAIN, |
|
1872 "Allows mount/umount of ZFS datasets")); |
|
1873 case ZFS_DELEG_NOTE_SHARE: |
|
1874 return (dgettext(TEXT_DOMAIN, |
|
1875 "Allows sharing file systems over NFS or SMB\n" |
|
1876 "\t\t\t\tprotocols")); |
|
1877 case ZFS_DELEG_NOTE_NONE: |
|
1878 default: |
|
1879 return (dgettext(TEXT_DOMAIN, "")); |
|
1880 } |
|
1881 } |
|
1882 |
|
1883 typedef enum { |
|
1884 ZFS_DELEG_SUBCOMMAND, |
|
1885 ZFS_DELEG_PROP, |
|
1886 ZFS_DELEG_OTHER |
|
1887 } zfs_deleg_perm_type_t; |
|
1888 |
|
1889 /* |
|
1890 * is the permission a subcommand or other? |
|
1891 */ |
|
1892 zfs_deleg_perm_type_t |
|
1893 zfs_deleg_perm_type(const char *perm) |
|
1894 { |
|
1895 if (strcmp(perm, "userprop") == 0) |
|
1896 return (ZFS_DELEG_OTHER); |
|
1897 else |
|
1898 return (ZFS_DELEG_SUBCOMMAND); |
|
1899 } |
|
1900 |
|
1901 static char * |
|
1902 zfs_deleg_perm_type_str(zfs_deleg_perm_type_t type) |
|
1903 { |
|
1904 switch (type) { |
|
1905 case ZFS_DELEG_SUBCOMMAND: |
|
1906 return (dgettext(TEXT_DOMAIN, "subcommand")); |
|
1907 case ZFS_DELEG_PROP: |
|
1908 return (dgettext(TEXT_DOMAIN, "property")); |
|
1909 case ZFS_DELEG_OTHER: |
|
1910 return (dgettext(TEXT_DOMAIN, "other")); |
|
1911 } |
|
1912 return (""); |
|
1913 } |
|
1914 |
|
1915 /*ARGSUSED*/ |
|
1916 static int |
|
1917 zfs_deleg_prop_cb(int prop, void *cb) |
|
1918 { |
|
1919 if (zfs_prop_delegatable(prop)) |
|
1920 (void) fprintf(stderr, "%-15s %-15s\n", zfs_prop_to_name(prop), |
|
1921 zfs_deleg_perm_type_str(ZFS_DELEG_PROP)); |
|
1922 |
|
1923 return (ZPROP_CONT); |
|
1924 } |
|
1925 |
|
1926 void |
|
1927 zfs_deleg_permissions(void) |
|
1928 { |
|
1929 int i; |
|
1930 |
|
1931 (void) fprintf(stderr, "\n%-15s %-15s\t%s\n\n", "NAME", |
|
1932 "TYPE", "NOTES"); |
|
1933 |
|
1934 /* |
|
1935 * First print out the subcommands |
|
1936 */ |
|
1937 for (i = 0; zfs_deleg_perm_tab[i].z_perm != NULL; i++) { |
|
1938 (void) fprintf(stderr, "%-15s %-15s\t%s\n", |
|
1939 zfs_deleg_perm_tab[i].z_perm, |
|
1940 zfs_deleg_perm_type_str( |
|
1941 zfs_deleg_perm_type(zfs_deleg_perm_tab[i].z_perm)), |
|
1942 zfs_deleg_perm_note(zfs_deleg_perm_tab[i].z_note)); |
|
1943 } |
|
1944 |
|
1945 (void) zprop_iter(zfs_deleg_prop_cb, NULL, B_FALSE, B_TRUE, |
|
1946 ZFS_TYPE_DATASET|ZFS_TYPE_VOLUME); |
|
1947 } |
|
1948 |
|
1949 /* |
1228 /* |
1950 * Given a property name and value, set the property for the given dataset. |
1229 * Given a property name and value, set the property for the given dataset. |
1951 */ |
1230 */ |
1952 int |
1231 int |
1953 zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) |
1232 zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) |
2744 if (get_numeric_property(zhp, prop, src, &source, value) != 0) |
2023 if (get_numeric_property(zhp, prop, src, &source, value) != 0) |
2745 return (-1); |
2024 return (-1); |
2746 |
2025 |
2747 get_source(zhp, src, source, statbuf, statlen); |
2026 get_source(zhp, src, source, statbuf, statlen); |
2748 |
2027 |
|
2028 return (0); |
|
2029 } |
|
2030 |
|
2031 static int |
|
2032 idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, |
|
2033 char **domainp, idmap_rid_t *ridp) |
|
2034 { |
|
2035 idmap_handle_t *idmap_hdl = NULL; |
|
2036 idmap_get_handle_t *get_hdl = NULL; |
|
2037 idmap_stat status; |
|
2038 int err = EINVAL; |
|
2039 |
|
2040 if (idmap_init(&idmap_hdl) != IDMAP_SUCCESS) |
|
2041 goto out; |
|
2042 if (idmap_get_create(idmap_hdl, &get_hdl) != IDMAP_SUCCESS) |
|
2043 goto out; |
|
2044 |
|
2045 if (isuser) { |
|
2046 err = idmap_get_sidbyuid(get_hdl, id, |
|
2047 IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); |
|
2048 } else { |
|
2049 err = idmap_get_sidbygid(get_hdl, id, |
|
2050 IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); |
|
2051 } |
|
2052 if (err == IDMAP_SUCCESS && |
|
2053 idmap_get_mappings(get_hdl) == IDMAP_SUCCESS && |
|
2054 status == IDMAP_SUCCESS) |
|
2055 err = 0; |
|
2056 else |
|
2057 err = EINVAL; |
|
2058 out: |
|
2059 if (get_hdl) |
|
2060 idmap_get_destroy(get_hdl); |
|
2061 if (idmap_hdl) |
|
2062 (void) idmap_fini(idmap_hdl); |
|
2063 return (err); |
|
2064 } |
|
2065 |
|
2066 /* |
|
2067 * convert the propname into parameters needed by kernel |
|
2068 * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 |
|
2069 * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 |
|
2070 */ |
|
2071 static int |
|
2072 userquota_propname_decode(const char *propname, boolean_t zoned, |
|
2073 zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp) |
|
2074 { |
|
2075 zfs_userquota_prop_t type; |
|
2076 char *cp, *end; |
|
2077 boolean_t isuser; |
|
2078 |
|
2079 domain[0] = '\0'; |
|
2080 |
|
2081 /* Figure out the property type ({user|group}{quota|space}) */ |
|
2082 for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { |
|
2083 if (strncmp(propname, zfs_userquota_prop_prefixes[type], |
|
2084 strlen(zfs_userquota_prop_prefixes[type])) == 0) |
|
2085 break; |
|
2086 } |
|
2087 if (type == ZFS_NUM_USERQUOTA_PROPS) |
|
2088 return (EINVAL); |
|
2089 *typep = type; |
|
2090 |
|
2091 isuser = (type == ZFS_PROP_USERQUOTA || |
|
2092 type == ZFS_PROP_USERUSED); |
|
2093 |
|
2094 cp = strchr(propname, '@') + 1; |
|
2095 |
|
2096 if (strchr(cp, '@')) { |
|
2097 /* |
|
2098 * It's a SID name (eg "user@domain") that needs to be |
|
2099 * turned into S-1-domainID-RID. There should be a |
|
2100 * better way to do this, but for now just translate it |
|
2101 * to the (possibly ephemeral) uid and then back to the |
|
2102 * SID. This is like getsidname(noresolve=TRUE). |
|
2103 */ |
|
2104 uid_t id; |
|
2105 idmap_rid_t rid; |
|
2106 char *mapdomain; |
|
2107 |
|
2108 if (zoned && getzoneid() == GLOBAL_ZONEID) |
|
2109 return (ENOENT); |
|
2110 if (sid_to_id(cp, isuser, &id) != 0) |
|
2111 return (ENOENT); |
|
2112 if (idmap_id_to_numeric_domain_rid(id, isuser, |
|
2113 &mapdomain, &rid) != 0) |
|
2114 return (ENOENT); |
|
2115 (void) strlcpy(domain, mapdomain, domainlen); |
|
2116 *ridp = rid; |
|
2117 } else if (strncmp(cp, "S-1-", 4) == 0) { |
|
2118 /* It's a numeric SID (eg "S-1-234-567-89") */ |
|
2119 (void) strcpy(domain, cp); |
|
2120 cp = strrchr(domain, '-'); |
|
2121 *cp = '\0'; |
|
2122 cp++; |
|
2123 |
|
2124 errno = 0; |
|
2125 *ridp = strtoull(cp, &end, 10); |
|
2126 if (errno == 0 || *end != '\0') |
|
2127 return (EINVAL); |
|
2128 } else if (!isdigit(*cp)) { |
|
2129 /* |
|
2130 * It's a user/group name (eg "user") that needs to be |
|
2131 * turned into a uid/gid |
|
2132 */ |
|
2133 if (zoned && getzoneid() == GLOBAL_ZONEID) |
|
2134 return (ENOENT); |
|
2135 if (isuser) { |
|
2136 struct passwd *pw; |
|
2137 pw = getpwnam(cp); |
|
2138 if (pw == NULL) |
|
2139 return (ENOENT); |
|
2140 *ridp = pw->pw_uid; |
|
2141 } else { |
|
2142 struct group *gr; |
|
2143 gr = getgrnam(cp); |
|
2144 if (gr == NULL) |
|
2145 return (ENOENT); |
|
2146 *ridp = gr->gr_gid; |
|
2147 } |
|
2148 } else { |
|
2149 /* It's a user/group ID (eg "12345"). */ |
|
2150 uid_t id = strtoul(cp, &end, 10); |
|
2151 idmap_rid_t rid; |
|
2152 char *mapdomain; |
|
2153 |
|
2154 if (*end != '\0') |
|
2155 return (EINVAL); |
|
2156 if (id > MAXUID) { |
|
2157 /* It's an ephemeral ID. */ |
|
2158 if (idmap_id_to_numeric_domain_rid(id, isuser, |
|
2159 &mapdomain, &rid) != 0) |
|
2160 return (ENOENT); |
|
2161 (void) strcpy(domain, mapdomain); |
|
2162 *ridp = rid; |
|
2163 } else { |
|
2164 *ridp = id; |
|
2165 } |
|
2166 } |
|
2167 |
|
2168 return (0); |
|
2169 } |
|
2170 |
|
2171 int |
|
2172 zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, |
|
2173 char *propbuf, int proplen, boolean_t literal) |
|
2174 { |
|
2175 int err; |
|
2176 zfs_cmd_t zc = { 0 }; |
|
2177 zfs_userquota_prop_t type; |
|
2178 |
|
2179 (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); |
|
2180 |
|
2181 err = userquota_propname_decode(propname, |
|
2182 zfs_prop_get_int(zhp, ZFS_PROP_ZONED), |
|
2183 &type, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); |
|
2184 zc.zc_objset_type = type; |
|
2185 if (err) |
|
2186 return (err); |
|
2187 |
|
2188 err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); |
|
2189 if (err) |
|
2190 return (err); |
|
2191 |
|
2192 if (literal) { |
|
2193 (void) snprintf(propbuf, proplen, "%llu", |
|
2194 (u_longlong_t)zc.zc_cookie); |
|
2195 } else if (zc.zc_cookie == 0 && |
|
2196 (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { |
|
2197 (void) strlcpy(propbuf, "none", proplen); |
|
2198 } else { |
|
2199 zfs_nicenum(zc.zc_cookie, propbuf, proplen); |
|
2200 } |
2749 return (0); |
2201 return (0); |
2750 } |
2202 } |
2751 |
2203 |
2752 /* |
2204 /* |
2753 * Returns the name of the given zfs handle. |
2205 * Returns the name of the given zfs handle. |