2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Net DFS server side RPC service for managing DFS namespaces.
2N/A *
2N/A * For more details refer to following Microsoft specification:
2N/A * [MS-DFSNM]
2N/A * Distributed File System (DFS): Namespace Management Protocol Specification
2N/A */
2N/A
2N/A#include <unistd.h>
2N/A#include <strings.h>
2N/A#include <sys/sysmacros.h>
2N/A
2N/A#include <smbsrv/libntsvcs.h>
2N/A#include <smb/nmpipes.h>
2N/A#include <smbsrv/ndl/netdfs.ndl>
2N/A#include <dfs.h>
2N/A
2N/A/*
2N/A * Depends on the information level requested around 4000 or more links
2N/A * can be provided with this buffer size. The limitation here is due
2N/A * to some problem in NDR and/or opipe layer so:
2N/A *
2N/A * - Do NOT increase the buffer size until that problem is fixed
2N/A * - The buffer size should be increased when the problem is fixed
2N/A * so the 4000 link limitation is removed.
2N/A */
2N/A#define NETDFS_MAXBUFLEN (800 * 1024)
2N/A#define NETDFS_MAXPREFLEN ((uint32_t)(-1))
2N/A
2N/Atypedef struct netdfs_enumhandle_t {
2N/A uint32_t de_level; /* level of detail being requested */
2N/A uint32_t de_prefmaxlen; /* client MAX size buffer preference */
2N/A uint32_t de_resume; /* client resume handle */
2N/A uint32_t de_bavail; /* remaining buffer space in bytes */
2N/A uint32_t de_ntotal; /* total number of objects */
2N/A uint32_t de_nmax; /* MAX number of objects to return */
2N/A uint32_t de_nitems; /* number of objects in buf */
2N/A uint32_t de_nskip; /* number of objects to skip */
2N/A void *de_entries; /* ndr buffer */
2N/A} netdfs_enumhandle_t;
2N/A
2N/Astatic int netdfs_s_getver(void *, ndr_xa_t *);
2N/Astatic int netdfs_s_add(void *, ndr_xa_t *);
2N/Astatic int netdfs_s_remove(void *, ndr_xa_t *);
2N/Astatic int netdfs_s_setinfo(void *, ndr_xa_t *);
2N/Astatic int netdfs_s_getinfo(void *, ndr_xa_t *);
2N/Astatic int netdfs_s_enum(void *, ndr_xa_t *);
2N/Astatic int netdfs_s_move(void *, ndr_xa_t *);
2N/Astatic int netdfs_s_rename(void *, ndr_xa_t *);
2N/Astatic int netdfs_s_addstdroot(void *, ndr_xa_t *);
2N/Astatic int netdfs_s_remstdroot(void *, ndr_xa_t *);
2N/Astatic int netdfs_s_enumex(void *, ndr_xa_t *);
2N/A
2N/Astatic uint32_t netdfs_setinfo_100(dfs_path_t *, netdfs_info100_t *);
2N/Astatic uint32_t netdfs_setinfo_101(dfs_path_t *, netdfs_info101_t *,
2N/A const char *, const char *);
2N/Astatic uint32_t netdfs_setinfo_102(dfs_path_t *, netdfs_info102_t *);
2N/Astatic uint32_t netdfs_setinfo_103(dfs_path_t *, netdfs_info103_t *);
2N/Astatic uint32_t netdfs_setinfo_104(dfs_path_t *, netdfs_info104_t *,
2N/A const char *, const char *);
2N/Astatic uint32_t netdfs_setinfo_105(dfs_path_t *, netdfs_info105_t *);
2N/A
2N/Astatic uint32_t netdfs_info_1(netdfs_info1_t *, dfs_info_t *, ndr_xa_t *,
2N/A uint32_t *);
2N/Astatic uint32_t netdfs_info_2(netdfs_info2_t *, dfs_info_t *, ndr_xa_t *,
2N/A uint32_t *);
2N/Astatic uint32_t netdfs_info_3(netdfs_info3_t *, dfs_info_t *, ndr_xa_t *,
2N/A uint32_t *);
2N/Astatic uint32_t netdfs_info_4(netdfs_info4_t *, dfs_info_t *, ndr_xa_t *,
2N/A uint32_t *);
2N/Astatic uint32_t netdfs_info_5(netdfs_info5_t *, dfs_info_t *, ndr_xa_t *,
2N/A uint32_t *);
2N/Astatic uint32_t netdfs_info_6(netdfs_info6_t *, dfs_info_t *, ndr_xa_t *,
2N/A uint32_t *);
2N/Astatic uint32_t netdfs_info_100(netdfs_info100_t *, dfs_info_t *, ndr_xa_t *,
2N/A uint32_t *);
2N/Astatic uint32_t netdfs_info_300(netdfs_info300_t *, dfs_info_t *, ndr_xa_t *,
2N/A uint32_t *);
2N/A
2N/Astatic uint32_t netdfs_enum_common(netdfs_enumhandle_t *, ndr_xa_t *);
2N/A
2N/Astatic boolean_t netdfs_guid_fromstr(char *, netdfs_uuid_t *);
2N/A
2N/Astatic ndr_stub_table_t netdfs_stub_table[] = {
2N/A { netdfs_s_getver, NETDFS_OPNUM_GETVER },
2N/A { netdfs_s_add, NETDFS_OPNUM_ADD },
2N/A { netdfs_s_remove, NETDFS_OPNUM_REMOVE },
2N/A { netdfs_s_setinfo, NETDFS_OPNUM_SETINFO },
2N/A { netdfs_s_getinfo, NETDFS_OPNUM_GETINFO },
2N/A { netdfs_s_enum, NETDFS_OPNUM_ENUM },
2N/A { netdfs_s_rename, NETDFS_OPNUM_RENAME },
2N/A { netdfs_s_move, NETDFS_OPNUM_MOVE },
2N/A { netdfs_s_addstdroot, NETDFS_OPNUM_ADDSTDROOT },
2N/A { netdfs_s_remstdroot, NETDFS_OPNUM_REMSTDROOT },
2N/A { netdfs_s_enumex, NETDFS_OPNUM_ENUMEX },
2N/A {0}
2N/A};
2N/A
2N/Astatic ndr_service_t netdfs_service = {
2N/A "NETDFS", /* name */
2N/A "DFS", /* desc */
2N/A "\\netdfs", /* endpoint */
2N/A PIPE_NETDFS, /* sec_addr_port */
2N/A NETDFS_ABSTRACT_UUID, NETDFS_ABSTRACT_VERS,
2N/A NETDFS_TRANSFER_UUID, NETDFS_TRANSFER_VERS,
2N/A
2N/A 0, /* no bind_instance_size */
2N/A 0, /* no bind_req() */
2N/A 0, /* no unbind_and_close() */
2N/A 0, /* use generic_call_stub() */
2N/A
2N/A &TYPEINFO(netdfs_interface), /* interface ti */
2N/A netdfs_stub_table /* stub_table */
2N/A};
2N/A
2N/A/*
2N/A * Register the NETDFS RPC interface with the RPC runtime library.
2N/A * The service must be registered in order to use either the client
2N/A * side or the server side functions.
2N/A */
2N/Avoid
2N/Anetdfs_initialize(void)
2N/A{
2N/A (void) ndr_svc_register(&netdfs_service);
2N/A dfs_init();
2N/A}
2N/A
2N/Avoid
2N/Anetdfs_finalize(void)
2N/A{
2N/A dfs_fini();
2N/A}
2N/A
2N/A/*
2N/A * Returns the version number of the DFS server in use on the server.
2N/A *
2N/A * [MS-DFSNM]: NetrDfsManagerGetVersion (Opnum 0)
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Anetdfs_s_getver(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A struct netdfs_getver *param = arg;
2N/A
2N/A param->version = DFS_MANAGER_VERSION_NT4;
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * Creates a new DFS link or adds a new target to an existing link of a
2N/A * DFS namespace.
2N/A *
2N/A * [MS-DFSNM]: NetrDfsAdd (Opnum 1)
2N/A */
2N/Astatic int
2N/Anetdfs_s_add(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A netdfs_add_t *param = arg;
2N/A dfs_path_t path;
2N/A uint32_t status;
2N/A const char *uncpath = (const char *)param->dfs_path;
2N/A
2N/A if (!ndr_is_admin(mxa)) {
2N/A param->status = ERROR_ACCESS_DENIED;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A if (param->server == NULL || param->share == NULL) {
2N/A param->status = ERROR_INVALID_PARAMETER;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A switch (param->flags) {
2N/A case DFS_CREATE_VOLUME:
2N/A case DFS_ADD_VOLUME:
2N/A case DFS_RESTORE_VOLUME:
2N/A case (DFS_ADD_VOLUME | DFS_RESTORE_VOLUME):
2N/A break;
2N/A default:
2N/A param->status = ERROR_INVALID_PARAMETER;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A status = dfs_path_parse(&path, uncpath, DFS_OBJECT_LINK, SMB_NS_DFS);
2N/A if (status != ERROR_SUCCESS) {
2N/A param->status = status;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A status = smb_name_validate_rpath(path.p_unc.unc_path);
2N/A if (status != ERROR_SUCCESS) {
2N/A dfs_path_free(&path);
2N/A param->status = status;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A dfs_setpriv(PRIV_ON);
2N/A
2N/A status = dfs_ns_addlink(path.p_unc.unc_share, &path,
2N/A (const char *)param->server, (const char *)param->share,
2N/A (const char *)param->comment, param->flags, SMB_NS_DFS);
2N/A
2N/A dfs_setpriv(PRIV_OFF);
2N/A
2N/A dfs_path_free(&path);
2N/A param->status = status;
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * Removes a link or a link target from a DFS namespace. A link can be
2N/A * removed regardless of the number of targets associated with it.
2N/A *
2N/A * [MS-DFSNM]: NetrDfsRemove (Opnum 2)
2N/A */
2N/Astatic int
2N/Anetdfs_s_remove(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A struct netdfs_remove *param = arg;
2N/A dfs_path_t path;
2N/A uint32_t status;
2N/A const char *uncpath = (const char *)param->dfs_path;
2N/A
2N/A if (!ndr_is_admin(mxa)) {
2N/A param->status = ERROR_ACCESS_DENIED;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A /* both server and share must be NULL or non-NULL */
2N/A if ((param->server == NULL && param->share != NULL) ||
2N/A (param->server != NULL && param->share == NULL)) {
2N/A param->status = ERROR_INVALID_PARAMETER;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A status = dfs_path_parse(&path, uncpath, DFS_OBJECT_LINK, SMB_NS_DFS);
2N/A if (status != ERROR_SUCCESS) {
2N/A param->status = status;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A dfs_setpriv(PRIV_ON);
2N/A
2N/A status = dfs_ns_removelink(path.p_unc.unc_share, &path,
2N/A (const char *)param->server, (const char *)param->share,
2N/A SMB_NS_DFS);
2N/A
2N/A dfs_setpriv(PRIV_OFF);
2N/A
2N/A dfs_path_free(&path);
2N/A param->status = status;
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * Sets or modifies information relevant to a specific DFS root, DFS root
2N/A * target, DFS link, or DFS link target
2N/A *
2N/A * [MS-DFSNM]: NetrDfsSetInfo (Opnum 3)
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Anetdfs_s_setinfo(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A netdfs_setinfo_t *param = arg;
2N/A dfs_path_t path;
2N/A uint32_t status, stat;
2N/A
2N/A /* both server and share must be NULL or non-NULL */
2N/A if ((param->server == NULL && param->share != NULL) ||
2N/A (param->server != NULL && param->share == NULL)) {
2N/A param->status = ERROR_INVALID_PARAMETER;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A status = dfs_path_parse(&path, (const char *)param->dfs_path,
2N/A DFS_OBJECT_ANY, SMB_NS_DFS);
2N/A
2N/A if (status != ERROR_SUCCESS) {
2N/A param->status = status;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A dfs_setpriv(PRIV_ON);
2N/A if (path.p_type == DFS_OBJECT_LINK) {
2N/A status = dfs_link_stat((const char *)path.p_fspath, &stat);
2N/A if ((status != ERROR_SUCCESS) || (stat != DFS_STAT_ISDFS)) {
2N/A dfs_setpriv(PRIV_OFF);
2N/A dfs_path_free(&path);
2N/A param->status = ERROR_NOT_FOUND;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A }
2N/A
2N/A switch (param->info.level) {
2N/A case 100:
2N/A status = netdfs_setinfo_100(&path, param->info.iu.info100);
2N/A break;
2N/A case 101:
2N/A status = netdfs_setinfo_101(&path, param->info.iu.info101,
2N/A (const char *)param->server, (const char *)param->share);
2N/A break;
2N/A case 102:
2N/A status = netdfs_setinfo_102(&path, param->info.iu.info102);
2N/A break;
2N/A case 103:
2N/A status = netdfs_setinfo_103(&path, param->info.iu.info103);
2N/A break;
2N/A case 104:
2N/A status = netdfs_setinfo_104(&path, param->info.iu.info104,
2N/A (const char *)param->server, (const char *)param->share);
2N/A break;
2N/A case 105:
2N/A status = netdfs_setinfo_105(&path, param->info.iu.info105);
2N/A break;
2N/A default:
2N/A status = ERROR_INVALID_LEVEL;
2N/A break;
2N/A }
2N/A
2N/A dfs_setpriv(PRIV_OFF);
2N/A dfs_path_free(&path);
2N/A param->status = status;
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * Returns information about a DFS root or a DFS link of the specified
2N/A * DFS namespace.
2N/A *
2N/A * [MS-DFSNM]: NetrDfsGetInfo (Opnum 4)
2N/A */
2N/Astatic int
2N/Anetdfs_s_getinfo(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A netdfs_getinfo_t *param = arg;
2N/A netdfs_info1_t *info1;
2N/A netdfs_info2_t *info2;
2N/A netdfs_info3_t *info3;
2N/A netdfs_info4_t *info4;
2N/A netdfs_info5_t *info5;
2N/A netdfs_info6_t *info6;
2N/A netdfs_info100_t *info100;
2N/A dfs_info_t info;
2N/A dfs_path_t path;
2N/A uint32_t status, stat;
2N/A const char *fspath;
2N/A uint32_t level = param->level;
2N/A
2N/A status = dfs_path_parse(&path, (const char *)param->dfs_path,
2N/A DFS_OBJECT_ANY, SMB_NS_DFS);
2N/A
2N/A if (status != ERROR_SUCCESS)
2N/A goto getinfo_error;
2N/A
2N/A dfs_setpriv(PRIV_ON);
2N/A
2N/A fspath = path.p_fspath;
2N/A if (path.p_type == DFS_OBJECT_LINK) {
2N/A status = dfs_link_stat(fspath, &stat);
2N/A if ((status != ERROR_SUCCESS) || (stat != DFS_STAT_ISDFS)) {
2N/A status = ERROR_NOT_FOUND;
2N/A goto getinfo_error;
2N/A }
2N/A
2N/A status = dfs_link_getinfo(fspath, &info, param->level,
2N/A SMB_NS_DFS);
2N/A } else {
2N/A status = dfs_root_getinfo(fspath, &info, param->level,
2N/A SMB_NS_DFS);
2N/A }
2N/A
2N/A if (status != ERROR_SUCCESS)
2N/A goto getinfo_error;
2N/A
2N/A (void) strlcpy(info.i_uncpath, (char *)param->dfs_path,
2N/A sizeof (info.i_uncpath));
2N/A
2N/A dfs_info_trace("netdfs_s_getinfo", &info);
2N/A
2N/A status = ERROR_NOT_ENOUGH_MEMORY;
2N/A
2N/A switch (level) {
2N/A case 1:
2N/A if ((info1 = NDR_NEW(mxa, netdfs_info1_t)) != NULL) {
2N/A param->info.iu.info1 = info1;
2N/A status = netdfs_info_1(info1, &info, mxa, NULL);
2N/A }
2N/A break;
2N/A case 2:
2N/A if ((info2 = NDR_NEW(mxa, netdfs_info2_t)) != NULL) {
2N/A param->info.iu.info2 = info2;
2N/A status = netdfs_info_2(info2, &info, mxa, NULL);
2N/A }
2N/A break;
2N/A case 3:
2N/A if ((info3 = NDR_NEW(mxa, netdfs_info3_t)) != NULL) {
2N/A param->info.iu.info3 = info3;
2N/A status = netdfs_info_3(info3, &info, mxa, NULL);
2N/A }
2N/A break;
2N/A case 4:
2N/A if ((info4 = NDR_NEW(mxa, netdfs_info4_t)) != NULL) {
2N/A param->info.iu.info4 = info4;
2N/A status = netdfs_info_4(info4, &info, mxa, NULL);
2N/A }
2N/A break;
2N/A case 5:
2N/A if ((info5 = NDR_NEW(mxa, netdfs_info5_t)) != NULL) {
2N/A param->info.iu.info5 = info5;
2N/A status = netdfs_info_5(info5, &info, mxa, NULL);
2N/A }
2N/A break;
2N/A case 6:
2N/A if ((info6 = NDR_NEW(mxa, netdfs_info6_t)) != NULL) {
2N/A param->info.iu.info6 = info6;
2N/A status = netdfs_info_6(info6, &info, mxa, NULL);
2N/A }
2N/A break;
2N/A case 100:
2N/A if ((info100 = NDR_NEW(mxa, netdfs_info100_t)) != NULL) {
2N/A param->info.iu.info100 = info100;
2N/A status = netdfs_info_100(info100, &info, mxa, NULL);
2N/A }
2N/A break;
2N/A
2N/A default:
2N/A status = ERROR_INVALID_LEVEL;
2N/A break;
2N/A }
2N/A
2N/A dfs_info_free(&info);
2N/A
2N/Agetinfo_error:
2N/A dfs_setpriv(PRIV_OFF);
2N/A dfs_path_free(&path);
2N/A if (status != ERROR_SUCCESS)
2N/A bzero(param, sizeof (netdfs_getinfo_t));
2N/A
2N/A param->info.level = level;
2N/A param->status = status;
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * Enumerates the DFS root hosted on a server or the DFS links of the
2N/A * namespace hosted by a server. Depending on the information level,
2N/A * the targets of the root and links are also displayed.
2N/A *
2N/A * For level 300, only one DFS root info is returned, no DFS links info.
2N/A * ERROR_DEVICE_NOT_AVAILABLE is returned if multiple namespaces are
2N/A * hosted by a server.
2N/A *
2N/A * For unsupported levels, it should return ERROR_INVALID_LEVEL as
2N/A * Microsoft does for DFS server on Win2000 and NT.
2N/A *
2N/A * [MS-DFSNM]: NetrDfsEnum (Opnum 5)
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Anetdfs_s_enum(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A netdfs_enum_t *param = arg;
2N/A netdfs_enumhandle_t de;
2N/A uint32_t level = param->level;
2N/A uint32_t status = ERROR_SUCCESS;
2N/A uint32_t nroot;
2N/A size_t entsize;
2N/A
2N/A dfs_ns_hold(NULL);
2N/A
2N/A if (param->info == NULL) {
2N/A status = ERROR_INVALID_PARAMETER;
2N/A goto enum_error;
2N/A }
2N/A
2N/A if (!dfs_ns_exists(SMB_NS_DFS)) {
2N/A status = ERROR_NOT_FOUND;
2N/A goto enum_error;
2N/A }
2N/A
2N/A if ((nroot = dfs_ns_count()) == 0)
2N/A status = ERROR_NOT_FOUND;
2N/A else if (nroot > 1)
2N/A status = ERROR_DEVICE_NOT_AVAILABLE;
2N/A
2N/A if (status != ERROR_SUCCESS)
2N/A goto enum_error;
2N/A
2N/A bzero(&de, sizeof (netdfs_enumhandle_t));
2N/A de.de_level = level;
2N/A de.de_ntotal = dfs_ns_numlink(NULL);
2N/A if (de.de_ntotal == 0) {
2N/A status = ERROR_NOT_FOUND;
2N/A goto enum_error;
2N/A }
2N/A
2N/A if (param->pref_max_len == NETDFS_MAXPREFLEN ||
2N/A param->pref_max_len > NETDFS_MAXBUFLEN)
2N/A de.de_prefmaxlen = NETDFS_MAXBUFLEN;
2N/A else
2N/A de.de_prefmaxlen = param->pref_max_len;
2N/A
2N/A de.de_bavail = de.de_prefmaxlen;
2N/A
2N/A if (param->resume_handle != NULL) {
2N/A if (*param->resume_handle >= de.de_ntotal ||
2N/A (level == 300 && *param->resume_handle == 1)) {
2N/A status = ERROR_NO_MORE_ITEMS;
2N/A goto enum_error;
2N/A }
2N/A de.de_resume = *param->resume_handle;
2N/A de.de_nskip = de.de_resume;
2N/A *param->resume_handle = 0;
2N/A }
2N/A
2N/A dfs_setpriv(PRIV_ON);
2N/A
2N/A status = ERROR_NOT_ENOUGH_MEMORY;
2N/A
2N/A switch (level) {
2N/A case 1:
2N/A entsize = sizeof (netdfs_info1_t);
2N/A de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
2N/A de.de_entries = NDR_NEWN(mxa, netdfs_info1_t, de.de_nmax);
2N/A if (de.de_entries == NULL)
2N/A goto enum_error;
2N/A
2N/A if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
2N/A param->info->iu.info1->info1 = de.de_entries;
2N/A param->info->iu.info1->count = de.de_nitems;
2N/A }
2N/A break;
2N/A case 2:
2N/A entsize = sizeof (netdfs_info2_t);
2N/A de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
2N/A de.de_entries = NDR_NEWN(mxa, netdfs_info2_t, de.de_nmax);
2N/A if (de.de_entries == NULL)
2N/A goto enum_error;
2N/A
2N/A if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
2N/A param->info->iu.info2->info2 = de.de_entries;
2N/A param->info->iu.info2->count = de.de_nitems;
2N/A }
2N/A break;
2N/A case 3:
2N/A entsize = sizeof (netdfs_info3_t) +
2N/A sizeof (netdfs_storage_info_t);
2N/A de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
2N/A de.de_entries = NDR_NEWN(mxa, netdfs_info3_t, de.de_nmax);
2N/A if (de.de_entries == NULL)
2N/A goto enum_error;
2N/A
2N/A if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
2N/A param->info->iu.info3->info3 = de.de_entries;
2N/A param->info->iu.info3->count = de.de_nitems;
2N/A }
2N/A break;
2N/A case 4:
2N/A entsize = sizeof (netdfs_info4_t) +
2N/A sizeof (netdfs_storage_info_t);
2N/A de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
2N/A de.de_entries = NDR_NEWN(mxa, netdfs_info4_t, de.de_nmax);
2N/A if (de.de_entries == NULL)
2N/A goto enum_error;
2N/A
2N/A if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
2N/A param->info->iu.info4->info4 = de.de_entries;
2N/A param->info->iu.info4->count = de.de_nitems;
2N/A }
2N/A break;
2N/A
2N/A case 5:
2N/A entsize = sizeof (netdfs_info5_t);
2N/A de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
2N/A de.de_entries = NDR_NEWN(mxa, netdfs_info5_t, de.de_nmax);
2N/A if (de.de_entries == NULL)
2N/A goto enum_error;
2N/A
2N/A if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
2N/A param->info->iu.info5->info5 = de.de_entries;
2N/A param->info->iu.info5->count = de.de_nitems;
2N/A }
2N/A break;
2N/A
2N/A case 6:
2N/A entsize = sizeof (netdfs_info6_t) +
2N/A sizeof (netdfs_storage_info1_t);
2N/A de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1);
2N/A de.de_entries = NDR_NEWN(mxa, netdfs_info6_t, de.de_nmax);
2N/A if (de.de_entries == NULL)
2N/A goto enum_error;
2N/A
2N/A if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
2N/A param->info->iu.info6->info6 = de.de_entries;
2N/A param->info->iu.info6->count = de.de_nitems;
2N/A }
2N/A break;
2N/A
2N/A case 300:
2N/A entsize = sizeof (netdfs_info300_t);
2N/A de.de_nmax = 1;
2N/A de.de_entries = NDR_NEWN(mxa, netdfs_info300_t, de.de_nmax);
2N/A if (de.de_entries == NULL)
2N/A goto enum_error;
2N/A
2N/A if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) {
2N/A param->info->iu.info300->info300 = de.de_entries;
2N/A param->info->iu.info300->count = de.de_nitems;
2N/A }
2N/A break;
2N/A
2N/A default:
2N/A status = ERROR_INVALID_PARAMETER;
2N/A break;
2N/A }
2N/A
2N/A if ((status == ERROR_SUCCESS) && (param->resume_handle != NULL))
2N/A *param->resume_handle = de.de_resume;
2N/A
2N/Aenum_error:
2N/A dfs_ns_rele(NULL);
2N/A dfs_setpriv(PRIV_OFF);
2N/A param->status = status;
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * Renames or moves a DFS link
2N/A *
2N/A * Does not need to be supported for DFS version 1
2N/A *
2N/A * [MS-DFSNM]: NetrDfsMove (Opnum 6)
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Anetdfs_s_move(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A struct netdfs_move *param = arg;
2N/A
2N/A param->status = ERROR_NOT_SUPPORTED;
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * According to [MS-DFSNM] spec this operation (opnum 7) is not
2N/A * used over the wire.
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Anetdfs_s_rename(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A struct netdfs_rename *param = arg;
2N/A
2N/A param->status = ERROR_NOT_SUPPORTED;
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * Creates a new standalone DFS namespace
2N/A *
2N/A * [MS-DFSNM]: NetrDfsAddStdRoot (Opnum 12)
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Anetdfs_s_addstdroot(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A struct netdfs_addstdroot *param = arg;
2N/A const char *share = (const char *)param->share;
2N/A const char *comment = (const char *)param->comment;
2N/A
2N/A if (!ndr_is_admin(mxa)) {
2N/A param->status = ERROR_ACCESS_DENIED;
2N/A return (NDR_DRC_OK);
2N/A }
2N/A
2N/A dfs_setpriv(PRIV_ON);
2N/A param->status = dfs_ns_create(share, comment, SMB_NS_DFS);
2N/A dfs_setpriv(PRIV_OFF);
2N/A
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * Deletes the specified stand-alone DFS namespace. The DFS namespace can be
2N/A * removed without first removing all of the links in it.
2N/A *
2N/A * [MS-DFSNM]: NetrDfsRemoveStdRoot (Opnum 13)
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Anetdfs_s_remstdroot(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A struct netdfs_remstdroot *param = arg;
2N/A const char *share = (const char *)param->share;
2N/A
2N/A dfs_setpriv(PRIV_ON);
2N/A
2N/A if (ndr_is_admin(mxa))
2N/A param->status = dfs_ns_destroy(share, SMB_NS_DFS);
2N/A else
2N/A param->status = ERROR_ACCESS_DENIED;
2N/A
2N/A dfs_setpriv(PRIV_OFF);
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * Enumerates the DFS roots hosted on a server, or DFS links of a namespace
2N/A * hosted by the server. Depending on the information level, the targets
2N/A * associated with the roots and links are also displayed
2N/A *
2N/A * Does not need to be supported for DFS version 1
2N/A *
2N/A * [MS-DFSNM] NetrDfsEnumEx (Opnum 21)
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Anetdfs_s_enumex(void *arg, ndr_xa_t *mxa)
2N/A{
2N/A struct netdfs_enumex *param = arg;
2N/A
2N/A bzero(param->info, sizeof (struct netdfs_enumex));
2N/A param->status = ERROR_NOT_SUPPORTED;
2N/A return (NDR_DRC_OK);
2N/A}
2N/A
2N/A/*
2N/A * Sets the comment for the DFS link/root.
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_setinfo_100(dfs_path_t *path, netdfs_info100_t *netinfo)
2N/A{
2N/A dfs_info_t info;
2N/A uint32_t status;
2N/A char *cmnt = (char *)netinfo->comment;
2N/A
2N/A bzero(&info, sizeof (dfs_info_t));
2N/A if (cmnt != NULL)
2N/A (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment));
2N/A
2N/A if (path->p_type == DFS_OBJECT_LINK)
2N/A status = dfs_link_setinfo(path->p_fspath, &info, 100,
2N/A SMB_NS_DFS);
2N/A else
2N/A status = dfs_root_setinfo(path->p_fspath, &info, 100,
2N/A SMB_NS_DFS);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Sets the state for the DFS root/link or its target.
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_setinfo_101(dfs_path_t *path, netdfs_info101_t *netinfo,
2N/A const char *t_server, const char *t_share)
2N/A{
2N/A dfs_info_t info;
2N/A dfs_target_t target;
2N/A uint32_t status;
2N/A
2N/A bzero(&info, sizeof (dfs_info_t));
2N/A bzero(&target, sizeof (dfs_target_t));
2N/A
2N/A if (t_server == NULL && t_share == NULL) {
2N/A info.i_state = netinfo->state;
2N/A } else {
2N/A target.t_state = netinfo->state;
2N/A (void) strlcpy(target.t_server, t_server,
2N/A sizeof (target.t_server));
2N/A (void) strlcpy(target.t_share, t_share,
2N/A sizeof (target.t_share));
2N/A info.i_targets = &target;
2N/A }
2N/A
2N/A if (path->p_type == DFS_OBJECT_LINK)
2N/A status = dfs_link_setinfo(path->p_fspath, &info, 101,
2N/A SMB_NS_DFS);
2N/A else
2N/A status = dfs_root_setinfo(path->p_fspath, &info, 101,
2N/A SMB_NS_DFS);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Sets the timeout value of the DFS link/root.
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_setinfo_102(dfs_path_t *path, netdfs_info102_t *netinfo)
2N/A{
2N/A dfs_info_t info;
2N/A uint32_t status;
2N/A
2N/A bzero(&info, sizeof (dfs_info_t));
2N/A info.i_timeout = netinfo->timeout;
2N/A
2N/A if (path->p_type == DFS_OBJECT_LINK)
2N/A status = dfs_link_setinfo(path->p_fspath, &info, 102,
2N/A SMB_NS_DFS);
2N/A else
2N/A status = dfs_root_setinfo(path->p_fspath, &info, 102,
2N/A SMB_NS_DFS);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Sets the property flags for the root or link.
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_setinfo_103(dfs_path_t *path, netdfs_info103_t *netinfo)
2N/A{
2N/A dfs_info_t info;
2N/A uint32_t status;
2N/A
2N/A bzero(&info, sizeof (dfs_info_t));
2N/A info.i_propflags =
2N/A netinfo->property_flags & netinfo->property_flag_mask;
2N/A
2N/A if (path->p_type == DFS_OBJECT_LINK)
2N/A status = dfs_link_setinfo(path->p_fspath, &info, 103,
2N/A SMB_NS_DFS);
2N/A else
2N/A status = dfs_root_setinfo(path->p_fspath, &info, 103,
2N/A SMB_NS_DFS);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Sets the target priority rank and class for the root target or link target
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_setinfo_104(dfs_path_t *path, netdfs_info104_t *netinfo,
2N/A const char *t_server, const char *t_share)
2N/A{
2N/A dfs_info_t info;
2N/A dfs_target_t target;
2N/A uint32_t status;
2N/A
2N/A if ((t_server == NULL) || (t_share == NULL))
2N/A return (ERROR_INVALID_PARAMETER);
2N/A
2N/A if (netinfo->priority_class > DfsGlobalLowPriorityClass)
2N/A return (ERROR_INVALID_PARAMETER);
2N/A
2N/A if (netinfo->priority_rank > DFS_PRIORITY_RANK_MAX)
2N/A return (ERROR_INVALID_PARAMETER);
2N/A
2N/A bzero(&info, sizeof (dfs_info_t));
2N/A bzero(&target, sizeof (dfs_target_t));
2N/A
2N/A target.t_priority.p_class = netinfo->priority_class;
2N/A target.t_priority.p_rank = netinfo->priority_rank;
2N/A (void) strlcpy(target.t_server, t_server, sizeof (target.t_server));
2N/A (void) strlcpy(target.t_share, t_share, sizeof (target.t_share));
2N/A info.i_targets = &target;
2N/A
2N/A if (path->p_type == DFS_OBJECT_LINK)
2N/A status = dfs_link_setinfo(path->p_fspath, &info, 104,
2N/A SMB_NS_DFS);
2N/A else
2N/A status = dfs_root_setinfo(path->p_fspath, &info, 104,
2N/A SMB_NS_DFS);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Sets the comment, state, time-out information, and property flags for the
2N/A * namespace root or link specified in DfsInfo. Does not apply to a root target
2N/A * or link target.
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_setinfo_105(dfs_path_t *path, netdfs_info105_t *netinfo)
2N/A{
2N/A dfs_info_t info;
2N/A uint32_t status, flavor;
2N/A char *cmnt = (char *)netinfo->comment;
2N/A
2N/A bzero(&info, sizeof (dfs_info_t));
2N/A
2N/A flavor = dfs_ns_getflavor(path->p_unc.unc_share, SMB_NS_DFS);
2N/A if (flavor == 0)
2N/A return (ERROR_INTERNAL_ERROR);
2N/A info.i_flavor = flavor;
2N/A
2N/A if (cmnt != NULL)
2N/A (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment));
2N/A info.i_state = netinfo->state;
2N/A info.i_timeout = netinfo->timeout;
2N/A info.i_propflag_mask = netinfo->property_flag_mask;
2N/A info.i_propflags =
2N/A netinfo->property_flags & netinfo->property_flag_mask;
2N/A
2N/A if (path->p_type == DFS_OBJECT_LINK)
2N/A status = dfs_link_setinfo(path->p_fspath, &info, 105,
2N/A SMB_NS_DFS);
2N/A else
2N/A status = dfs_root_setinfo(path->p_fspath, &info, 105,
2N/A SMB_NS_DFS);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * DFS_STORAGE_INFO: target information
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_info_storage(netdfs_storage_info_t **sinfo, dfs_info_t *info,
2N/A ndr_xa_t *mxa, uint32_t *size)
2N/A{
2N/A netdfs_storage_info_t *storage;
2N/A dfs_target_t *target;
2N/A int i;
2N/A
2N/A *sinfo = NULL;
2N/A if (info->i_ntargets == 0)
2N/A return (ERROR_SUCCESS);
2N/A
2N/A *sinfo = NDR_NEWN(mxa, netdfs_storage_info_t, info->i_ntargets);
2N/A if (*sinfo == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if (size != NULL)
2N/A *size += info->i_ntargets * sizeof (netdfs_storage_info_t);
2N/A
2N/A target = info->i_targets;
2N/A storage = *sinfo;
2N/A for (i = 0; i < info->i_ntargets; i++, target++, storage++) {
2N/A storage->state = target->t_state;
2N/A storage->server = NDR_STRDUP(mxa, target->t_server);
2N/A storage->share = NDR_STRDUP(mxa, target->t_share);
2N/A
2N/A if (storage->server == NULL || storage->share == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if (size != NULL)
2N/A *size += smb_wcequiv_strlen(target->t_server) +
2N/A smb_wcequiv_strlen(target->t_share);
2N/A }
2N/A
2N/A return (ERROR_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * DFS_STORAGE_INFO_1: target information
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_info_storage1(netdfs_storage_info1_t **sinfo, dfs_info_t *info,
2N/A ndr_xa_t *mxa, uint32_t *size)
2N/A{
2N/A netdfs_storage_info1_t *storage;
2N/A dfs_target_t *target;
2N/A int i;
2N/A
2N/A *sinfo = NULL;
2N/A if (info->i_ntargets == 0)
2N/A return (ERROR_SUCCESS);
2N/A
2N/A *sinfo = NDR_NEWN(mxa, netdfs_storage_info1_t, info->i_ntargets);
2N/A if (*sinfo == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if (size != NULL)
2N/A *size += info->i_ntargets * sizeof (netdfs_storage_info1_t);
2N/A
2N/A target = info->i_targets;
2N/A storage = *sinfo;
2N/A for (i = 0; i < info->i_ntargets; i++, target++, storage++) {
2N/A storage->state = target->t_state;
2N/A storage->server = NDR_STRDUP(mxa, target->t_server);
2N/A storage->share = NDR_STRDUP(mxa, target->t_share);
2N/A storage->p_class = target->t_priority.p_class;
2N/A storage->p_rank = target->t_priority.p_rank;
2N/A storage->p_reserved = 0;
2N/A
2N/A if (storage->server == NULL || storage->share == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if (size != NULL)
2N/A *size += smb_wcequiv_strlen(target->t_server) +
2N/A smb_wcequiv_strlen(target->t_share);
2N/A }
2N/A
2N/A return (ERROR_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Sets a DFS_INFO_1 for get/enum response
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_info_1(netdfs_info1_t *info1, dfs_info_t *info, ndr_xa_t *mxa,
2N/A uint32_t *size)
2N/A{
2N/A info1->entry_path = NDR_STRDUP(mxa, info->i_uncpath);
2N/A if (info1->entry_path == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if (size != NULL)
2N/A *size = sizeof (netdfs_info1_t) +
2N/A smb_wcequiv_strlen(info->i_uncpath);
2N/A
2N/A return (ERROR_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Sets a DFS_INFO_2 for get/enum response
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_info_2(netdfs_info2_t *info2, dfs_info_t *info, ndr_xa_t *mxa,
2N/A uint32_t *size)
2N/A{
2N/A void *entry_path;
2N/A void *comment;
2N/A
2N/A entry_path = NDR_STRDUP(mxa, info->i_uncpath);
2N/A comment = NDR_STRDUP(mxa, info->i_comment);
2N/A
2N/A if (entry_path == NULL || comment == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A info2->entry_path = entry_path;
2N/A info2->comment = comment;
2N/A info2->state = info->i_state;
2N/A info2->n_store = info->i_ntargets;
2N/A
2N/A if (size != NULL)
2N/A *size = sizeof (netdfs_info2_t) +
2N/A smb_wcequiv_strlen(info->i_uncpath) +
2N/A smb_wcequiv_strlen(info->i_comment);
2N/A
2N/A return (ERROR_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Sets a DFS_INFO_3 for get/enum response
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_info_3(netdfs_info3_t *info3, dfs_info_t *info, ndr_xa_t *mxa,
2N/A uint32_t *size)
2N/A{
2N/A void *entry_path;
2N/A void *comment;
2N/A
2N/A entry_path = NDR_STRDUP(mxa, info->i_uncpath);
2N/A comment = NDR_STRDUP(mxa, info->i_comment);
2N/A
2N/A if (entry_path == NULL || comment == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A info3->entry_path = entry_path;
2N/A info3->comment = comment;
2N/A info3->state = info->i_state;
2N/A info3->n_store = info->i_ntargets;
2N/A
2N/A if (size != NULL)
2N/A *size = sizeof (netdfs_info3_t) +
2N/A smb_wcequiv_strlen(info->i_uncpath) +
2N/A smb_wcequiv_strlen(info->i_comment);
2N/A
2N/A return (netdfs_info_storage(&info3->si, info, mxa, size));
2N/A}
2N/A
2N/A/*
2N/A * Sets a DFS_INFO_4 for get/enum response
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_info_4(netdfs_info4_t *info4, dfs_info_t *info, ndr_xa_t *mxa,
2N/A uint32_t *size)
2N/A{
2N/A void *entry_path;
2N/A void *comment;
2N/A
2N/A entry_path = NDR_STRDUP(mxa, info->i_uncpath);
2N/A comment = NDR_STRDUP(mxa, info->i_comment);
2N/A
2N/A if (entry_path == NULL || comment == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if (!netdfs_guid_fromstr(info->i_guid, &info4->guid))
2N/A return (ERROR_INVALID_DATA);
2N/A
2N/A info4->entry_path = entry_path;
2N/A info4->comment = comment;
2N/A info4->state = info->i_state;
2N/A info4->timeout = info->i_timeout;
2N/A info4->n_store = info->i_ntargets;
2N/A
2N/A if (size != NULL)
2N/A *size = sizeof (netdfs_info4_t) +
2N/A smb_wcequiv_strlen(info->i_uncpath) +
2N/A smb_wcequiv_strlen(info->i_comment);
2N/A
2N/A return (netdfs_info_storage(&info4->si, info, mxa, size));
2N/A}
2N/A
2N/A/*
2N/A * Sets a DFS_INFO_5 for get/enum response
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_info_5(netdfs_info5_t *info5, dfs_info_t *info, ndr_xa_t *mxa,
2N/A uint32_t *size)
2N/A{
2N/A void *entry_path;
2N/A void *comment;
2N/A
2N/A entry_path = NDR_STRDUP(mxa, info->i_uncpath);
2N/A comment = NDR_STRDUP(mxa, info->i_comment);
2N/A
2N/A if (entry_path == NULL || comment == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if (!netdfs_guid_fromstr(info->i_guid, &info5->guid))
2N/A return (ERROR_INVALID_DATA);
2N/A
2N/A info5->entry_path = entry_path;
2N/A info5->comment = comment;
2N/A info5->state = info->i_state;
2N/A info5->timeout = info->i_timeout;
2N/A info5->flags = info->i_propflags;
2N/A info5->metadata_sz = 0;
2N/A info5->n_store = info->i_ntargets;
2N/A
2N/A if (size != NULL)
2N/A *size = sizeof (netdfs_info5_t) +
2N/A smb_wcequiv_strlen(info->i_uncpath) +
2N/A smb_wcequiv_strlen(info->i_comment);
2N/A
2N/A return (ERROR_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Sets a DFS_INFO_6 for get/enum response
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_info_6(netdfs_info6_t *info6, dfs_info_t *info, ndr_xa_t *mxa,
2N/A uint32_t *size)
2N/A{
2N/A void *entry_path;
2N/A void *comment;
2N/A
2N/A entry_path = NDR_STRDUP(mxa, info->i_uncpath);
2N/A comment = NDR_STRDUP(mxa, info->i_comment);
2N/A
2N/A if (entry_path == NULL || comment == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if (!netdfs_guid_fromstr(info->i_guid, &info6->guid))
2N/A return (ERROR_INVALID_DATA);
2N/A
2N/A info6->entry_path = entry_path;
2N/A info6->comment = comment;
2N/A info6->state = info->i_state;
2N/A info6->timeout = info->i_timeout;
2N/A info6->flags = info->i_propflags;
2N/A info6->metadata_sz = 0;
2N/A info6->n_store = info->i_ntargets;
2N/A
2N/A if (size != NULL)
2N/A *size = sizeof (netdfs_info6_t) +
2N/A smb_wcequiv_strlen(info->i_uncpath) +
2N/A smb_wcequiv_strlen(info->i_comment);
2N/A
2N/A return (netdfs_info_storage1(&info6->si, info, mxa, size));
2N/A}
2N/A
2N/A/*
2N/A * Sets a DFS_INFO_100 for Get response
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_info_100(netdfs_info100_t *info100, dfs_info_t *info, ndr_xa_t *mxa,
2N/A uint32_t *size)
2N/A{
2N/A info100->comment = NDR_STRDUP(mxa, info->i_comment);
2N/A if (info100->comment == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A if (size != NULL)
2N/A *size = sizeof (netdfs_info100_t) +
2N/A smb_wcequiv_strlen(info->i_comment);
2N/A
2N/A return (ERROR_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Sets a DFS_INFO_300 for Enum response
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_info_300(netdfs_info300_t *info300, dfs_info_t *info, ndr_xa_t *mxa,
2N/A uint32_t *size)
2N/A{
2N/A info300->dfsname = NDR_STRDUP(mxa, info->i_uncpath);
2N/A if (info300->dfsname == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A info300->flavor = DFS_VOLUME_FLAVOR_STANDALONE;
2N/A if (size != NULL)
2N/A *size = sizeof (netdfs_info300_t) +
2N/A smb_wcequiv_strlen(info->i_uncpath);
2N/A
2N/A return (ERROR_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Common enumeration function.
2N/A * Caller must be holding namespace lock (dfs_ns_hold)
2N/A */
2N/Astatic uint32_t
2N/Anetdfs_enum_common(netdfs_enumhandle_t *de, ndr_xa_t *mxa)
2N/A{
2N/A netdfs_info1_t *info1 = de->de_entries;
2N/A netdfs_info2_t *info2 = de->de_entries;
2N/A netdfs_info3_t *info3 = de->de_entries;
2N/A netdfs_info4_t *info4 = de->de_entries;
2N/A netdfs_info5_t *info5 = de->de_entries;
2N/A netdfs_info6_t *info6 = de->de_entries;
2N/A netdfs_info300_t *info300 = de->de_entries;
2N/A dfs_info_t dfsinfo;
2N/A dfs_node_t *dn;
2N/A uint32_t status;
2N/A uint32_t itemsz;
2N/A
2N/A de->de_nitems = 0;
2N/A if ((dn = dfs_ns_firstlink(NULL)) == NULL)
2N/A return (ERROR_SUCCESS);
2N/A
2N/A do {
2N/A if (de->de_level == 300 && dn->dn_type != DFS_OBJECT_ROOT)
2N/A continue;
2N/A
2N/A if (de->de_nskip > 0) {
2N/A de->de_nskip--;
2N/A continue;
2N/A }
2N/A
2N/A if (de->de_nitems == de->de_nmax)
2N/A break;
2N/A
2N/A status = dfs_getinfo(dn, &dfsinfo, de->de_level, SMB_NS_DFS);
2N/A if (status != ERROR_SUCCESS)
2N/A continue;
2N/A
2N/A switch (de->de_level) {
2N/A case 1:
2N/A status = netdfs_info_1(info1, &dfsinfo, mxa, &itemsz);
2N/A info1++;
2N/A break;
2N/A case 2:
2N/A status = netdfs_info_2(info2, &dfsinfo, mxa, &itemsz);
2N/A info2++;
2N/A break;
2N/A case 3:
2N/A status = netdfs_info_3(info3, &dfsinfo, mxa, &itemsz);
2N/A info3++;
2N/A break;
2N/A case 4:
2N/A status = netdfs_info_4(info4, &dfsinfo, mxa, &itemsz);
2N/A info4++;
2N/A break;
2N/A case 5:
2N/A status = netdfs_info_5(info5, &dfsinfo, mxa, &itemsz);
2N/A info5++;
2N/A break;
2N/A case 6:
2N/A status = netdfs_info_6(info6, &dfsinfo, mxa, &itemsz);
2N/A info6++;
2N/A break;
2N/A case 300:
2N/A status = netdfs_info_300(info300, &dfsinfo, mxa,
2N/A &itemsz);
2N/A info300++;
2N/A break;
2N/A default:
2N/A status = ERROR_INVALID_LEVEL;
2N/A }
2N/A
2N/A dfs_info_free(&dfsinfo);
2N/A
2N/A if (status != ERROR_SUCCESS)
2N/A return (status);
2N/A
2N/A if (de->de_nmax == 1) {
2N/A de->de_nitems = 1;
2N/A break;
2N/A }
2N/A
2N/A if (itemsz > de->de_bavail)
2N/A break;
2N/A
2N/A de->de_bavail -= itemsz;
2N/A de->de_nitems++;
2N/A } while ((dn = dfs_ns_nextlink(NULL, dn)) != NULL);
2N/A
2N/A de->de_resume += de->de_nitems;
2N/A
2N/A return (ERROR_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Converts the guid string into binary format in network byte order.
2N/A */
2N/Astatic boolean_t
2N/Anetdfs_guid_fromstr(char *guid_str, netdfs_uuid_t *guid)
2N/A{
2N/A uuid_t uuid;
2N/A
2N/A if (uuid_parse(guid_str, uuid) != 0)
2N/A return (B_FALSE);
2N/A
2N/A bcopy(&uuid, guid, sizeof (uuid_t));
2N/A
2N/A guid->data1 = htonl(guid->data1);
2N/A guid->data2 = htons(guid->data2);
2N/A guid->data3 = htons(guid->data3);
2N/A
2N/A return (B_TRUE);
2N/A}