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 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Net DFS server side RPC service for managing DFS namespaces. 28 * 29 * For more details refer to following Microsoft specification: 30 * [MS-DFSNM] 31 * Distributed File System (DFS): Namespace Management Protocol Specification 32 */ 33 34 #include <unistd.h> 35 #include <libgen.h> 36 #include <strings.h> 37 #include <sys/sysmacros.h> 38 39 #include <smbsrv/libmlsvc.h> 40 #include <smbsrv/nmpipes.h> 41 #include <smbsrv/ndl/netdfs.ndl> 42 #include <dfs.h> 43 44 /* 45 * Depends on the information level requested around 4000 or more links 46 * can be provided with this buffer size. The limitation here is due 47 * to some problem in NDR and/or opipe layer so: 48 * 49 * - Do NOT increase the buffer size until that problem is fixed 50 * - The buffer size should be increased when the problem is fixed 51 * so the 4000 link limitation is removed. 52 */ 53 #define NETDFS_MAXBUFLEN (800 * 1024) 54 #define NETDFS_MAXPREFLEN ((uint32_t)(-1)) 55 56 typedef struct netdfs_enumhandle_t { 57 uint32_t de_level; /* level of detail being requested */ 58 uint32_t de_prefmaxlen; /* client MAX size buffer preference */ 59 uint32_t de_resume; /* client resume handle */ 60 uint32_t de_bavail; /* remaining buffer space in bytes */ 61 uint32_t de_ntotal; /* total number of objects */ 62 uint32_t de_nmax; /* MAX number of objects to return */ 63 uint32_t de_nitems; /* number of objects in buf */ 64 uint32_t de_nskip; /* number of objects to skip */ 65 void *de_entries; /* ndr buffer */ 66 } netdfs_enumhandle_t; 67 68 static int netdfs_s_getver(void *, ndr_xa_t *); 69 static int netdfs_s_add(void *, ndr_xa_t *); 70 static int netdfs_s_remove(void *, ndr_xa_t *); 71 static int netdfs_s_setinfo(void *, ndr_xa_t *); 72 static int netdfs_s_getinfo(void *, ndr_xa_t *); 73 static int netdfs_s_enum(void *, ndr_xa_t *); 74 static int netdfs_s_move(void *, ndr_xa_t *); 75 static int netdfs_s_rename(void *, ndr_xa_t *); 76 static int netdfs_s_addstdroot(void *, ndr_xa_t *); 77 static int netdfs_s_remstdroot(void *, ndr_xa_t *); 78 static int netdfs_s_enumex(void *, ndr_xa_t *); 79 80 static uint32_t netdfs_setinfo_100(dfs_path_t *, netdfs_info100_t *); 81 static uint32_t netdfs_setinfo_101(dfs_path_t *, netdfs_info101_t *, 82 const char *, const char *); 83 static uint32_t netdfs_setinfo_102(dfs_path_t *, netdfs_info102_t *); 84 static uint32_t netdfs_setinfo_103(dfs_path_t *, netdfs_info103_t *); 85 static uint32_t netdfs_setinfo_104(dfs_path_t *, netdfs_info104_t *, 86 const char *, const char *); 87 static uint32_t netdfs_setinfo_105(dfs_path_t *, netdfs_info105_t *); 88 89 static uint32_t netdfs_info_1(netdfs_info1_t *, dfs_info_t *, ndr_xa_t *, 90 uint32_t *); 91 static uint32_t netdfs_info_2(netdfs_info2_t *, dfs_info_t *, ndr_xa_t *, 92 uint32_t *); 93 static uint32_t netdfs_info_3(netdfs_info3_t *, dfs_info_t *, ndr_xa_t *, 94 uint32_t *); 95 static uint32_t netdfs_info_4(netdfs_info4_t *, dfs_info_t *, ndr_xa_t *, 96 uint32_t *); 97 static uint32_t netdfs_info_5(netdfs_info5_t *, dfs_info_t *, ndr_xa_t *, 98 uint32_t *); 99 static uint32_t netdfs_info_6(netdfs_info6_t *, dfs_info_t *, ndr_xa_t *, 100 uint32_t *); 101 static uint32_t netdfs_info_100(netdfs_info100_t *, dfs_info_t *, ndr_xa_t *, 102 uint32_t *); 103 static uint32_t netdfs_info_300(netdfs_info300_t *, dfs_info_t *, ndr_xa_t *, 104 uint32_t *); 105 106 static uint32_t netdfs_enum_common(netdfs_enumhandle_t *, ndr_xa_t *); 107 108 static void netdfs_path_create(const char *); 109 static void netdfs_path_remove(smb_unc_t *); 110 static boolean_t netdfs_guid_fromstr(char *, netdfs_uuid_t *); 111 112 static ndr_stub_table_t netdfs_stub_table[] = { 113 { netdfs_s_getver, NETDFS_OPNUM_GETVER }, 114 { netdfs_s_add, NETDFS_OPNUM_ADD }, 115 { netdfs_s_remove, NETDFS_OPNUM_REMOVE }, 116 { netdfs_s_setinfo, NETDFS_OPNUM_SETINFO }, 117 { netdfs_s_getinfo, NETDFS_OPNUM_GETINFO }, 118 { netdfs_s_enum, NETDFS_OPNUM_ENUM }, 119 { netdfs_s_rename, NETDFS_OPNUM_RENAME }, 120 { netdfs_s_move, NETDFS_OPNUM_MOVE }, 121 { netdfs_s_addstdroot, NETDFS_OPNUM_ADDSTDROOT }, 122 { netdfs_s_remstdroot, NETDFS_OPNUM_REMSTDROOT }, 123 { netdfs_s_enumex, NETDFS_OPNUM_ENUMEX }, 124 {0} 125 }; 126 127 static ndr_service_t netdfs_service = { 128 "NETDFS", /* name */ 129 "DFS", /* desc */ 130 "\\netdfs", /* endpoint */ 131 PIPE_NETDFS, /* sec_addr_port */ 132 NETDFS_ABSTRACT_UUID, NETDFS_ABSTRACT_VERS, 133 NETDFS_TRANSFER_UUID, NETDFS_TRANSFER_VERS, 134 135 0, /* no bind_instance_size */ 136 0, /* no bind_req() */ 137 0, /* no unbind_and_close() */ 138 0, /* use generic_call_stub() */ 139 140 &TYPEINFO(netdfs_interface), /* interface ti */ 141 netdfs_stub_table /* stub_table */ 142 }; 143 144 /* 145 * Register the NETDFS RPC interface with the RPC runtime library. 146 * The service must be registered in order to use either the client 147 * side or the server side functions. 148 */ 149 void 150 netdfs_initialize(void) 151 { 152 (void) ndr_svc_register(&netdfs_service); 153 dfs_init(); 154 } 155 156 void 157 netdfs_finalize(void) 158 { 159 dfs_fini(); 160 } 161 162 /* 163 * Returns the version number of the DFS server in use on the server. 164 * 165 * [MS-DFSNM]: NetrDfsManagerGetVersion (Opnum 0) 166 */ 167 /*ARGSUSED*/ 168 static int 169 netdfs_s_getver(void *arg, ndr_xa_t *mxa) 170 { 171 struct netdfs_getver *param = arg; 172 173 param->version = DFS_MANAGER_VERSION_NT4; 174 return (NDR_DRC_OK); 175 } 176 177 /* 178 * Creates a new DFS link or adds a new target to an existing link of a 179 * DFS namespace. 180 * 181 * [MS-DFSNM]: NetrDfsAdd (Opnum 1) 182 */ 183 static int 184 netdfs_s_add(void *arg, ndr_xa_t *mxa) 185 { 186 netdfs_add_t *param = arg; 187 dfs_path_t path; 188 uint32_t status; 189 const char *uncpath = (const char *)param->dfs_path; 190 const char *fspath = (const char *)path.p_fspath; 191 boolean_t newlink; 192 193 if (!ndr_is_admin(mxa)) { 194 param->status = ERROR_ACCESS_DENIED; 195 return (NDR_DRC_OK); 196 } 197 198 if (param->server == NULL || param->share == NULL) { 199 param->status = ERROR_INVALID_PARAMETER; 200 return (NDR_DRC_OK); 201 } 202 203 switch (param->flags) { 204 case DFS_CREATE_VOLUME: 205 case DFS_ADD_VOLUME: 206 case DFS_RESTORE_VOLUME: 207 case (DFS_ADD_VOLUME | DFS_RESTORE_VOLUME): 208 break; 209 default: 210 param->status = ERROR_INVALID_PARAMETER; 211 return (NDR_DRC_OK); 212 } 213 214 status = dfs_path_parse(&path, uncpath, DFS_OBJECT_LINK); 215 if (status != ERROR_SUCCESS) { 216 param->status = status; 217 return (NDR_DRC_OK); 218 } 219 220 status = smb_name_validate_rpath(path.p_unc.unc_path); 221 if (status != ERROR_SUCCESS) { 222 dfs_path_free(&path); 223 param->status = status; 224 return (NDR_DRC_OK); 225 } 226 227 dfs_setpriv(PRIV_ON); 228 229 netdfs_path_create(fspath); 230 231 status = dfs_link_add(fspath, (const char *)param->server, 232 (const char *)param->share, (const char *)param->comment, 233 param->flags, &newlink); 234 235 if (newlink) 236 (void) dfs_cache_add_byname(path.p_unc.unc_share, 237 path.p_unc.unc_path, DFS_OBJECT_LINK); 238 239 if (status != ERROR_SUCCESS) 240 netdfs_path_remove(&path.p_unc); 241 242 dfs_setpriv(PRIV_OFF); 243 244 dfs_path_free(&path); 245 param->status = status; 246 return (NDR_DRC_OK); 247 } 248 249 /* 250 * Removes a link or a link target from a DFS namespace. A link can be 251 * removed regardless of the number of targets associated with it. 252 * 253 * [MS-DFSNM]: NetrDfsRemove (Opnum 2) 254 */ 255 static int 256 netdfs_s_remove(void *arg, ndr_xa_t *mxa) 257 { 258 struct netdfs_remove *param = arg; 259 dfs_path_t path; 260 uint32_t status, stat; 261 const char *uncpath = (const char *)param->dfs_path; 262 const char *fspath = (const char *)path.p_fspath; 263 264 if (!ndr_is_admin(mxa)) { 265 param->status = ERROR_ACCESS_DENIED; 266 return (NDR_DRC_OK); 267 } 268 269 /* both server and share must be NULL or non-NULL */ 270 if ((param->server == NULL && param->share != NULL) || 271 (param->server != NULL && param->share == NULL)) { 272 param->status = ERROR_INVALID_PARAMETER; 273 return (NDR_DRC_OK); 274 } 275 276 status = dfs_path_parse(&path, uncpath, DFS_OBJECT_LINK); 277 if (status != ERROR_SUCCESS) { 278 param->status = status; 279 return (NDR_DRC_OK); 280 } 281 282 dfs_setpriv(PRIV_ON); 283 284 status = dfs_link_remove(fspath, (const char *)param->server, 285 (const char *)param->share); 286 287 if (status == ERROR_SUCCESS) { 288 if (dfs_link_stat(fspath, &stat) == ERROR_SUCCESS) { 289 if (stat != DFS_STAT_ISDFS) 290 dfs_cache_remove(path.p_unc.unc_share, 291 path.p_unc.unc_path); 292 /* 293 * if link is removed then try to remove its 294 * empty parent directories if any 295 */ 296 if (stat == DFS_STAT_NOTFOUND) 297 netdfs_path_remove(&path.p_unc); 298 } 299 } 300 301 dfs_setpriv(PRIV_OFF); 302 303 dfs_path_free(&path); 304 param->status = status; 305 return (NDR_DRC_OK); 306 } 307 308 /* 309 * Sets or modifies information relevant to a specific DFS root, DFS root 310 * target, DFS link, or DFS link target 311 * 312 * [MS-DFSNM]: NetrDfsSetInfo (Opnum 3) 313 */ 314 /*ARGSUSED*/ 315 static int 316 netdfs_s_setinfo(void *arg, ndr_xa_t *mxa) 317 { 318 netdfs_setinfo_t *param = arg; 319 dfs_path_t path; 320 uint32_t status, stat; 321 322 /* both server and share must be NULL or non-NULL */ 323 if ((param->server == NULL && param->share != NULL) || 324 (param->server != NULL && param->share == NULL)) { 325 param->status = ERROR_INVALID_PARAMETER; 326 return (NDR_DRC_OK); 327 } 328 329 status = dfs_path_parse(&path, (const char *)param->dfs_path, 330 DFS_OBJECT_ANY); 331 332 if (status != ERROR_SUCCESS) { 333 param->status = status; 334 return (NDR_DRC_OK); 335 } 336 337 dfs_setpriv(PRIV_ON); 338 status = dfs_link_stat((const char *)path.p_fspath, &stat); 339 340 if ((path.p_type == DFS_OBJECT_LINK) && (stat != DFS_STAT_ISDFS)) { 341 dfs_setpriv(PRIV_OFF); 342 dfs_path_free(&path); 343 param->status = ERROR_NOT_FOUND; 344 return (NDR_DRC_OK); 345 } 346 347 switch (param->info.level) { 348 case 100: 349 status = netdfs_setinfo_100(&path, param->info.iu.info100); 350 break; 351 case 101: 352 status = netdfs_setinfo_101(&path, param->info.iu.info101, 353 (const char *)param->server, (const char *)param->share); 354 break; 355 case 102: 356 status = netdfs_setinfo_102(&path, param->info.iu.info102); 357 break; 358 case 103: 359 status = netdfs_setinfo_103(&path, param->info.iu.info103); 360 break; 361 case 104: 362 status = netdfs_setinfo_104(&path, param->info.iu.info104, 363 (const char *)param->server, (const char *)param->share); 364 break; 365 case 105: 366 status = netdfs_setinfo_105(&path, param->info.iu.info105); 367 break; 368 default: 369 status = ERROR_INVALID_LEVEL; 370 break; 371 } 372 373 dfs_setpriv(PRIV_OFF); 374 dfs_path_free(&path); 375 param->status = status; 376 return (NDR_DRC_OK); 377 } 378 379 /* 380 * Returns information about a DFS root or a DFS link of the specified 381 * DFS namespace. 382 * 383 * [MS-DFSNM]: NetrDfsGetInfo (Opnum 4) 384 */ 385 static int 386 netdfs_s_getinfo(void *arg, ndr_xa_t *mxa) 387 { 388 netdfs_getinfo_t *param = arg; 389 netdfs_info1_t *info1; 390 netdfs_info2_t *info2; 391 netdfs_info3_t *info3; 392 netdfs_info4_t *info4; 393 netdfs_info5_t *info5; 394 netdfs_info6_t *info6; 395 netdfs_info100_t *info100; 396 dfs_info_t info; 397 dfs_path_t path; 398 uint32_t status, stat; 399 const char *fspath; 400 uint32_t level = param->level; 401 402 status = dfs_path_parse(&path, (const char *)param->dfs_path, 403 DFS_OBJECT_ANY); 404 405 if (status != ERROR_SUCCESS) 406 goto getinfo_error; 407 408 dfs_setpriv(PRIV_ON); 409 410 fspath = path.p_fspath; 411 if (path.p_type == DFS_OBJECT_LINK) { 412 status = dfs_link_stat(fspath, &stat); 413 if ((status != ERROR_SUCCESS) || (stat != DFS_STAT_ISDFS)) { 414 status = ERROR_NOT_FOUND; 415 goto getinfo_error; 416 } 417 418 status = dfs_link_getinfo(fspath, &info, param->level); 419 } else { 420 status = dfs_root_getinfo(fspath, &info, param->level); 421 } 422 423 if (status != ERROR_SUCCESS) 424 goto getinfo_error; 425 426 (void) strlcpy(info.i_uncpath, (char *)param->dfs_path, 427 sizeof (info.i_uncpath)); 428 429 dfs_info_trace("netdfs_s_getinfo", &info); 430 431 status = ERROR_NOT_ENOUGH_MEMORY; 432 433 switch (level) { 434 case 1: 435 if ((info1 = NDR_NEW(mxa, netdfs_info1_t)) != NULL) { 436 param->info.iu.info1 = info1; 437 status = netdfs_info_1(info1, &info, mxa, NULL); 438 } 439 break; 440 case 2: 441 if ((info2 = NDR_NEW(mxa, netdfs_info2_t)) != NULL) { 442 param->info.iu.info2 = info2; 443 status = netdfs_info_2(info2, &info, mxa, NULL); 444 } 445 break; 446 case 3: 447 if ((info3 = NDR_NEW(mxa, netdfs_info3_t)) != NULL) { 448 param->info.iu.info3 = info3; 449 status = netdfs_info_3(info3, &info, mxa, NULL); 450 } 451 break; 452 case 4: 453 if ((info4 = NDR_NEW(mxa, netdfs_info4_t)) != NULL) { 454 param->info.iu.info4 = info4; 455 status = netdfs_info_4(info4, &info, mxa, NULL); 456 } 457 break; 458 case 5: 459 if ((info5 = NDR_NEW(mxa, netdfs_info5_t)) != NULL) { 460 param->info.iu.info5 = info5; 461 status = netdfs_info_5(info5, &info, mxa, NULL); 462 } 463 break; 464 case 6: 465 if ((info6 = NDR_NEW(mxa, netdfs_info6_t)) != NULL) { 466 param->info.iu.info6 = info6; 467 status = netdfs_info_6(info6, &info, mxa, NULL); 468 } 469 break; 470 case 100: 471 if ((info100 = NDR_NEW(mxa, netdfs_info100_t)) != NULL) { 472 param->info.iu.info100 = info100; 473 status = netdfs_info_100(info100, &info, mxa, NULL); 474 } 475 break; 476 477 default: 478 status = ERROR_INVALID_LEVEL; 479 break; 480 } 481 482 dfs_info_free(&info); 483 484 getinfo_error: 485 dfs_setpriv(PRIV_OFF); 486 dfs_path_free(&path); 487 if (status != ERROR_SUCCESS) 488 bzero(param, sizeof (netdfs_getinfo_t)); 489 490 param->info.level = level; 491 param->status = status; 492 return (NDR_DRC_OK); 493 } 494 495 /* 496 * Enumerates the DFS root hosted on a server or the DFS links of the 497 * namespace hosted by a server. Depending on the information level, 498 * the targets of the root and links are also displayed. 499 * 500 * For unsupported levels, it should return ERROR_INVALID_LEVEL as 501 * Microsoft does for DFS server on Win2000 and NT. 502 * 503 * [MS-DFSNM]: NetrDfsEnum (Opnum 5) 504 */ 505 /*ARGSUSED*/ 506 static int 507 netdfs_s_enum(void *arg, ndr_xa_t *mxa) 508 { 509 netdfs_enum_t *param = arg; 510 netdfs_enumhandle_t de; 511 uint32_t level = param->level; 512 uint32_t status = ERROR_SUCCESS; 513 uint32_t nroot; 514 size_t entsize; 515 516 if (param->info == NULL) { 517 status = ERROR_INVALID_PARAMETER; 518 goto enum_error; 519 } 520 521 if ((nroot = dfs_namespace_count()) == 0) 522 status = ERROR_NOT_FOUND; 523 else if (nroot > 1) 524 status = ERROR_DEVICE_NOT_AVAILABLE; 525 526 if (status != ERROR_SUCCESS) 527 goto enum_error; 528 529 bzero(&de, sizeof (netdfs_enumhandle_t)); 530 de.de_level = level; 531 de.de_ntotal = dfs_cache_num(); 532 533 if (param->pref_max_len == NETDFS_MAXPREFLEN || 534 param->pref_max_len > NETDFS_MAXBUFLEN) 535 de.de_prefmaxlen = NETDFS_MAXBUFLEN; 536 else 537 de.de_prefmaxlen = param->pref_max_len; 538 539 de.de_bavail = de.de_prefmaxlen; 540 541 if (param->resume_handle != NULL) { 542 if (*param->resume_handle >= de.de_ntotal) { 543 status = ERROR_NO_MORE_ITEMS; 544 goto enum_error; 545 } 546 de.de_resume = *param->resume_handle; 547 de.de_nskip = de.de_resume; 548 *param->resume_handle = 0; 549 } 550 551 dfs_setpriv(PRIV_ON); 552 553 status = ERROR_NOT_ENOUGH_MEMORY; 554 555 switch (level) { 556 case 1: 557 entsize = sizeof (netdfs_info1_t); 558 de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1); 559 de.de_entries = NDR_NEWN(mxa, netdfs_info1_t, de.de_nmax); 560 if (de.de_entries == NULL) 561 goto enum_error; 562 563 if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) { 564 param->info->iu.info1->info1 = de.de_entries; 565 param->info->iu.info1->count = de.de_nitems; 566 } 567 break; 568 case 2: 569 entsize = sizeof (netdfs_info2_t); 570 de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1); 571 de.de_entries = NDR_NEWN(mxa, netdfs_info2_t, de.de_nmax); 572 if (de.de_entries == NULL) 573 goto enum_error; 574 575 if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) { 576 param->info->iu.info2->info2 = de.de_entries; 577 param->info->iu.info2->count = de.de_nitems; 578 } 579 break; 580 case 3: 581 entsize = sizeof (netdfs_info3_t) + 582 sizeof (netdfs_storage_info_t); 583 de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1); 584 de.de_entries = NDR_NEWN(mxa, netdfs_info3_t, de.de_nmax); 585 if (de.de_entries == NULL) 586 goto enum_error; 587 588 if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) { 589 param->info->iu.info3->info3 = de.de_entries; 590 param->info->iu.info3->count = de.de_nitems; 591 } 592 break; 593 case 4: 594 entsize = sizeof (netdfs_info4_t) + 595 sizeof (netdfs_storage_info_t); 596 de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1); 597 de.de_entries = NDR_NEWN(mxa, netdfs_info4_t, de.de_nmax); 598 if (de.de_entries == NULL) 599 goto enum_error; 600 601 if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) { 602 param->info->iu.info4->info4 = de.de_entries; 603 param->info->iu.info4->count = de.de_nitems; 604 } 605 break; 606 607 case 5: 608 entsize = sizeof (netdfs_info5_t); 609 de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1); 610 de.de_entries = NDR_NEWN(mxa, netdfs_info5_t, de.de_nmax); 611 if (de.de_entries == NULL) 612 goto enum_error; 613 614 if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) { 615 param->info->iu.info5->info5 = de.de_entries; 616 param->info->iu.info5->count = de.de_nitems; 617 } 618 break; 619 620 case 6: 621 entsize = sizeof (netdfs_info6_t) + 622 sizeof (netdfs_storage_info1_t); 623 de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1); 624 de.de_entries = NDR_NEWN(mxa, netdfs_info6_t, de.de_nmax); 625 if (de.de_entries == NULL) 626 goto enum_error; 627 628 if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) { 629 param->info->iu.info6->info6 = de.de_entries; 630 param->info->iu.info6->count = de.de_nitems; 631 } 632 break; 633 634 case 300: 635 entsize = sizeof (netdfs_info300_t); 636 de.de_nmax = MAX((de.de_prefmaxlen / entsize), 1); 637 de.de_entries = NDR_NEWN(mxa, netdfs_info300_t, de.de_nmax); 638 if (de.de_entries == NULL) 639 goto enum_error; 640 641 if ((status = netdfs_enum_common(&de, mxa)) == ERROR_SUCCESS) { 642 param->info->iu.info300->info300 = de.de_entries; 643 param->info->iu.info300->count = de.de_nitems; 644 } 645 break; 646 647 default: 648 status = ERROR_INVALID_PARAMETER; 649 break; 650 } 651 652 if ((status == ERROR_SUCCESS) && (param->resume_handle != NULL)) 653 *param->resume_handle = de.de_resume; 654 655 enum_error: 656 dfs_setpriv(PRIV_OFF); 657 param->status = status; 658 return (NDR_DRC_OK); 659 } 660 661 /* 662 * Renames or moves a DFS link 663 * 664 * Does not need to be supported for DFS version 1 665 * 666 * [MS-DFSNM]: NetrDfsMove (Opnum 6) 667 */ 668 /*ARGSUSED*/ 669 static int 670 netdfs_s_move(void *arg, ndr_xa_t *mxa) 671 { 672 struct netdfs_move *param = arg; 673 674 param->status = ERROR_NOT_SUPPORTED; 675 return (NDR_DRC_OK); 676 } 677 678 /* 679 * According to [MS-DFSNM] spec this operation (opnum 7) is not 680 * used over the wire. 681 */ 682 /*ARGSUSED*/ 683 static int 684 netdfs_s_rename(void *arg, ndr_xa_t *mxa) 685 { 686 struct netdfs_rename *param = arg; 687 688 param->status = ERROR_NOT_SUPPORTED; 689 return (NDR_DRC_OK); 690 } 691 692 /* 693 * Creates a new standalone DFS namespace 694 * 695 * [MS-DFSNM]: NetrDfsAddStdRoot (Opnum 12) 696 */ 697 /*ARGSUSED*/ 698 static int 699 netdfs_s_addstdroot(void *arg, ndr_xa_t *mxa) 700 { 701 struct netdfs_addstdroot *param = arg; 702 const char *share = (const char *)param->share; 703 const char *comment = (const char *)param->comment; 704 705 if (!ndr_is_admin(mxa)) { 706 param->status = ERROR_ACCESS_DENIED; 707 return (NDR_DRC_OK); 708 } 709 710 dfs_setpriv(PRIV_ON); 711 712 /* For now only allow a single standalone namespace */ 713 if (dfs_namespace_count() == 0) { 714 param->status = dfs_namespace_add(share, comment); 715 if (param->status == ERROR_SUCCESS) 716 (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1); 717 } else { 718 param->status = ERROR_NOT_SUPPORTED; 719 } 720 721 dfs_setpriv(PRIV_OFF); 722 return (NDR_DRC_OK); 723 } 724 725 /* 726 * Deletes the specified stand-alone DFS namespace. The DFS namespace can be 727 * removed without first removing all of the links in it. 728 * 729 * [MS-DFSNM]: NetrDfsRemoveStdRoot (Opnum 13) 730 */ 731 /*ARGSUSED*/ 732 static int 733 netdfs_s_remstdroot(void *arg, ndr_xa_t *mxa) 734 { 735 struct netdfs_remstdroot *param = arg; 736 const char *share = (const char *)param->share; 737 738 dfs_setpriv(PRIV_ON); 739 740 if (ndr_is_admin(mxa)) { 741 param->status = dfs_namespace_remove(share); 742 if (param->status == ERROR_SUCCESS) 743 (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 0); 744 } else { 745 param->status = ERROR_ACCESS_DENIED; 746 } 747 748 dfs_setpriv(PRIV_OFF); 749 return (NDR_DRC_OK); 750 } 751 752 /* 753 * Enumerates the DFS roots hosted on a server, or DFS links of a namespace 754 * hosted by the server. Depending on the information level, the targets 755 * associated with the roots and links are also displayed 756 * 757 * Does not need to be supported for DFS version 1 758 * 759 * [MS-DFSNM] NetrDfsEnumEx (Opnum 21) 760 */ 761 /*ARGSUSED*/ 762 static int 763 netdfs_s_enumex(void *arg, ndr_xa_t *mxa) 764 { 765 struct netdfs_enumex *param = arg; 766 767 bzero(param->info, sizeof (struct netdfs_enumex)); 768 param->status = ERROR_NOT_SUPPORTED; 769 return (NDR_DRC_OK); 770 } 771 772 /* 773 * Sets the comment for the DFS link/root. 774 */ 775 static uint32_t 776 netdfs_setinfo_100(dfs_path_t *path, netdfs_info100_t *netinfo) 777 { 778 dfs_info_t info; 779 uint32_t status; 780 char *cmnt = (char *)netinfo->comment; 781 782 bzero(&info, sizeof (dfs_info_t)); 783 if (cmnt != NULL) 784 (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment)); 785 786 if (path->p_type == DFS_OBJECT_LINK) 787 status = dfs_link_setinfo(path->p_fspath, &info, 100); 788 else 789 status = dfs_root_setinfo(path->p_fspath, &info, 100); 790 791 return (status); 792 } 793 794 /* 795 * Sets the state for the DFS root/link or its target. 796 */ 797 static uint32_t 798 netdfs_setinfo_101(dfs_path_t *path, netdfs_info101_t *netinfo, 799 const char *t_server, const char *t_share) 800 { 801 dfs_info_t info; 802 dfs_target_t target; 803 uint32_t status; 804 805 bzero(&info, sizeof (dfs_info_t)); 806 bzero(&target, sizeof (dfs_target_t)); 807 808 if (t_server == NULL && t_share == NULL) { 809 info.i_state = netinfo->state; 810 } else { 811 target.t_state = netinfo->state; 812 (void) strlcpy(target.t_server, t_server, 813 sizeof (target.t_server)); 814 (void) strlcpy(target.t_share, t_share, 815 sizeof (target.t_share)); 816 info.i_targets = ⌖ 817 } 818 819 if (path->p_type == DFS_OBJECT_LINK) 820 status = dfs_link_setinfo(path->p_fspath, &info, 101); 821 else 822 status = dfs_root_setinfo(path->p_fspath, &info, 101); 823 824 return (status); 825 } 826 827 /* 828 * Sets the timeout value of the DFS link/root. 829 */ 830 static uint32_t 831 netdfs_setinfo_102(dfs_path_t *path, netdfs_info102_t *netinfo) 832 { 833 dfs_info_t info; 834 uint32_t status; 835 836 bzero(&info, sizeof (dfs_info_t)); 837 info.i_timeout = netinfo->timeout; 838 839 if (path->p_type == DFS_OBJECT_LINK) 840 status = dfs_link_setinfo(path->p_fspath, &info, 102); 841 else 842 status = dfs_root_setinfo(path->p_fspath, &info, 102); 843 844 return (status); 845 } 846 847 /* 848 * Sets the property flags for the root or link. 849 */ 850 static uint32_t 851 netdfs_setinfo_103(dfs_path_t *path, netdfs_info103_t *netinfo) 852 { 853 dfs_info_t info; 854 uint32_t status; 855 856 bzero(&info, sizeof (dfs_info_t)); 857 info.i_propflags = 858 netinfo->property_flags & netinfo->property_flag_mask; 859 860 if (path->p_type == DFS_OBJECT_LINK) 861 status = dfs_link_setinfo(path->p_fspath, &info, 103); 862 else 863 status = dfs_root_setinfo(path->p_fspath, &info, 103); 864 865 return (status); 866 } 867 868 /* 869 * Sets the target priority rank and class for the root target or link target 870 */ 871 static uint32_t 872 netdfs_setinfo_104(dfs_path_t *path, netdfs_info104_t *netinfo, 873 const char *t_server, const char *t_share) 874 { 875 dfs_info_t info; 876 dfs_target_t target; 877 uint32_t status; 878 879 if ((t_server == NULL) || (t_share == NULL)) 880 return (ERROR_INVALID_PARAMETER); 881 882 bzero(&info, sizeof (dfs_info_t)); 883 bzero(&target, sizeof (dfs_target_t)); 884 885 target.t_priority.p_class = netinfo->priority_class; 886 target.t_priority.p_rank = netinfo->priority_rank; 887 (void) strlcpy(target.t_server, t_server, sizeof (target.t_server)); 888 (void) strlcpy(target.t_share, t_share, sizeof (target.t_share)); 889 info.i_targets = ⌖ 890 891 if (path->p_type == DFS_OBJECT_LINK) 892 status = dfs_link_setinfo(path->p_fspath, &info, 104); 893 else 894 status = dfs_root_setinfo(path->p_fspath, &info, 104); 895 896 return (status); 897 } 898 899 /* 900 * Sets the comment, state, time-out information, and property flags for the 901 * namespace root or link specified in DfsInfo. Does not apply to a root target 902 * or link target. 903 */ 904 static uint32_t 905 netdfs_setinfo_105(dfs_path_t *path, netdfs_info105_t *netinfo) 906 { 907 dfs_info_t info; 908 uint32_t status; 909 char *cmnt = (char *)netinfo->comment; 910 911 bzero(&info, sizeof (dfs_info_t)); 912 913 if (cmnt != NULL) 914 (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment)); 915 info.i_state = netinfo->state; 916 info.i_timeout = netinfo->timeout; 917 info.i_propflags = 918 netinfo->property_flags & netinfo->property_flag_mask; 919 920 if (path->p_type == DFS_OBJECT_LINK) 921 status = dfs_link_setinfo(path->p_fspath, &info, 105); 922 else 923 status = dfs_root_setinfo(path->p_fspath, &info, 105); 924 925 return (status); 926 } 927 928 /* 929 * DFS_STORAGE_INFO: target information 930 */ 931 static uint32_t 932 netdfs_info_storage(netdfs_storage_info_t **sinfo, dfs_info_t *info, 933 ndr_xa_t *mxa, uint32_t *size) 934 { 935 netdfs_storage_info_t *storage; 936 dfs_target_t *target; 937 int i; 938 939 *sinfo = NULL; 940 if (info->i_ntargets == 0) 941 return (ERROR_SUCCESS); 942 943 *sinfo = NDR_NEWN(mxa, netdfs_storage_info_t, info->i_ntargets); 944 if (*sinfo == NULL) 945 return (ERROR_NOT_ENOUGH_MEMORY); 946 947 if (size != NULL) 948 *size += info->i_ntargets * sizeof (netdfs_storage_info_t); 949 950 target = info->i_targets; 951 storage = *sinfo; 952 for (i = 0; i < info->i_ntargets; i++, target++, storage++) { 953 storage->state = target->t_state; 954 storage->server = NDR_STRDUP(mxa, target->t_server); 955 storage->share = NDR_STRDUP(mxa, target->t_share); 956 957 if (storage->server == NULL || storage->share == NULL) 958 return (ERROR_NOT_ENOUGH_MEMORY); 959 960 if (size != NULL) 961 *size += smb_wcequiv_strlen(target->t_server) + 962 smb_wcequiv_strlen(target->t_share); 963 } 964 965 return (ERROR_SUCCESS); 966 } 967 968 /* 969 * DFS_STORAGE_INFO_1: target information 970 */ 971 static uint32_t 972 netdfs_info_storage1(netdfs_storage_info1_t **sinfo, dfs_info_t *info, 973 ndr_xa_t *mxa, uint32_t *size) 974 { 975 netdfs_storage_info1_t *storage; 976 dfs_target_t *target; 977 int i; 978 979 *sinfo = NULL; 980 if (info->i_ntargets == 0) 981 return (ERROR_SUCCESS); 982 983 *sinfo = NDR_NEWN(mxa, netdfs_storage_info1_t, info->i_ntargets); 984 if (*sinfo == NULL) 985 return (ERROR_NOT_ENOUGH_MEMORY); 986 987 if (size != NULL) 988 *size += info->i_ntargets * sizeof (netdfs_storage_info1_t); 989 990 target = info->i_targets; 991 storage = *sinfo; 992 for (i = 0; i < info->i_ntargets; i++, target++, storage++) { 993 storage->state = target->t_state; 994 storage->server = NDR_STRDUP(mxa, target->t_server); 995 storage->share = NDR_STRDUP(mxa, target->t_share); 996 storage->p_class = target->t_priority.p_class; 997 storage->p_rank = target->t_priority.p_rank; 998 storage->p_reserved = 0; 999 1000 if (storage->server == NULL || storage->share == NULL) 1001 return (ERROR_NOT_ENOUGH_MEMORY); 1002 1003 if (size != NULL) 1004 *size += smb_wcequiv_strlen(target->t_server) + 1005 smb_wcequiv_strlen(target->t_share); 1006 } 1007 1008 return (ERROR_SUCCESS); 1009 } 1010 1011 /* 1012 * Sets a DFS_INFO_1 for get/enum response 1013 */ 1014 static uint32_t 1015 netdfs_info_1(netdfs_info1_t *info1, dfs_info_t *info, ndr_xa_t *mxa, 1016 uint32_t *size) 1017 { 1018 info1->entry_path = NDR_STRDUP(mxa, info->i_uncpath); 1019 if (info1->entry_path == NULL) 1020 return (ERROR_NOT_ENOUGH_MEMORY); 1021 1022 if (size != NULL) 1023 *size = sizeof (netdfs_info1_t) + 1024 smb_wcequiv_strlen(info->i_uncpath); 1025 1026 return (ERROR_SUCCESS); 1027 } 1028 1029 /* 1030 * Sets a DFS_INFO_2 for get/enum response 1031 */ 1032 static uint32_t 1033 netdfs_info_2(netdfs_info2_t *info2, dfs_info_t *info, ndr_xa_t *mxa, 1034 uint32_t *size) 1035 { 1036 void *entry_path; 1037 void *comment; 1038 1039 entry_path = NDR_STRDUP(mxa, info->i_uncpath); 1040 comment = NDR_STRDUP(mxa, info->i_comment); 1041 1042 if (entry_path == NULL || comment == NULL) 1043 return (ERROR_NOT_ENOUGH_MEMORY); 1044 1045 info2->entry_path = entry_path; 1046 info2->comment = comment; 1047 info2->state = info->i_state; 1048 info2->n_store = info->i_ntargets; 1049 1050 if (size != NULL) 1051 *size = sizeof (netdfs_info2_t) + 1052 smb_wcequiv_strlen(info->i_uncpath) + 1053 smb_wcequiv_strlen(info->i_comment); 1054 1055 return (ERROR_SUCCESS); 1056 } 1057 1058 /* 1059 * Sets a DFS_INFO_3 for get/enum response 1060 */ 1061 static uint32_t 1062 netdfs_info_3(netdfs_info3_t *info3, dfs_info_t *info, ndr_xa_t *mxa, 1063 uint32_t *size) 1064 { 1065 void *entry_path; 1066 void *comment; 1067 1068 entry_path = NDR_STRDUP(mxa, info->i_uncpath); 1069 comment = NDR_STRDUP(mxa, info->i_comment); 1070 1071 if (entry_path == NULL || comment == NULL) 1072 return (ERROR_NOT_ENOUGH_MEMORY); 1073 1074 info3->entry_path = entry_path; 1075 info3->comment = comment; 1076 info3->state = info->i_state; 1077 info3->n_store = info->i_ntargets; 1078 1079 if (size != NULL) 1080 *size = sizeof (netdfs_info3_t) + 1081 smb_wcequiv_strlen(info->i_uncpath) + 1082 smb_wcequiv_strlen(info->i_comment); 1083 1084 return (netdfs_info_storage(&info3->si, info, mxa, size)); 1085 } 1086 1087 /* 1088 * Sets a DFS_INFO_4 for get/enum response 1089 */ 1090 static uint32_t 1091 netdfs_info_4(netdfs_info4_t *info4, dfs_info_t *info, ndr_xa_t *mxa, 1092 uint32_t *size) 1093 { 1094 void *entry_path; 1095 void *comment; 1096 1097 entry_path = NDR_STRDUP(mxa, info->i_uncpath); 1098 comment = NDR_STRDUP(mxa, info->i_comment); 1099 1100 if (entry_path == NULL || comment == NULL) 1101 return (ERROR_NOT_ENOUGH_MEMORY); 1102 1103 if (!netdfs_guid_fromstr(info->i_guid, &info4->guid)) 1104 return (ERROR_INVALID_DATA); 1105 1106 info4->entry_path = entry_path; 1107 info4->comment = comment; 1108 info4->state = info->i_state; 1109 info4->timeout = info->i_timeout; 1110 info4->n_store = info->i_ntargets; 1111 1112 if (size != NULL) 1113 *size = sizeof (netdfs_info4_t) + 1114 smb_wcequiv_strlen(info->i_uncpath) + 1115 smb_wcequiv_strlen(info->i_comment); 1116 1117 return (netdfs_info_storage(&info4->si, info, mxa, size)); 1118 } 1119 1120 /* 1121 * Sets a DFS_INFO_5 for get/enum response 1122 */ 1123 static uint32_t 1124 netdfs_info_5(netdfs_info5_t *info5, dfs_info_t *info, ndr_xa_t *mxa, 1125 uint32_t *size) 1126 { 1127 void *entry_path; 1128 void *comment; 1129 1130 entry_path = NDR_STRDUP(mxa, info->i_uncpath); 1131 comment = NDR_STRDUP(mxa, info->i_comment); 1132 1133 if (entry_path == NULL || comment == NULL) 1134 return (ERROR_NOT_ENOUGH_MEMORY); 1135 1136 if (!netdfs_guid_fromstr(info->i_guid, &info5->guid)) 1137 return (ERROR_INVALID_DATA); 1138 1139 info5->entry_path = entry_path; 1140 info5->comment = comment; 1141 info5->state = info->i_state; 1142 info5->timeout = info->i_timeout; 1143 info5->flags = info->i_propflags; 1144 info5->metadata_sz = 0; 1145 info5->n_store = info->i_ntargets; 1146 1147 if (size != NULL) 1148 *size = sizeof (netdfs_info5_t) + 1149 smb_wcequiv_strlen(info->i_uncpath) + 1150 smb_wcequiv_strlen(info->i_comment); 1151 1152 return (ERROR_SUCCESS); 1153 } 1154 1155 /* 1156 * Sets a DFS_INFO_6 for get/enum response 1157 */ 1158 static uint32_t 1159 netdfs_info_6(netdfs_info6_t *info6, dfs_info_t *info, ndr_xa_t *mxa, 1160 uint32_t *size) 1161 { 1162 void *entry_path; 1163 void *comment; 1164 1165 entry_path = NDR_STRDUP(mxa, info->i_uncpath); 1166 comment = NDR_STRDUP(mxa, info->i_comment); 1167 1168 if (entry_path == NULL || comment == NULL) 1169 return (ERROR_NOT_ENOUGH_MEMORY); 1170 1171 if (!netdfs_guid_fromstr(info->i_guid, &info6->guid)) 1172 return (ERROR_INVALID_DATA); 1173 1174 info6->entry_path = entry_path; 1175 info6->comment = comment; 1176 info6->state = info->i_state; 1177 info6->timeout = info->i_timeout; 1178 info6->flags = info->i_propflags; 1179 info6->metadata_sz = 0; 1180 info6->n_store = info->i_ntargets; 1181 1182 if (size != NULL) 1183 *size = sizeof (netdfs_info6_t) + 1184 smb_wcequiv_strlen(info->i_uncpath) + 1185 smb_wcequiv_strlen(info->i_comment); 1186 1187 return (netdfs_info_storage1(&info6->si, info, mxa, size)); 1188 } 1189 1190 /* 1191 * Sets a DFS_INFO_100 for Get response 1192 */ 1193 static uint32_t 1194 netdfs_info_100(netdfs_info100_t *info100, dfs_info_t *info, ndr_xa_t *mxa, 1195 uint32_t *size) 1196 { 1197 info100->comment = NDR_STRDUP(mxa, info->i_comment); 1198 if (info100->comment == NULL) 1199 return (ERROR_NOT_ENOUGH_MEMORY); 1200 1201 if (size != NULL) 1202 *size = sizeof (netdfs_info100_t) + 1203 smb_wcequiv_strlen(info->i_comment); 1204 1205 return (ERROR_SUCCESS); 1206 } 1207 1208 /* 1209 * Sets a DFS_INFO_300 for Enum response 1210 */ 1211 static uint32_t 1212 netdfs_info_300(netdfs_info300_t *info300, dfs_info_t *info, ndr_xa_t *mxa, 1213 uint32_t *size) 1214 { 1215 info300->dfsname = NDR_STRDUP(mxa, info->i_uncpath); 1216 if (info300->dfsname == NULL) 1217 return (ERROR_NOT_ENOUGH_MEMORY); 1218 1219 info300->flavor = DFS_VOLUME_FLAVOR_STANDALONE; 1220 if (size != NULL) 1221 *size = sizeof (netdfs_info300_t) + 1222 smb_wcequiv_strlen(info->i_uncpath); 1223 1224 return (ERROR_SUCCESS); 1225 } 1226 1227 /* 1228 * Common enumeration function 1229 */ 1230 static uint32_t 1231 netdfs_enum_common(netdfs_enumhandle_t *de, ndr_xa_t *mxa) 1232 { 1233 netdfs_info1_t *info1 = de->de_entries; 1234 netdfs_info2_t *info2 = de->de_entries; 1235 netdfs_info3_t *info3 = de->de_entries; 1236 netdfs_info4_t *info4 = de->de_entries; 1237 netdfs_info5_t *info5 = de->de_entries; 1238 netdfs_info6_t *info6 = de->de_entries; 1239 netdfs_info300_t *info300 = de->de_entries; 1240 dfs_info_t dfsinfo; 1241 smb_cache_cursor_t cursor; 1242 dfs_nscnode_t nscnode; 1243 uint32_t status; 1244 uint32_t itemsz; 1245 1246 dfs_cache_iterinit(&cursor); 1247 1248 de->de_nitems = 0; 1249 while (dfs_cache_iterate(&cursor, &nscnode)) { 1250 if (de->de_nskip > 0) { 1251 de->de_nskip--; 1252 continue; 1253 } 1254 1255 if (de->de_nitems == de->de_nmax) 1256 break; 1257 1258 status = dfs_cache_getinfo(&nscnode, &dfsinfo, de->de_level); 1259 if (status != ERROR_SUCCESS) 1260 continue; 1261 1262 switch (de->de_level) { 1263 case 1: 1264 status = netdfs_info_1(info1, &dfsinfo, mxa, &itemsz); 1265 info1++; 1266 break; 1267 case 2: 1268 status = netdfs_info_2(info2, &dfsinfo, mxa, &itemsz); 1269 info2++; 1270 break; 1271 case 3: 1272 status = netdfs_info_3(info3, &dfsinfo, mxa, &itemsz); 1273 info3++; 1274 break; 1275 case 4: 1276 status = netdfs_info_4(info4, &dfsinfo, mxa, &itemsz); 1277 info4++; 1278 break; 1279 case 5: 1280 status = netdfs_info_5(info5, &dfsinfo, mxa, &itemsz); 1281 info5++; 1282 break; 1283 case 6: 1284 status = netdfs_info_6(info6, &dfsinfo, mxa, &itemsz); 1285 info6++; 1286 break; 1287 case 300: 1288 status = netdfs_info_300(info300, &dfsinfo, mxa, 1289 &itemsz); 1290 info300++; 1291 break; 1292 default: 1293 status = ERROR_INVALID_LEVEL; 1294 } 1295 1296 dfs_info_free(&dfsinfo); 1297 1298 if (status != ERROR_SUCCESS) 1299 return (status); 1300 1301 if (de->de_nmax == 1) { 1302 de->de_nitems = 1; 1303 break; 1304 } 1305 1306 if (itemsz > de->de_bavail) 1307 break; 1308 1309 de->de_bavail -= itemsz; 1310 de->de_nitems++; 1311 } 1312 1313 de->de_resume += de->de_nitems; 1314 return (ERROR_SUCCESS); 1315 } 1316 1317 /* 1318 * Creates intermediate directories of a link from the root share path. 1319 * 1320 * TODO: directories should be created by smbsrv to get Windows compatible 1321 * ACL inheritance. 1322 */ 1323 static void 1324 netdfs_path_create(const char *path) 1325 { 1326 char dirpath[DFS_PATH_MAX]; 1327 mode_t mode; 1328 char *p; 1329 1330 (void) strlcpy(dirpath, path, DFS_PATH_MAX); 1331 1332 /* drop the link itself from the path */ 1333 if ((p = strrchr(dirpath, '/')) != NULL) { 1334 *p = '\0'; 1335 mode = umask(0); 1336 (void) mkdirp(dirpath, 0777); 1337 (void) umask(mode); 1338 } 1339 } 1340 1341 /* 1342 * Removes empty directories 1343 */ 1344 static void 1345 netdfs_path_remove(smb_unc_t *unc) 1346 { 1347 char rootdir[DFS_PATH_MAX]; 1348 char relpath[DFS_PATH_MAX]; 1349 char dir[DFS_PATH_MAX]; 1350 uint32_t status; 1351 char *p; 1352 1353 status = dfs_namespace_path(unc->unc_share, rootdir, DFS_PATH_MAX); 1354 if ((status == ERROR_SUCCESS) && (chdir(rootdir) == 0)) { 1355 (void) strlcpy(relpath, unc->unc_path, DFS_PATH_MAX); 1356 /* drop the link itself from the path */ 1357 if ((p = strrchr(relpath, '/')) != NULL) { 1358 *p = '\0'; 1359 (void) rmdirp(relpath, dir); 1360 } 1361 } 1362 } 1363 1364 /* 1365 * Converts the guid string into binary format in network byte order. 1366 */ 1367 static boolean_t 1368 netdfs_guid_fromstr(char *guid_str, netdfs_uuid_t *guid) 1369 { 1370 uuid_t uuid; 1371 1372 if (uuid_parse(guid_str, uuid) != 0) 1373 return (B_FALSE); 1374 1375 bcopy(&uuid, guid, sizeof (uuid_t)); 1376 1377 guid->data1 = htonl(guid->data1); 1378 guid->data2 = htons(guid->data2); 1379 guid->data3 = htons(guid->data3); 1380 1381 return (B_TRUE); 1382 } 1383