15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 22*8334SJose.Borrego@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw /* 275331Samw * Net DFS server side RPC service. 285331Samw */ 295331Samw 305331Samw #include <sys/types.h> 315331Samw #include <strings.h> 325331Samw #include <string.h> 335331Samw 345331Samw #include <smbsrv/libsmb.h> 355331Samw #include <smbsrv/lmerr.h> 365331Samw #include <smbsrv/lmdfs.h> 375331Samw #include <smbsrv/nmpipes.h> 385331Samw #include <smbsrv/nterror.h> 39*8334SJose.Borrego@Sun.COM #include <smbsrv/libmlrpc.h> 405331Samw #include <smbsrv/ndl/netdfs.ndl> 415331Samw 425331Samw typedef struct { 435331Samw char *server; 445331Samw char *share; 455331Samw char *path; 465331Samw char *buf; 475331Samw } netdfs_unc_t; 485331Samw 49*8334SJose.Borrego@Sun.COM static int netdfs_unc_parse(ndr_xa_t *, const char *, 505331Samw netdfs_unc_t *); 515331Samw 52*8334SJose.Borrego@Sun.COM static int netdfs_s_getver(void *, ndr_xa_t *); 53*8334SJose.Borrego@Sun.COM static int netdfs_s_add(void *, ndr_xa_t *); 54*8334SJose.Borrego@Sun.COM static int netdfs_s_remove(void *, ndr_xa_t *); 55*8334SJose.Borrego@Sun.COM static int netdfs_s_setinfo(void *, ndr_xa_t *); 56*8334SJose.Borrego@Sun.COM static int netdfs_s_getinfo(void *, ndr_xa_t *); 57*8334SJose.Borrego@Sun.COM static int netdfs_s_enum(void *, ndr_xa_t *); 58*8334SJose.Borrego@Sun.COM static int netdfs_s_move(void *, ndr_xa_t *); 59*8334SJose.Borrego@Sun.COM static int netdfs_s_rename(void *, ndr_xa_t *); 60*8334SJose.Borrego@Sun.COM static int netdfs_s_addstdroot(void *, ndr_xa_t *); 61*8334SJose.Borrego@Sun.COM static int netdfs_s_remstdroot(void *, ndr_xa_t *); 62*8334SJose.Borrego@Sun.COM static int netdfs_s_enumex(void *, ndr_xa_t *); 635331Samw 64*8334SJose.Borrego@Sun.COM static ndr_stub_table_t netdfs_stub_table[] = { 655331Samw { netdfs_s_getver, NETDFS_OPNUM_GETVER }, 665331Samw { netdfs_s_add, NETDFS_OPNUM_ADD }, 675331Samw { netdfs_s_remove, NETDFS_OPNUM_REMOVE }, 685331Samw { netdfs_s_setinfo, NETDFS_OPNUM_SETINFO }, 695331Samw { netdfs_s_getinfo, NETDFS_OPNUM_GETINFO }, 705331Samw { netdfs_s_enum, NETDFS_OPNUM_ENUM }, 715331Samw { netdfs_s_rename, NETDFS_OPNUM_RENAME }, 725331Samw { netdfs_s_move, NETDFS_OPNUM_MOVE }, 735331Samw { netdfs_s_addstdroot, NETDFS_OPNUM_ADDSTDROOT }, 745331Samw { netdfs_s_remstdroot, NETDFS_OPNUM_REMSTDROOT }, 755331Samw { netdfs_s_enumex, NETDFS_OPNUM_ENUMEX }, 765331Samw {0} 775331Samw }; 785331Samw 79*8334SJose.Borrego@Sun.COM static ndr_service_t netdfs_service = { 805331Samw "NETDFS", /* name */ 815331Samw "DFS", /* desc */ 825331Samw "\\dfs", /* endpoint */ 835331Samw PIPE_NTSVCS, /* sec_addr_port */ 845331Samw NETDFS_ABSTRACT_UUID, NETDFS_ABSTRACT_VERS, 855331Samw NETDFS_TRANSFER_UUID, NETDFS_TRANSFER_VERS, 865331Samw 875331Samw 0, /* no bind_instance_size */ 885331Samw 0, /* no bind_req() */ 895331Samw 0, /* no unbind_and_close() */ 905331Samw 0, /* use generic_call_stub() */ 915331Samw 925331Samw &TYPEINFO(netdfs_interface), /* interface ti */ 935331Samw netdfs_stub_table /* stub_table */ 945331Samw }; 955331Samw 965331Samw /* 975331Samw * Register the NETDFS RPC interface with the RPC runtime library. 985331Samw * The service must be registered in order to use either the client 995331Samw * side or the server side functions. 1005331Samw */ 1015331Samw void 1025331Samw netdfs_initialize(void) 1035331Samw { 104*8334SJose.Borrego@Sun.COM (void) ndr_svc_register(&netdfs_service); 1055331Samw } 1065331Samw 1075331Samw /* 1085331Samw * Return the version. 1095331Samw * 1105331Samw * We have to indicate that we emulate a Windows 2003 Server or the 1115331Samw * client will not use the EnumEx RPC and this would limit support 1125331Samw * to a single DFS root. 1135331Samw */ 1145331Samw /*ARGSUSED*/ 1155331Samw static int 116*8334SJose.Borrego@Sun.COM netdfs_s_getver(void *arg, ndr_xa_t *mxa) 1175331Samw { 1185331Samw struct netdfs_getver *param = arg; 1195331Samw 1205331Samw param->version = DFS_MANAGER_VERSION_W2K3; 121*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 1225331Samw } 1235331Samw 1245331Samw /* 1255331Samw * Add a new volume or additional storage for an existing volume at 1265331Samw * dfs_path. 1275331Samw */ 1285331Samw static int 129*8334SJose.Borrego@Sun.COM netdfs_s_add(void *arg, ndr_xa_t *mxa) 1305331Samw { 1315331Samw struct netdfs_add *param = arg; 1325331Samw netdfs_unc_t unc; 1335331Samw DWORD status = ERROR_SUCCESS; 1345331Samw 1355331Samw if (param->dfs_path == NULL || param->server == NULL || 1365331Samw param->share == NULL) { 1375331Samw bzero(param, sizeof (struct netdfs_add)); 1385331Samw param->status = ERROR_INVALID_PARAMETER; 139*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 1405331Samw } 1415331Samw 1425331Samw if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) { 1435331Samw status = ERROR_INVALID_PARAMETER; 1445331Samw } else { 1455331Samw if (unc.path == NULL) 1465331Samw status = ERROR_BAD_PATHNAME; 1475331Samw 1485331Samw if (unc.share == NULL) 1495331Samw status = ERROR_INVALID_SHARENAME; 1505331Samw } 1515331Samw 1525331Samw if (param->status != ERROR_SUCCESS) { 1535331Samw bzero(param, sizeof (struct netdfs_add)); 1545331Samw param->status = status; 155*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 1565331Samw } 1575331Samw 1585331Samw bzero(param, sizeof (struct netdfs_add)); 1595331Samw param->status = ERROR_ACCESS_DENIED; 160*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 1615331Samw } 1625331Samw 1635331Samw /* 1645331Samw * netdfs_s_remove 1655331Samw * 1665331Samw * Remove a volume or additional storage for volume from the DFS at 1675331Samw * dfs_path. When applied to the last storage in a volume, removes 1685331Samw * the volume from the DFS. 1695331Samw */ 1705331Samw static int 171*8334SJose.Borrego@Sun.COM netdfs_s_remove(void *arg, ndr_xa_t *mxa) 1725331Samw { 1735331Samw struct netdfs_remove *param = arg; 1745331Samw netdfs_unc_t unc; 1755331Samw DWORD status = ERROR_SUCCESS; 1765331Samw 1775331Samw if (param->dfs_path == NULL || param->server == NULL || 1785331Samw param->share == NULL) { 1795331Samw bzero(param, sizeof (struct netdfs_remove)); 1805331Samw param->status = ERROR_INVALID_PARAMETER; 181*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 1825331Samw } 1835331Samw 1845331Samw if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) { 1855331Samw status = ERROR_INVALID_PARAMETER; 1865331Samw } else { 1875331Samw if (unc.path == NULL) 1885331Samw status = ERROR_BAD_PATHNAME; 1895331Samw 1905331Samw if (unc.share == NULL) 1915331Samw status = ERROR_INVALID_SHARENAME; 1925331Samw } 1935331Samw 1945331Samw if (param->status != ERROR_SUCCESS) { 1955331Samw bzero(param, sizeof (struct netdfs_remove)); 1965331Samw param->status = status; 197*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 1985331Samw } 1995331Samw 2005331Samw bzero(param, sizeof (struct netdfs_remove)); 2015331Samw param->status = ERROR_ACCESS_DENIED; 202*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 2035331Samw } 2045331Samw 2055331Samw /* 2065331Samw * Set information about the volume or storage. If the server and share 2075331Samw * are specified, the information set is specific to that server and 2085331Samw * share. Otherwise the information is specific to the volume as a whole. 2095331Samw * 2105331Samw * Valid levels are 100-102. 2115331Samw */ 2125331Samw /*ARGSUSED*/ 2135331Samw static int 214*8334SJose.Borrego@Sun.COM netdfs_s_setinfo(void *arg, ndr_xa_t *mxa) 2155331Samw { 2165331Samw struct netdfs_setinfo *param = arg; 2175331Samw netdfs_unc_t unc; 2185331Samw DWORD status = ERROR_SUCCESS; 2195331Samw 2205331Samw if (param->dfs_path == NULL) { 2215331Samw bzero(param, sizeof (struct netdfs_setinfo)); 2225331Samw param->status = ERROR_INVALID_PARAMETER; 223*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 2245331Samw } 2255331Samw 2265331Samw if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) { 2275331Samw status = ERROR_INVALID_PARAMETER; 2285331Samw } else { 2295331Samw if (unc.share == NULL) 2305331Samw status = ERROR_INVALID_SHARENAME; 2315331Samw } 2325331Samw 2335331Samw if (param->status != ERROR_SUCCESS) { 2345331Samw bzero(param, sizeof (struct netdfs_setinfo)); 2355331Samw param->status = status; 236*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 2375331Samw } 2385331Samw 2395331Samw switch (param->info.level) { 2405331Samw case 100: 2415331Samw case 101: 2425331Samw case 102: 2435331Samw break; 2445331Samw 2455331Samw default: 2465331Samw bzero(param, sizeof (struct netdfs_setinfo)); 2475331Samw param->status = ERROR_INVALID_LEVEL; 248*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 2495331Samw } 2505331Samw 2515331Samw bzero(param, sizeof (struct netdfs_setinfo)); 2525331Samw param->status = ERROR_ACCESS_DENIED; 253*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 2545331Samw } 2555331Samw 2565331Samw /* 2575331Samw * Get information about the volume or storage. If the server and share 2585331Samw * are specified, the information returned is specific to that server 2595331Samw * and share. Otherwise the information is specific to the volume as a 2605331Samw * whole. 2615331Samw * 2625331Samw * Valid levels are 1-4, 100-104. 2635331Samw */ 2645331Samw /*ARGSUSED*/ 2655331Samw static int 266*8334SJose.Borrego@Sun.COM netdfs_s_getinfo(void *arg, ndr_xa_t *mxa) 2675331Samw { 2685331Samw struct netdfs_getinfo *param = arg; 2695331Samw netdfs_unc_t unc; 2705331Samw DWORD status = ERROR_SUCCESS; 2715331Samw 2725331Samw if (param->dfs_path == NULL) { 2735331Samw bzero(param, sizeof (struct netdfs_getinfo)); 2745331Samw param->status = ERROR_INVALID_PARAMETER; 275*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 2765331Samw } 2775331Samw 2785331Samw if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) { 2795331Samw status = ERROR_INVALID_PARAMETER; 2805331Samw } else { 2815331Samw if (unc.share == NULL) 2825331Samw status = ERROR_INVALID_SHARENAME; 2835331Samw } 2845331Samw 2855331Samw if (param->status != ERROR_SUCCESS) { 2865331Samw bzero(param, sizeof (struct netdfs_getinfo)); 2875331Samw param->status = status; 288*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 2895331Samw } 2905331Samw 2915331Samw switch (param->level) { 2925331Samw case 1: 2935331Samw case 2: 2945331Samw case 3: 2955331Samw case 4: 2965331Samw case 100: 2975331Samw case 101: 2985331Samw case 102: 2995331Samw case 103: 3005331Samw case 104: 3015331Samw break; 3025331Samw 3035331Samw default: 3045331Samw bzero(param, sizeof (struct netdfs_getinfo)); 3055331Samw param->status = ERROR_INVALID_LEVEL; 306*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 3075331Samw } 3085331Samw 3095331Samw bzero(param, sizeof (struct netdfs_getinfo)); 3105331Samw param->status = ERROR_ACCESS_DENIED; 311*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 3125331Samw } 3135331Samw 3145331Samw /* 3155331Samw * Get information about all of the volumes in the DFS. dfs_name is 3165331Samw * the "server" part of the UNC name used to refer to this particular 3175331Samw * DFS. 3185331Samw * 3195331Samw * Valid levels are 1-3. 3205331Samw */ 3215331Samw /*ARGSUSED*/ 3225331Samw static int 323*8334SJose.Borrego@Sun.COM netdfs_s_enum(void *arg, ndr_xa_t *mxa) 3245331Samw { 3255331Samw struct netdfs_enum *param = arg; 3265331Samw 3275331Samw switch (param->level) { 3285331Samw case 1: 3295331Samw case 2: 3305331Samw case 3: 3315331Samw break; 3325331Samw 3335331Samw default: 3345331Samw (void) bzero(param, sizeof (struct netdfs_enum)); 3355331Samw param->status = ERROR_INVALID_LEVEL; 336*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 3375331Samw } 3385331Samw 3395331Samw (void) bzero(param, sizeof (struct netdfs_enum)); 3405331Samw param->status = ERROR_ACCESS_DENIED; 341*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 3425331Samw } 3435331Samw 3445331Samw /* 3455331Samw * Move a DFS volume and all subordinate volumes from one place in the 3465331Samw * DFS to another place in the DFS. 3475331Samw */ 3485331Samw /*ARGSUSED*/ 3495331Samw static int 350*8334SJose.Borrego@Sun.COM netdfs_s_move(void *arg, ndr_xa_t *mxa) 3515331Samw { 3525331Samw struct netdfs_move *param = arg; 3535331Samw 3545331Samw if (param->dfs_path == NULL || param->new_path == NULL) { 3555331Samw bzero(param, sizeof (struct netdfs_move)); 3565331Samw param->status = ERROR_INVALID_PARAMETER; 357*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 3585331Samw } 3595331Samw 3605331Samw bzero(param, sizeof (struct netdfs_move)); 3615331Samw param->status = ERROR_ACCESS_DENIED; 362*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 3635331Samw } 3645331Samw 3655331Samw /* 3665331Samw * Rename the current path in a DFS to a new path in the same DFS. 3675331Samw */ 3685331Samw /*ARGSUSED*/ 3695331Samw static int 370*8334SJose.Borrego@Sun.COM netdfs_s_rename(void *arg, ndr_xa_t *mxa) 3715331Samw { 3725331Samw struct netdfs_rename *param = arg; 3735331Samw 3745331Samw if (param->dfs_path == NULL || param->new_path == NULL) { 3755331Samw bzero(param, sizeof (struct netdfs_rename)); 3765331Samw param->status = ERROR_INVALID_PARAMETER; 377*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 3785331Samw } 3795331Samw 3805331Samw bzero(param, sizeof (struct netdfs_rename)); 3815331Samw param->status = ERROR_ACCESS_DENIED; 382*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 3835331Samw } 3845331Samw 3855331Samw /* 3865331Samw * Add a DFS root share. 3875331Samw */ 3885331Samw /*ARGSUSED*/ 3895331Samw static int 390*8334SJose.Borrego@Sun.COM netdfs_s_addstdroot(void *arg, ndr_xa_t *mxa) 3915331Samw { 3925331Samw struct netdfs_addstdroot *param = arg; 3935331Samw 3945331Samw bzero(param, sizeof (struct netdfs_addstdroot)); 3955331Samw param->status = ERROR_INVALID_PARAMETER; 396*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 3975331Samw } 3985331Samw 3995331Samw /* 4005331Samw * Remove a DFS root share. 4015331Samw */ 4025331Samw /*ARGSUSED*/ 4035331Samw static int 404*8334SJose.Borrego@Sun.COM netdfs_s_remstdroot(void *arg, ndr_xa_t *mxa) 4055331Samw { 4065331Samw struct netdfs_remstdroot *param = arg; 4075331Samw 4085331Samw bzero(param, sizeof (struct netdfs_remstdroot)); 4095331Samw param->status = ERROR_INVALID_PARAMETER; 410*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 4115331Samw } 4125331Samw 4135331Samw /* 4145331Samw * Get information about all of the volumes in the DFS. dfs_path is 4155331Samw * the "server" part of the UNC name used to refer to this particular 4165331Samw * DFS. 4175331Samw * 4185331Samw * Valid levels are 1-3, 300. 4195331Samw */ 4205331Samw static int 421*8334SJose.Borrego@Sun.COM netdfs_s_enumex(void *arg, ndr_xa_t *mxa) 4225331Samw { 4235331Samw struct netdfs_enumex *param = arg; 4245331Samw netdfs_unc_t unc; 4255331Samw DWORD status = ERROR_SUCCESS; 4265331Samw 4275331Samw if (param->dfs_path == NULL) { 4285331Samw bzero(param, sizeof (struct netdfs_enumex)); 4295331Samw param->status = ERROR_INVALID_PARAMETER; 430*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 4315331Samw } 4325331Samw 4335331Samw if (param->resume_handle == NULL) 434*8334SJose.Borrego@Sun.COM param->resume_handle = NDR_NEW(mxa, DWORD); 4355331Samw 4365331Samw if (param->resume_handle) 4375331Samw *(param->resume_handle) = 0; 4385331Samw 4395331Samw if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) { 4405331Samw status = ERROR_INVALID_PARAMETER; 4415331Samw } else { 4425331Samw if (unc.path == NULL) 4435331Samw status = ERROR_BAD_PATHNAME; 4445331Samw 4455331Samw if (unc.share == NULL) 4465331Samw status = ERROR_INVALID_SHARENAME; 4475331Samw } 4485331Samw 4495331Samw if (param->status != ERROR_SUCCESS) { 4505331Samw bzero(param, sizeof (struct netdfs_enumex)); 4515331Samw param->status = status; 452*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 4535331Samw } 4545331Samw 455*8334SJose.Borrego@Sun.COM param->info = NDR_NEW(mxa, struct netdfs_enum_info); 4565331Samw if (param->info == NULL) { 4575331Samw bzero(param, sizeof (struct netdfs_enumex)); 4585331Samw param->status = ERROR_NOT_ENOUGH_MEMORY; 459*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 4605331Samw } 4615331Samw 4625331Samw bzero(param->info, sizeof (struct netdfs_enumex)); 4635331Samw param->status = ERROR_SUCCESS; 464*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 4655331Samw } 4665331Samw 4675331Samw /* 4685331Samw * Parse a UNC path (\\server\share\path) into components. 4695331Samw * Path separators are converted to forward slashes. 4705331Samw * 4715331Samw * Returns 0 on success, otherwise -1 to indicate an error. 4725331Samw */ 4735331Samw static int 474*8334SJose.Borrego@Sun.COM netdfs_unc_parse(ndr_xa_t *mxa, const char *path, netdfs_unc_t *unc) 4755331Samw { 4765331Samw char *p; 4775331Samw 4785331Samw if (path == NULL || unc == NULL) 4795331Samw return (-1); 4805331Samw 481*8334SJose.Borrego@Sun.COM if ((unc->buf = NDR_STRDUP(mxa, (char *)path)) == NULL) 4825331Samw return (-1); 4835331Samw 4845331Samw if ((p = strchr(unc->buf, '\n')) != NULL) 4855331Samw *p = '\0'; 4865331Samw 4875331Samw (void) strsubst(unc->buf, '\\', '/'); 4885331Samw (void) strcanon(unc->buf, "/"); 4895331Samw 4905331Samw unc->server = unc->buf; 4915331Samw unc->server += strspn(unc->buf, "/"); 4925331Samw 4935331Samw if (unc->server) { 4945331Samw unc->share = strchr(unc->server, '/'); 4955331Samw if ((p = unc->share) != NULL) { 4965331Samw unc->share += strspn(unc->share, "/"); 4975331Samw *p = '\0'; 4985331Samw } 4995331Samw } 5005331Samw 5015331Samw if (unc->share) { 5025331Samw unc->path = strchr(unc->share, '/'); 5035331Samw if ((p = unc->path) != NULL) { 5045331Samw unc->path += strspn(unc->path, "/"); 5055331Samw *p = '\0'; 5065331Samw } 5075331Samw } 5085331Samw 5095331Samw if (unc->path) { 5105331Samw if ((p = strchr(unc->path, '\0')) != NULL) { 5115331Samw if (*(--p) == '/') 5125331Samw *p = '\0'; 5135331Samw } 5145331Samw } 5155331Samw 5165331Samw return (0); 5175331Samw } 518