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