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
netdfs_initialize(void)150 netdfs_initialize(void)
151 {
152 (void) ndr_svc_register(&netdfs_service);
153 dfs_init();
154 }
155
156 void
netdfs_finalize(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
netdfs_s_getver(void * arg,ndr_xa_t * mxa)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
netdfs_s_add(void * arg,ndr_xa_t * mxa)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
netdfs_s_remove(void * arg,ndr_xa_t * mxa)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
netdfs_s_setinfo(void * arg,ndr_xa_t * mxa)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
netdfs_s_getinfo(void * arg,ndr_xa_t * mxa)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
netdfs_s_enum(void * arg,ndr_xa_t * mxa)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
netdfs_s_move(void * arg,ndr_xa_t * mxa)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
netdfs_s_rename(void * arg,ndr_xa_t * mxa)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
netdfs_s_addstdroot(void * arg,ndr_xa_t * mxa)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 /* For now only allow a single standalone namespace */
712 if (dfs_namespace_count() == 0)
713 param->status = dfs_namespace_add(share, comment);
714 else
715 param->status = ERROR_NOT_SUPPORTED;
716 dfs_setpriv(PRIV_OFF);
717
718 return (NDR_DRC_OK);
719 }
720
721 /*
722 * Deletes the specified stand-alone DFS namespace. The DFS namespace can be
723 * removed without first removing all of the links in it.
724 *
725 * [MS-DFSNM]: NetrDfsRemoveStdRoot (Opnum 13)
726 */
727 /*ARGSUSED*/
728 static int
netdfs_s_remstdroot(void * arg,ndr_xa_t * mxa)729 netdfs_s_remstdroot(void *arg, ndr_xa_t *mxa)
730 {
731 struct netdfs_remstdroot *param = arg;
732 const char *share = (const char *)param->share;
733
734 dfs_setpriv(PRIV_ON);
735
736 if (ndr_is_admin(mxa))
737 param->status = dfs_namespace_remove(share);
738 else
739 param->status = ERROR_ACCESS_DENIED;
740
741 dfs_setpriv(PRIV_OFF);
742 return (NDR_DRC_OK);
743 }
744
745 /*
746 * Enumerates the DFS roots hosted on a server, or DFS links of a namespace
747 * hosted by the server. Depending on the information level, the targets
748 * associated with the roots and links are also displayed
749 *
750 * Does not need to be supported for DFS version 1
751 *
752 * [MS-DFSNM] NetrDfsEnumEx (Opnum 21)
753 */
754 /*ARGSUSED*/
755 static int
netdfs_s_enumex(void * arg,ndr_xa_t * mxa)756 netdfs_s_enumex(void *arg, ndr_xa_t *mxa)
757 {
758 struct netdfs_enumex *param = arg;
759
760 bzero(param->info, sizeof (struct netdfs_enumex));
761 param->status = ERROR_NOT_SUPPORTED;
762 return (NDR_DRC_OK);
763 }
764
765 /*
766 * Sets the comment for the DFS link/root.
767 */
768 static uint32_t
netdfs_setinfo_100(dfs_path_t * path,netdfs_info100_t * netinfo)769 netdfs_setinfo_100(dfs_path_t *path, netdfs_info100_t *netinfo)
770 {
771 dfs_info_t info;
772 uint32_t status;
773 char *cmnt = (char *)netinfo->comment;
774
775 bzero(&info, sizeof (dfs_info_t));
776 if (cmnt != NULL)
777 (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment));
778
779 if (path->p_type == DFS_OBJECT_LINK)
780 status = dfs_link_setinfo(path->p_fspath, &info, 100);
781 else
782 status = dfs_root_setinfo(path->p_fspath, &info, 100);
783
784 return (status);
785 }
786
787 /*
788 * Sets the state for the DFS root/link or its target.
789 */
790 static uint32_t
netdfs_setinfo_101(dfs_path_t * path,netdfs_info101_t * netinfo,const char * t_server,const char * t_share)791 netdfs_setinfo_101(dfs_path_t *path, netdfs_info101_t *netinfo,
792 const char *t_server, const char *t_share)
793 {
794 dfs_info_t info;
795 dfs_target_t target;
796 uint32_t status;
797
798 bzero(&info, sizeof (dfs_info_t));
799 bzero(&target, sizeof (dfs_target_t));
800
801 if (t_server == NULL && t_share == NULL) {
802 info.i_state = netinfo->state;
803 } else {
804 target.t_state = netinfo->state;
805 (void) strlcpy(target.t_server, t_server,
806 sizeof (target.t_server));
807 (void) strlcpy(target.t_share, t_share,
808 sizeof (target.t_share));
809 info.i_targets = ⌖
810 }
811
812 if (path->p_type == DFS_OBJECT_LINK)
813 status = dfs_link_setinfo(path->p_fspath, &info, 101);
814 else
815 status = dfs_root_setinfo(path->p_fspath, &info, 101);
816
817 return (status);
818 }
819
820 /*
821 * Sets the timeout value of the DFS link/root.
822 */
823 static uint32_t
netdfs_setinfo_102(dfs_path_t * path,netdfs_info102_t * netinfo)824 netdfs_setinfo_102(dfs_path_t *path, netdfs_info102_t *netinfo)
825 {
826 dfs_info_t info;
827 uint32_t status;
828
829 bzero(&info, sizeof (dfs_info_t));
830 info.i_timeout = netinfo->timeout;
831
832 if (path->p_type == DFS_OBJECT_LINK)
833 status = dfs_link_setinfo(path->p_fspath, &info, 102);
834 else
835 status = dfs_root_setinfo(path->p_fspath, &info, 102);
836
837 return (status);
838 }
839
840 /*
841 * Sets the property flags for the root or link.
842 */
843 static uint32_t
netdfs_setinfo_103(dfs_path_t * path,netdfs_info103_t * netinfo)844 netdfs_setinfo_103(dfs_path_t *path, netdfs_info103_t *netinfo)
845 {
846 dfs_info_t info;
847 uint32_t status;
848
849 bzero(&info, sizeof (dfs_info_t));
850 info.i_propflags =
851 netinfo->property_flags & netinfo->property_flag_mask;
852
853 if (path->p_type == DFS_OBJECT_LINK)
854 status = dfs_link_setinfo(path->p_fspath, &info, 103);
855 else
856 status = dfs_root_setinfo(path->p_fspath, &info, 103);
857
858 return (status);
859 }
860
861 /*
862 * Sets the target priority rank and class for the root target or link target
863 */
864 static uint32_t
netdfs_setinfo_104(dfs_path_t * path,netdfs_info104_t * netinfo,const char * t_server,const char * t_share)865 netdfs_setinfo_104(dfs_path_t *path, netdfs_info104_t *netinfo,
866 const char *t_server, const char *t_share)
867 {
868 dfs_info_t info;
869 dfs_target_t target;
870 uint32_t status;
871
872 if ((t_server == NULL) || (t_share == NULL))
873 return (ERROR_INVALID_PARAMETER);
874
875 if (netinfo->priority_class > DfsGlobalLowPriorityClass)
876 return (ERROR_INVALID_PARAMETER);
877
878 if (netinfo->priority_rank > DFS_PRIORITY_RANK_MAX)
879 return (ERROR_INVALID_PARAMETER);
880
881 bzero(&info, sizeof (dfs_info_t));
882 bzero(&target, sizeof (dfs_target_t));
883
884 target.t_priority.p_class = netinfo->priority_class;
885 target.t_priority.p_rank = netinfo->priority_rank;
886 (void) strlcpy(target.t_server, t_server, sizeof (target.t_server));
887 (void) strlcpy(target.t_share, t_share, sizeof (target.t_share));
888 info.i_targets = ⌖
889
890 if (path->p_type == DFS_OBJECT_LINK)
891 status = dfs_link_setinfo(path->p_fspath, &info, 104);
892 else
893 status = dfs_root_setinfo(path->p_fspath, &info, 104);
894
895 return (status);
896 }
897
898 /*
899 * Sets the comment, state, time-out information, and property flags for the
900 * namespace root or link specified in DfsInfo. Does not apply to a root target
901 * or link target.
902 */
903 static uint32_t
netdfs_setinfo_105(dfs_path_t * path,netdfs_info105_t * netinfo)904 netdfs_setinfo_105(dfs_path_t *path, netdfs_info105_t *netinfo)
905 {
906 dfs_info_t info;
907 uint32_t status, flavor;
908 char *cmnt = (char *)netinfo->comment;
909
910 bzero(&info, sizeof (dfs_info_t));
911
912 flavor = dfs_namespace_getflavor(path->p_unc.unc_share);
913 if (flavor == 0)
914 return (ERROR_INTERNAL_ERROR);
915 info.i_flavor = flavor;
916
917 if (cmnt != NULL)
918 (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment));
919 info.i_state = netinfo->state;
920 info.i_timeout = netinfo->timeout;
921 info.i_propflag_mask = netinfo->property_flag_mask;
922 info.i_propflags =
923 netinfo->property_flags & netinfo->property_flag_mask;
924
925 if (path->p_type == DFS_OBJECT_LINK)
926 status = dfs_link_setinfo(path->p_fspath, &info, 105);
927 else
928 status = dfs_root_setinfo(path->p_fspath, &info, 105);
929
930 return (status);
931 }
932
933 /*
934 * DFS_STORAGE_INFO: target information
935 */
936 static uint32_t
netdfs_info_storage(netdfs_storage_info_t ** sinfo,dfs_info_t * info,ndr_xa_t * mxa,uint32_t * size)937 netdfs_info_storage(netdfs_storage_info_t **sinfo, dfs_info_t *info,
938 ndr_xa_t *mxa, uint32_t *size)
939 {
940 netdfs_storage_info_t *storage;
941 dfs_target_t *target;
942 int i;
943
944 *sinfo = NULL;
945 if (info->i_ntargets == 0)
946 return (ERROR_SUCCESS);
947
948 *sinfo = NDR_NEWN(mxa, netdfs_storage_info_t, info->i_ntargets);
949 if (*sinfo == NULL)
950 return (ERROR_NOT_ENOUGH_MEMORY);
951
952 if (size != NULL)
953 *size += info->i_ntargets * sizeof (netdfs_storage_info_t);
954
955 target = info->i_targets;
956 storage = *sinfo;
957 for (i = 0; i < info->i_ntargets; i++, target++, storage++) {
958 storage->state = target->t_state;
959 storage->server = NDR_STRDUP(mxa, target->t_server);
960 storage->share = NDR_STRDUP(mxa, target->t_share);
961
962 if (storage->server == NULL || storage->share == NULL)
963 return (ERROR_NOT_ENOUGH_MEMORY);
964
965 if (size != NULL)
966 *size += smb_wcequiv_strlen(target->t_server) +
967 smb_wcequiv_strlen(target->t_share);
968 }
969
970 return (ERROR_SUCCESS);
971 }
972
973 /*
974 * DFS_STORAGE_INFO_1: target information
975 */
976 static uint32_t
netdfs_info_storage1(netdfs_storage_info1_t ** sinfo,dfs_info_t * info,ndr_xa_t * mxa,uint32_t * size)977 netdfs_info_storage1(netdfs_storage_info1_t **sinfo, dfs_info_t *info,
978 ndr_xa_t *mxa, uint32_t *size)
979 {
980 netdfs_storage_info1_t *storage;
981 dfs_target_t *target;
982 int i;
983
984 *sinfo = NULL;
985 if (info->i_ntargets == 0)
986 return (ERROR_SUCCESS);
987
988 *sinfo = NDR_NEWN(mxa, netdfs_storage_info1_t, info->i_ntargets);
989 if (*sinfo == NULL)
990 return (ERROR_NOT_ENOUGH_MEMORY);
991
992 if (size != NULL)
993 *size += info->i_ntargets * sizeof (netdfs_storage_info1_t);
994
995 target = info->i_targets;
996 storage = *sinfo;
997 for (i = 0; i < info->i_ntargets; i++, target++, storage++) {
998 storage->state = target->t_state;
999 storage->server = NDR_STRDUP(mxa, target->t_server);
1000 storage->share = NDR_STRDUP(mxa, target->t_share);
1001 storage->p_class = target->t_priority.p_class;
1002 storage->p_rank = target->t_priority.p_rank;
1003 storage->p_reserved = 0;
1004
1005 if (storage->server == NULL || storage->share == NULL)
1006 return (ERROR_NOT_ENOUGH_MEMORY);
1007
1008 if (size != NULL)
1009 *size += smb_wcequiv_strlen(target->t_server) +
1010 smb_wcequiv_strlen(target->t_share);
1011 }
1012
1013 return (ERROR_SUCCESS);
1014 }
1015
1016 /*
1017 * Sets a DFS_INFO_1 for get/enum response
1018 */
1019 static uint32_t
netdfs_info_1(netdfs_info1_t * info1,dfs_info_t * info,ndr_xa_t * mxa,uint32_t * size)1020 netdfs_info_1(netdfs_info1_t *info1, dfs_info_t *info, ndr_xa_t *mxa,
1021 uint32_t *size)
1022 {
1023 info1->entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1024 if (info1->entry_path == NULL)
1025 return (ERROR_NOT_ENOUGH_MEMORY);
1026
1027 if (size != NULL)
1028 *size = sizeof (netdfs_info1_t) +
1029 smb_wcequiv_strlen(info->i_uncpath);
1030
1031 return (ERROR_SUCCESS);
1032 }
1033
1034 /*
1035 * Sets a DFS_INFO_2 for get/enum response
1036 */
1037 static uint32_t
netdfs_info_2(netdfs_info2_t * info2,dfs_info_t * info,ndr_xa_t * mxa,uint32_t * size)1038 netdfs_info_2(netdfs_info2_t *info2, dfs_info_t *info, ndr_xa_t *mxa,
1039 uint32_t *size)
1040 {
1041 void *entry_path;
1042 void *comment;
1043
1044 entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1045 comment = NDR_STRDUP(mxa, info->i_comment);
1046
1047 if (entry_path == NULL || comment == NULL)
1048 return (ERROR_NOT_ENOUGH_MEMORY);
1049
1050 info2->entry_path = entry_path;
1051 info2->comment = comment;
1052 info2->state = info->i_state;
1053 info2->n_store = info->i_ntargets;
1054
1055 if (size != NULL)
1056 *size = sizeof (netdfs_info2_t) +
1057 smb_wcequiv_strlen(info->i_uncpath) +
1058 smb_wcequiv_strlen(info->i_comment);
1059
1060 return (ERROR_SUCCESS);
1061 }
1062
1063 /*
1064 * Sets a DFS_INFO_3 for get/enum response
1065 */
1066 static uint32_t
netdfs_info_3(netdfs_info3_t * info3,dfs_info_t * info,ndr_xa_t * mxa,uint32_t * size)1067 netdfs_info_3(netdfs_info3_t *info3, dfs_info_t *info, ndr_xa_t *mxa,
1068 uint32_t *size)
1069 {
1070 void *entry_path;
1071 void *comment;
1072
1073 entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1074 comment = NDR_STRDUP(mxa, info->i_comment);
1075
1076 if (entry_path == NULL || comment == NULL)
1077 return (ERROR_NOT_ENOUGH_MEMORY);
1078
1079 info3->entry_path = entry_path;
1080 info3->comment = comment;
1081 info3->state = info->i_state;
1082 info3->n_store = info->i_ntargets;
1083
1084 if (size != NULL)
1085 *size = sizeof (netdfs_info3_t) +
1086 smb_wcequiv_strlen(info->i_uncpath) +
1087 smb_wcequiv_strlen(info->i_comment);
1088
1089 return (netdfs_info_storage(&info3->si, info, mxa, size));
1090 }
1091
1092 /*
1093 * Sets a DFS_INFO_4 for get/enum response
1094 */
1095 static uint32_t
netdfs_info_4(netdfs_info4_t * info4,dfs_info_t * info,ndr_xa_t * mxa,uint32_t * size)1096 netdfs_info_4(netdfs_info4_t *info4, dfs_info_t *info, ndr_xa_t *mxa,
1097 uint32_t *size)
1098 {
1099 void *entry_path;
1100 void *comment;
1101
1102 entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1103 comment = NDR_STRDUP(mxa, info->i_comment);
1104
1105 if (entry_path == NULL || comment == NULL)
1106 return (ERROR_NOT_ENOUGH_MEMORY);
1107
1108 if (!netdfs_guid_fromstr(info->i_guid, &info4->guid))
1109 return (ERROR_INVALID_DATA);
1110
1111 info4->entry_path = entry_path;
1112 info4->comment = comment;
1113 info4->state = info->i_state;
1114 info4->timeout = info->i_timeout;
1115 info4->n_store = info->i_ntargets;
1116
1117 if (size != NULL)
1118 *size = sizeof (netdfs_info4_t) +
1119 smb_wcequiv_strlen(info->i_uncpath) +
1120 smb_wcequiv_strlen(info->i_comment);
1121
1122 return (netdfs_info_storage(&info4->si, info, mxa, size));
1123 }
1124
1125 /*
1126 * Sets a DFS_INFO_5 for get/enum response
1127 */
1128 static uint32_t
netdfs_info_5(netdfs_info5_t * info5,dfs_info_t * info,ndr_xa_t * mxa,uint32_t * size)1129 netdfs_info_5(netdfs_info5_t *info5, dfs_info_t *info, ndr_xa_t *mxa,
1130 uint32_t *size)
1131 {
1132 void *entry_path;
1133 void *comment;
1134
1135 entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1136 comment = NDR_STRDUP(mxa, info->i_comment);
1137
1138 if (entry_path == NULL || comment == NULL)
1139 return (ERROR_NOT_ENOUGH_MEMORY);
1140
1141 if (!netdfs_guid_fromstr(info->i_guid, &info5->guid))
1142 return (ERROR_INVALID_DATA);
1143
1144 info5->entry_path = entry_path;
1145 info5->comment = comment;
1146 info5->state = info->i_state;
1147 info5->timeout = info->i_timeout;
1148 info5->flags = info->i_propflags;
1149 info5->metadata_sz = 0;
1150 info5->n_store = info->i_ntargets;
1151
1152 if (size != NULL)
1153 *size = sizeof (netdfs_info5_t) +
1154 smb_wcequiv_strlen(info->i_uncpath) +
1155 smb_wcequiv_strlen(info->i_comment);
1156
1157 return (ERROR_SUCCESS);
1158 }
1159
1160 /*
1161 * Sets a DFS_INFO_6 for get/enum response
1162 */
1163 static uint32_t
netdfs_info_6(netdfs_info6_t * info6,dfs_info_t * info,ndr_xa_t * mxa,uint32_t * size)1164 netdfs_info_6(netdfs_info6_t *info6, dfs_info_t *info, ndr_xa_t *mxa,
1165 uint32_t *size)
1166 {
1167 void *entry_path;
1168 void *comment;
1169
1170 entry_path = NDR_STRDUP(mxa, info->i_uncpath);
1171 comment = NDR_STRDUP(mxa, info->i_comment);
1172
1173 if (entry_path == NULL || comment == NULL)
1174 return (ERROR_NOT_ENOUGH_MEMORY);
1175
1176 if (!netdfs_guid_fromstr(info->i_guid, &info6->guid))
1177 return (ERROR_INVALID_DATA);
1178
1179 info6->entry_path = entry_path;
1180 info6->comment = comment;
1181 info6->state = info->i_state;
1182 info6->timeout = info->i_timeout;
1183 info6->flags = info->i_propflags;
1184 info6->metadata_sz = 0;
1185 info6->n_store = info->i_ntargets;
1186
1187 if (size != NULL)
1188 *size = sizeof (netdfs_info6_t) +
1189 smb_wcequiv_strlen(info->i_uncpath) +
1190 smb_wcequiv_strlen(info->i_comment);
1191
1192 return (netdfs_info_storage1(&info6->si, info, mxa, size));
1193 }
1194
1195 /*
1196 * Sets a DFS_INFO_100 for Get response
1197 */
1198 static uint32_t
netdfs_info_100(netdfs_info100_t * info100,dfs_info_t * info,ndr_xa_t * mxa,uint32_t * size)1199 netdfs_info_100(netdfs_info100_t *info100, dfs_info_t *info, ndr_xa_t *mxa,
1200 uint32_t *size)
1201 {
1202 info100->comment = NDR_STRDUP(mxa, info->i_comment);
1203 if (info100->comment == NULL)
1204 return (ERROR_NOT_ENOUGH_MEMORY);
1205
1206 if (size != NULL)
1207 *size = sizeof (netdfs_info100_t) +
1208 smb_wcequiv_strlen(info->i_comment);
1209
1210 return (ERROR_SUCCESS);
1211 }
1212
1213 /*
1214 * Sets a DFS_INFO_300 for Enum response
1215 */
1216 static uint32_t
netdfs_info_300(netdfs_info300_t * info300,dfs_info_t * info,ndr_xa_t * mxa,uint32_t * size)1217 netdfs_info_300(netdfs_info300_t *info300, dfs_info_t *info, ndr_xa_t *mxa,
1218 uint32_t *size)
1219 {
1220 info300->dfsname = NDR_STRDUP(mxa, info->i_uncpath);
1221 if (info300->dfsname == NULL)
1222 return (ERROR_NOT_ENOUGH_MEMORY);
1223
1224 info300->flavor = DFS_VOLUME_FLAVOR_STANDALONE;
1225 if (size != NULL)
1226 *size = sizeof (netdfs_info300_t) +
1227 smb_wcequiv_strlen(info->i_uncpath);
1228
1229 return (ERROR_SUCCESS);
1230 }
1231
1232 /*
1233 * Common enumeration function
1234 */
1235 static uint32_t
netdfs_enum_common(netdfs_enumhandle_t * de,ndr_xa_t * mxa)1236 netdfs_enum_common(netdfs_enumhandle_t *de, ndr_xa_t *mxa)
1237 {
1238 netdfs_info1_t *info1 = de->de_entries;
1239 netdfs_info2_t *info2 = de->de_entries;
1240 netdfs_info3_t *info3 = de->de_entries;
1241 netdfs_info4_t *info4 = de->de_entries;
1242 netdfs_info5_t *info5 = de->de_entries;
1243 netdfs_info6_t *info6 = de->de_entries;
1244 netdfs_info300_t *info300 = de->de_entries;
1245 dfs_info_t dfsinfo;
1246 smb_cache_cursor_t cursor;
1247 dfs_nscnode_t nscnode;
1248 uint32_t status;
1249 uint32_t itemsz;
1250
1251 dfs_cache_iterinit(&cursor);
1252
1253 de->de_nitems = 0;
1254 while (dfs_cache_iterate(&cursor, &nscnode)) {
1255 if (de->de_nskip > 0) {
1256 de->de_nskip--;
1257 continue;
1258 }
1259
1260 if (de->de_nitems == de->de_nmax)
1261 break;
1262
1263 status = dfs_cache_getinfo(&nscnode, &dfsinfo, de->de_level);
1264 if (status != ERROR_SUCCESS)
1265 continue;
1266
1267 switch (de->de_level) {
1268 case 1:
1269 status = netdfs_info_1(info1, &dfsinfo, mxa, &itemsz);
1270 info1++;
1271 break;
1272 case 2:
1273 status = netdfs_info_2(info2, &dfsinfo, mxa, &itemsz);
1274 info2++;
1275 break;
1276 case 3:
1277 status = netdfs_info_3(info3, &dfsinfo, mxa, &itemsz);
1278 info3++;
1279 break;
1280 case 4:
1281 status = netdfs_info_4(info4, &dfsinfo, mxa, &itemsz);
1282 info4++;
1283 break;
1284 case 5:
1285 status = netdfs_info_5(info5, &dfsinfo, mxa, &itemsz);
1286 info5++;
1287 break;
1288 case 6:
1289 status = netdfs_info_6(info6, &dfsinfo, mxa, &itemsz);
1290 info6++;
1291 break;
1292 case 300:
1293 status = netdfs_info_300(info300, &dfsinfo, mxa,
1294 &itemsz);
1295 info300++;
1296 break;
1297 default:
1298 status = ERROR_INVALID_LEVEL;
1299 }
1300
1301 dfs_info_free(&dfsinfo);
1302
1303 if (status != ERROR_SUCCESS)
1304 return (status);
1305
1306 if (de->de_nmax == 1) {
1307 de->de_nitems = 1;
1308 break;
1309 }
1310
1311 if (itemsz > de->de_bavail)
1312 break;
1313
1314 de->de_bavail -= itemsz;
1315 de->de_nitems++;
1316 }
1317
1318 de->de_resume += de->de_nitems;
1319 return (ERROR_SUCCESS);
1320 }
1321
1322 /*
1323 * Creates intermediate directories of a link from the root share path.
1324 *
1325 * TODO: directories should be created by smbsrv to get Windows compatible
1326 * ACL inheritance.
1327 */
1328 static void
netdfs_path_create(const char * path)1329 netdfs_path_create(const char *path)
1330 {
1331 char dirpath[DFS_PATH_MAX];
1332 mode_t mode;
1333 char *p;
1334
1335 (void) strlcpy(dirpath, path, DFS_PATH_MAX);
1336
1337 /* drop the link itself from the path */
1338 if ((p = strrchr(dirpath, '/')) != NULL) {
1339 *p = '\0';
1340 mode = umask(0);
1341 (void) mkdirp(dirpath, 0777);
1342 (void) umask(mode);
1343 }
1344 }
1345
1346 /*
1347 * Removes empty directories
1348 */
1349 static void
netdfs_path_remove(smb_unc_t * unc)1350 netdfs_path_remove(smb_unc_t *unc)
1351 {
1352 char rootdir[DFS_PATH_MAX];
1353 char relpath[DFS_PATH_MAX];
1354 char dir[DFS_PATH_MAX];
1355 uint32_t status;
1356 char *p;
1357
1358 status = dfs_namespace_path(unc->unc_share, rootdir, DFS_PATH_MAX);
1359 if ((status == ERROR_SUCCESS) && (chdir(rootdir) == 0)) {
1360 (void) strlcpy(relpath, unc->unc_path, DFS_PATH_MAX);
1361 /* drop the link itself from the path */
1362 if ((p = strrchr(relpath, '/')) != NULL) {
1363 *p = '\0';
1364 (void) rmdirp(relpath, dir);
1365 }
1366 }
1367 }
1368
1369 /*
1370 * Converts the guid string into binary format in network byte order.
1371 */
1372 static boolean_t
netdfs_guid_fromstr(char * guid_str,netdfs_uuid_t * guid)1373 netdfs_guid_fromstr(char *guid_str, netdfs_uuid_t *guid)
1374 {
1375 uuid_t uuid;
1376
1377 if (uuid_parse(guid_str, uuid) != 0)
1378 return (B_FALSE);
1379
1380 bcopy(&uuid, guid, sizeof (uuid_t));
1381
1382 guid->data1 = htonl(guid->data1);
1383 guid->data2 = htons(guid->data2);
1384 guid->data3 = htons(guid->data3);
1385
1386 return (B_TRUE);
1387 }
1388