1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/param.h>
25#include <sys/errno.h>
26#include <sys/stat.h>
27#include <err.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <strings.h>
31#include <stdlib.h>
32#include <sysexits.h>
33#include <pwd.h>
34#include <membership.h>
35
36#include <smbclient/smbclient.h>
37#include <smbclient/smbclient_internal.h>
38#include <smbclient/ntstatus.h>
39
40#include "common.h"
41#include <netsmb/smb.h>
42
43static uint16_t
44uint16FromDictionary(CFDictionaryRef dict, CFStringRef key)
45{
46	CFNumberRef num = CFDictionaryGetValue( dict, key);
47	uint16_t value = 0;
48
49	if( num ) {
50		CFNumberGetValue(num, kCFNumberSInt16Type, &value);
51	}
52	return value;
53}
54
55static void
56fprintfCFString(CFStringRef theString, const char *preStr, Boolean newLn)
57{
58	char prntstr[1024];
59
60	if (theString == NULL) {
61		fprintf(stdout, "%s(NULL)", preStr);
62	} else {
63		CFStringGetCString(theString, prntstr, 1024, kCFStringEncodingUTF8);
64		fprintf(stdout, "%s%s", preStr, prntstr);
65	}
66	if (newLn) {
67		fprintf(stdout, "\n");
68	}
69}
70
71static void
72displayReferralList(CFArrayRef referralList)
73{
74	CFIndex ii, count = (referralList) ? CFArrayGetCount(referralList) : 0;
75
76	if (!referralList) {
77		return;
78	}
79	for (ii = 0; ii < count; ii++) {
80		CFDictionaryRef dict = CFArrayGetValueAtIndex(referralList, ii);
81
82		fprintf(stdout, "     list item %-2zu: ",  ii+1);
83		fprintfCFString(CFDictionaryGetValue(dict, kDFSPath), "Path: ", TRUE);
84		fprintf(stdout, "     list item %-2zu: ",  ii+1);
85		fprintfCFString(CFDictionaryGetValue(dict, kNetworkAddress),
86						"Network Address: ", TRUE);
87		fprintf(stdout, "     list item %-2zu: ",  ii+1);
88		fprintfCFString(CFDictionaryGetValue(dict, kNewReferral),
89						"New Referral: ", TRUE);
90	}
91}
92
93static void
94displayDomainReferralList(CFArrayRef referralList)
95{
96    CFArrayRef expandedNameArray;
97    CFIndex ii, count = (referralList) ? CFArrayGetCount(referralList) : 0;
98
99	if (!referralList) {
100		return;
101	}
102	for (ii = 0; ii < count; ii++) {
103		CFDictionaryRef dict = CFArrayGetValueAtIndex(referralList, ii);
104        CFIndex jj, exandedNameCount;
105
106        expandedNameArray = CFDictionaryGetValue(dict, kExpandedNameArray);
107        exandedNameCount = (expandedNameArray) ? CFArrayGetCount(expandedNameArray) : 0;
108        for (jj = 0; jj < exandedNameCount; jj++) {
109            fprintf(stdout, "                  ");
110            fprintfCFString(CFArrayGetValueAtIndex(expandedNameArray, jj), "ExpandedName: ", TRUE);
111       }
112        fprintf(stdout, "                  ");
113		fprintfCFString(CFDictionaryGetValue(dict, kSpecialName), "SpecialName: ", TRUE);
114		fprintf(stdout, "                  NumberOfExpandedNames: %d\n", uint16FromDictionary(dict, kNumberOfExpandedNames));
115		fprintf(stdout, "                  ServerType: %d\n", uint16FromDictionary(dict, kServerType));
116	}
117}
118
119int
120cmd_dfs(int argc, char *argv[])
121{
122	CFMutableDictionaryRef dfsReferralDict;
123	CFArrayRef dfsServerDictArray;
124	CFArrayRef dfsReferralDictArray;
125	CFIndex ad_count, count, ii;
126	const char *url = NULL;
127	int	opt;
128
129	while ((opt = getopt(argc, argv, "h")) != EOF) {
130		switch(opt){
131			case 'h':
132			default:
133				dfs_usage();
134				/*NOTREACHED*/
135		}
136	}
137
138	if (optind >= argc) {
139		dfs_usage();
140    }
141
142	url = argv[optind];
143	argc -= optind;
144	/* One more check to make sure we have the correct number of arguments */
145	if (argc != 1) {
146		dfs_usage();
147    }
148
149	dfsReferralDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0,
150                                        &kCFTypeDictionaryKeyCallBacks,
151                                        &kCFTypeDictionaryValueCallBacks);
152	if (!dfsReferralDict) {
153		errno = ENOMEM;
154		err(EX_UNAVAILABLE, "internal error");
155	}
156
157	SMBGetDfsReferral(url, dfsReferralDict);
158
159    /* Did we get a list of Domain Controllers from AD? */
160    dfsServerDictArray = CFDictionaryGetValue(dfsReferralDict,
161                                              kDfsADServerArray);
162
163	ad_count = (dfsServerDictArray) ? CFArrayGetCount(dfsServerDictArray) : 0;
164
165	if (ad_count) {
166        fprintf(stdout, "\n");
167        fprintf(stdout, "------------- AD Domain Entries -------------\n");
168
169        for (ii = ad_count - 1; ii >= 0; ii--) {
170            CFStringRef dc = CFArrayGetValueAtIndex(dfsServerDictArray, ii);
171
172            if (dc) {
173                fprintfCFString(dc, "Server Name : ", TRUE);
174            }
175        }
176    }
177
178    /*
179     * Did we get a list of Domain Controllers from the server name that really
180     * was a domain name (ie GET_DFS_REFERRAL)
181     */
182    dfsServerDictArray = CFDictionaryGetValue(dfsReferralDict, kDfsServerArray);
183
184	count = (dfsServerDictArray) ? CFArrayGetCount(dfsServerDictArray) : 0;
185	if (count) {
186        for (ii = count - 1; ii >= 0; ii--) {
187            CFDictionaryRef dict = CFArrayGetValueAtIndex(dfsServerDictArray, ii);
188
189            fprintf(stdout, "\n");
190            fprintf(stdout, "------------- Domain Entry %-2zu -------------\n", count - ii);
191            if (dict) {
192                fprintfCFString(CFDictionaryGetValue(dict, kRequestFileName),
193                                "Domain requested : ", TRUE);
194                displayDomainReferralList(CFDictionaryGetValue(dict, kReferralList));
195            }
196        }
197    }
198
199	if (!ad_count && !count) {
200		fprintf(stdout, "\nNo server entries found\n");
201	}
202
203    dfsReferralDictArray = CFDictionaryGetValue(dfsReferralDict, kDfsReferralArray);
204    count = (dfsReferralDictArray) ? CFArrayGetCount(dfsReferralDictArray) : 0;
205	if (!count) {
206		fprintf(stdout, "\nNo referral entries found\n");
207		goto done;
208	}
209	for (ii = count-1; ii >= 0; ii--) {
210		CFDictionaryRef dict = CFArrayGetValueAtIndex(dfsReferralDictArray, ii);
211
212		fprintf(stdout, "\n");
213		fprintf(stdout, "------------- Entry %-2zu -------------\n", count - ii);
214		if (dict) {
215			fprintfCFString(CFDictionaryGetValue(dict, kRequestFileName),
216							"Referral requested : ", TRUE);
217			displayReferralList(CFDictionaryGetValue(dict, kReferralList));
218		}
219	}
220
221done:
222	fprintf(stdout, "\n");
223	if (verbose) {
224		CFShow(dfsReferralDict);
225	}
226	CFRelease(dfsReferralDict);
227	return 0;
228}
229
230
231void
232dfs_usage(void)
233{
234	fprintf(stderr, "usage: smbutil dfs smb://"
235			"[domain;][user[:password]@]"
236			"server/dfsroot/dfslink\n");
237	exit(1);
238}
239