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