1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Net DFS server side RPC service. 30 */ 31 32 #include <sys/types.h> 33 #include <strings.h> 34 #include <string.h> 35 36 #include <smbsrv/libsmb.h> 37 #include <smbsrv/lmerr.h> 38 #include <smbsrv/lmdfs.h> 39 #include <smbsrv/nmpipes.h> 40 #include <smbsrv/nterror.h> 41 #include <smbsrv/mlrpc.h> 42 #include <smbsrv/ndl/netdfs.ndl> 43 44 typedef struct { 45 char *server; 46 char *share; 47 char *path; 48 char *buf; 49 } netdfs_unc_t; 50 51 static int netdfs_unc_parse(struct mlrpc_xaction *, const char *, 52 netdfs_unc_t *); 53 54 static int netdfs_s_getver(void *, struct mlrpc_xaction *); 55 static int netdfs_s_add(void *, struct mlrpc_xaction *); 56 static int netdfs_s_remove(void *, struct mlrpc_xaction *); 57 static int netdfs_s_setinfo(void *, struct mlrpc_xaction *); 58 static int netdfs_s_getinfo(void *, struct mlrpc_xaction *); 59 static int netdfs_s_enum(void *, struct mlrpc_xaction *); 60 static int netdfs_s_move(void *, struct mlrpc_xaction *); 61 static int netdfs_s_rename(void *, struct mlrpc_xaction *); 62 static int netdfs_s_addstdroot(void *, struct mlrpc_xaction *); 63 static int netdfs_s_remstdroot(void *, struct mlrpc_xaction *); 64 static int netdfs_s_enumex(void *, struct mlrpc_xaction *); 65 66 static mlrpc_stub_table_t netdfs_stub_table[] = { 67 { netdfs_s_getver, NETDFS_OPNUM_GETVER }, 68 { netdfs_s_add, NETDFS_OPNUM_ADD }, 69 { netdfs_s_remove, NETDFS_OPNUM_REMOVE }, 70 { netdfs_s_setinfo, NETDFS_OPNUM_SETINFO }, 71 { netdfs_s_getinfo, NETDFS_OPNUM_GETINFO }, 72 { netdfs_s_enum, NETDFS_OPNUM_ENUM }, 73 { netdfs_s_rename, NETDFS_OPNUM_RENAME }, 74 { netdfs_s_move, NETDFS_OPNUM_MOVE }, 75 { netdfs_s_addstdroot, NETDFS_OPNUM_ADDSTDROOT }, 76 { netdfs_s_remstdroot, NETDFS_OPNUM_REMSTDROOT }, 77 { netdfs_s_enumex, NETDFS_OPNUM_ENUMEX }, 78 {0} 79 }; 80 81 static mlrpc_service_t netdfs_service = { 82 "NETDFS", /* name */ 83 "DFS", /* desc */ 84 "\\dfs", /* endpoint */ 85 PIPE_NTSVCS, /* sec_addr_port */ 86 NETDFS_ABSTRACT_UUID, NETDFS_ABSTRACT_VERS, 87 NETDFS_TRANSFER_UUID, NETDFS_TRANSFER_VERS, 88 89 0, /* no bind_instance_size */ 90 0, /* no bind_req() */ 91 0, /* no unbind_and_close() */ 92 0, /* use generic_call_stub() */ 93 94 &TYPEINFO(netdfs_interface), /* interface ti */ 95 netdfs_stub_table /* stub_table */ 96 }; 97 98 /* 99 * Register the NETDFS RPC interface with the RPC runtime library. 100 * The service must be registered in order to use either the client 101 * side or the server side functions. 102 */ 103 void 104 netdfs_initialize(void) 105 { 106 (void) mlrpc_register_service(&netdfs_service); 107 } 108 109 /* 110 * Return the version. 111 * 112 * We have to indicate that we emulate a Windows 2003 Server or the 113 * client will not use the EnumEx RPC and this would limit support 114 * to a single DFS root. 115 */ 116 /*ARGSUSED*/ 117 static int 118 netdfs_s_getver(void *arg, struct mlrpc_xaction *mxa) 119 { 120 struct netdfs_getver *param = arg; 121 122 param->version = DFS_MANAGER_VERSION_W2K3; 123 return (MLRPC_DRC_OK); 124 } 125 126 /* 127 * Add a new volume or additional storage for an existing volume at 128 * dfs_path. 129 */ 130 static int 131 netdfs_s_add(void *arg, struct mlrpc_xaction *mxa) 132 { 133 struct netdfs_add *param = arg; 134 netdfs_unc_t unc; 135 DWORD status = ERROR_SUCCESS; 136 137 if (param->dfs_path == NULL || param->server == NULL || 138 param->share == NULL) { 139 bzero(param, sizeof (struct netdfs_add)); 140 param->status = ERROR_INVALID_PARAMETER; 141 return (MLRPC_DRC_OK); 142 } 143 144 if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) { 145 status = ERROR_INVALID_PARAMETER; 146 } else { 147 if (unc.path == NULL) 148 status = ERROR_BAD_PATHNAME; 149 150 if (unc.share == NULL) 151 status = ERROR_INVALID_SHARENAME; 152 } 153 154 if (param->status != ERROR_SUCCESS) { 155 bzero(param, sizeof (struct netdfs_add)); 156 param->status = status; 157 return (MLRPC_DRC_OK); 158 } 159 160 bzero(param, sizeof (struct netdfs_add)); 161 param->status = ERROR_ACCESS_DENIED; 162 return (MLRPC_DRC_OK); 163 } 164 165 /* 166 * netdfs_s_remove 167 * 168 * Remove a volume or additional storage for volume from the DFS at 169 * dfs_path. When applied to the last storage in a volume, removes 170 * the volume from the DFS. 171 */ 172 static int 173 netdfs_s_remove(void *arg, struct mlrpc_xaction *mxa) 174 { 175 struct netdfs_remove *param = arg; 176 netdfs_unc_t unc; 177 DWORD status = ERROR_SUCCESS; 178 179 if (param->dfs_path == NULL || param->server == NULL || 180 param->share == NULL) { 181 bzero(param, sizeof (struct netdfs_remove)); 182 param->status = ERROR_INVALID_PARAMETER; 183 return (MLRPC_DRC_OK); 184 } 185 186 if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) { 187 status = ERROR_INVALID_PARAMETER; 188 } else { 189 if (unc.path == NULL) 190 status = ERROR_BAD_PATHNAME; 191 192 if (unc.share == NULL) 193 status = ERROR_INVALID_SHARENAME; 194 } 195 196 if (param->status != ERROR_SUCCESS) { 197 bzero(param, sizeof (struct netdfs_remove)); 198 param->status = status; 199 return (MLRPC_DRC_OK); 200 } 201 202 bzero(param, sizeof (struct netdfs_remove)); 203 param->status = ERROR_ACCESS_DENIED; 204 return (MLRPC_DRC_OK); 205 } 206 207 /* 208 * Set information about the volume or storage. If the server and share 209 * are specified, the information set is specific to that server and 210 * share. Otherwise the information is specific to the volume as a whole. 211 * 212 * Valid levels are 100-102. 213 */ 214 /*ARGSUSED*/ 215 static int 216 netdfs_s_setinfo(void *arg, struct mlrpc_xaction *mxa) 217 { 218 struct netdfs_setinfo *param = arg; 219 netdfs_unc_t unc; 220 DWORD status = ERROR_SUCCESS; 221 222 if (param->dfs_path == NULL) { 223 bzero(param, sizeof (struct netdfs_setinfo)); 224 param->status = ERROR_INVALID_PARAMETER; 225 return (MLRPC_DRC_OK); 226 } 227 228 if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) { 229 status = ERROR_INVALID_PARAMETER; 230 } else { 231 if (unc.share == NULL) 232 status = ERROR_INVALID_SHARENAME; 233 } 234 235 if (param->status != ERROR_SUCCESS) { 236 bzero(param, sizeof (struct netdfs_setinfo)); 237 param->status = status; 238 return (MLRPC_DRC_OK); 239 } 240 241 switch (param->info.level) { 242 case 100: 243 case 101: 244 case 102: 245 break; 246 247 default: 248 bzero(param, sizeof (struct netdfs_setinfo)); 249 param->status = ERROR_INVALID_LEVEL; 250 return (MLRPC_DRC_OK); 251 } 252 253 bzero(param, sizeof (struct netdfs_setinfo)); 254 param->status = ERROR_ACCESS_DENIED; 255 return (MLRPC_DRC_OK); 256 } 257 258 /* 259 * Get information about the volume or storage. If the server and share 260 * are specified, the information returned is specific to that server 261 * and share. Otherwise the information is specific to the volume as a 262 * whole. 263 * 264 * Valid levels are 1-4, 100-104. 265 */ 266 /*ARGSUSED*/ 267 static int 268 netdfs_s_getinfo(void *arg, struct mlrpc_xaction *mxa) 269 { 270 struct netdfs_getinfo *param = arg; 271 netdfs_unc_t unc; 272 DWORD status = ERROR_SUCCESS; 273 274 if (param->dfs_path == NULL) { 275 bzero(param, sizeof (struct netdfs_getinfo)); 276 param->status = ERROR_INVALID_PARAMETER; 277 return (MLRPC_DRC_OK); 278 } 279 280 if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) { 281 status = ERROR_INVALID_PARAMETER; 282 } else { 283 if (unc.share == NULL) 284 status = ERROR_INVALID_SHARENAME; 285 } 286 287 if (param->status != ERROR_SUCCESS) { 288 bzero(param, sizeof (struct netdfs_getinfo)); 289 param->status = status; 290 return (MLRPC_DRC_OK); 291 } 292 293 switch (param->level) { 294 case 1: 295 case 2: 296 case 3: 297 case 4: 298 case 100: 299 case 101: 300 case 102: 301 case 103: 302 case 104: 303 break; 304 305 default: 306 bzero(param, sizeof (struct netdfs_getinfo)); 307 param->status = ERROR_INVALID_LEVEL; 308 return (MLRPC_DRC_OK); 309 } 310 311 bzero(param, sizeof (struct netdfs_getinfo)); 312 param->status = ERROR_ACCESS_DENIED; 313 return (MLRPC_DRC_OK); 314 } 315 316 /* 317 * Get information about all of the volumes in the DFS. dfs_name is 318 * the "server" part of the UNC name used to refer to this particular 319 * DFS. 320 * 321 * Valid levels are 1-3. 322 */ 323 /*ARGSUSED*/ 324 static int 325 netdfs_s_enum(void *arg, struct mlrpc_xaction *mxa) 326 { 327 struct netdfs_enum *param = arg; 328 329 switch (param->level) { 330 case 1: 331 case 2: 332 case 3: 333 break; 334 335 default: 336 (void) bzero(param, sizeof (struct netdfs_enum)); 337 param->status = ERROR_INVALID_LEVEL; 338 return (MLRPC_DRC_OK); 339 } 340 341 (void) bzero(param, sizeof (struct netdfs_enum)); 342 param->status = ERROR_ACCESS_DENIED; 343 return (MLRPC_DRC_OK); 344 } 345 346 /* 347 * Move a DFS volume and all subordinate volumes from one place in the 348 * DFS to another place in the DFS. 349 */ 350 /*ARGSUSED*/ 351 static int 352 netdfs_s_move(void *arg, struct mlrpc_xaction *mxa) 353 { 354 struct netdfs_move *param = arg; 355 356 if (param->dfs_path == NULL || param->new_path == NULL) { 357 bzero(param, sizeof (struct netdfs_move)); 358 param->status = ERROR_INVALID_PARAMETER; 359 return (MLRPC_DRC_OK); 360 } 361 362 bzero(param, sizeof (struct netdfs_move)); 363 param->status = ERROR_ACCESS_DENIED; 364 return (MLRPC_DRC_OK); 365 } 366 367 /* 368 * Rename the current path in a DFS to a new path in the same DFS. 369 */ 370 /*ARGSUSED*/ 371 static int 372 netdfs_s_rename(void *arg, struct mlrpc_xaction *mxa) 373 { 374 struct netdfs_rename *param = arg; 375 376 if (param->dfs_path == NULL || param->new_path == NULL) { 377 bzero(param, sizeof (struct netdfs_rename)); 378 param->status = ERROR_INVALID_PARAMETER; 379 return (MLRPC_DRC_OK); 380 } 381 382 bzero(param, sizeof (struct netdfs_rename)); 383 param->status = ERROR_ACCESS_DENIED; 384 return (MLRPC_DRC_OK); 385 } 386 387 /* 388 * Add a DFS root share. 389 */ 390 /*ARGSUSED*/ 391 static int 392 netdfs_s_addstdroot(void *arg, struct mlrpc_xaction *mxa) 393 { 394 struct netdfs_addstdroot *param = arg; 395 396 bzero(param, sizeof (struct netdfs_addstdroot)); 397 param->status = ERROR_INVALID_PARAMETER; 398 return (MLRPC_DRC_OK); 399 } 400 401 /* 402 * Remove a DFS root share. 403 */ 404 /*ARGSUSED*/ 405 static int 406 netdfs_s_remstdroot(void *arg, struct mlrpc_xaction *mxa) 407 { 408 struct netdfs_remstdroot *param = arg; 409 410 bzero(param, sizeof (struct netdfs_remstdroot)); 411 param->status = ERROR_INVALID_PARAMETER; 412 return (MLRPC_DRC_OK); 413 } 414 415 /* 416 * Get information about all of the volumes in the DFS. dfs_path is 417 * the "server" part of the UNC name used to refer to this particular 418 * DFS. 419 * 420 * Valid levels are 1-3, 300. 421 */ 422 static int 423 netdfs_s_enumex(void *arg, struct mlrpc_xaction *mxa) 424 { 425 struct netdfs_enumex *param = arg; 426 netdfs_unc_t unc; 427 DWORD status = ERROR_SUCCESS; 428 429 if (param->dfs_path == NULL) { 430 bzero(param, sizeof (struct netdfs_enumex)); 431 param->status = ERROR_INVALID_PARAMETER; 432 return (MLRPC_DRC_OK); 433 } 434 435 if (param->resume_handle == NULL) 436 param->resume_handle = MLRPC_HEAP_NEW(mxa, DWORD); 437 438 if (param->resume_handle) 439 *(param->resume_handle) = 0; 440 441 if (netdfs_unc_parse(mxa, (char *)param->dfs_path, &unc) != 0) { 442 status = ERROR_INVALID_PARAMETER; 443 } else { 444 if (unc.path == NULL) 445 status = ERROR_BAD_PATHNAME; 446 447 if (unc.share == NULL) 448 status = ERROR_INVALID_SHARENAME; 449 } 450 451 if (param->status != ERROR_SUCCESS) { 452 bzero(param, sizeof (struct netdfs_enumex)); 453 param->status = status; 454 return (MLRPC_DRC_OK); 455 } 456 457 param->info = MLRPC_HEAP_NEW(mxa, struct netdfs_enum_info); 458 if (param->info == NULL) { 459 bzero(param, sizeof (struct netdfs_enumex)); 460 param->status = ERROR_NOT_ENOUGH_MEMORY; 461 return (MLRPC_DRC_OK); 462 } 463 464 bzero(param->info, sizeof (struct netdfs_enumex)); 465 param->status = ERROR_SUCCESS; 466 return (MLRPC_DRC_OK); 467 } 468 469 /* 470 * Parse a UNC path (\\server\share\path) into components. 471 * Path separators are converted to forward slashes. 472 * 473 * Returns 0 on success, otherwise -1 to indicate an error. 474 */ 475 static int 476 netdfs_unc_parse(struct mlrpc_xaction *mxa, const char *path, netdfs_unc_t *unc) 477 { 478 char *p; 479 480 if (path == NULL || unc == NULL) 481 return (-1); 482 483 if ((unc->buf = MLRPC_HEAP_STRSAVE(mxa, (char *)path)) == NULL) 484 return (-1); 485 486 if ((p = strchr(unc->buf, '\n')) != NULL) 487 *p = '\0'; 488 489 (void) strsubst(unc->buf, '\\', '/'); 490 (void) strcanon(unc->buf, "/"); 491 492 unc->server = unc->buf; 493 unc->server += strspn(unc->buf, "/"); 494 495 if (unc->server) { 496 unc->share = strchr(unc->server, '/'); 497 if ((p = unc->share) != NULL) { 498 unc->share += strspn(unc->share, "/"); 499 *p = '\0'; 500 } 501 } 502 503 if (unc->share) { 504 unc->path = strchr(unc->share, '/'); 505 if ((p = unc->path) != NULL) { 506 unc->path += strspn(unc->path, "/"); 507 *p = '\0'; 508 } 509 } 510 511 if (unc->path) { 512 if ((p = strchr(unc->path, '\0')) != NULL) { 513 if (*(--p) == '/') 514 *p = '\0'; 515 } 516 } 517 518 return (0); 519 } 520