1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include	<stdio.h>
19#include	<stdlib.h>
20
21#include	"CommonServices.h"
22#include	"DebugServices.h"
23
24#include	<guiddef.h>
25#include	<ws2spi.h>
26
27//===========================================================================================================================
28//	Prototypes
29//===========================================================================================================================
30
31int  					main( int argc, char *argv[] );
32DEBUG_LOCAL void		Usage( void );
33DEBUG_LOCAL int			ProcessArgs( int argc, char *argv[] );
34DEBUG_LOCAL OSStatus	InstallNSP( const char *inName, const char *inGUID, const char *inPath );
35DEBUG_LOCAL OSStatus	RemoveNSP( const char *inGUID );
36DEBUG_LOCAL OSStatus	EnableNSP( const char *inGUID, BOOL inEnable );
37DEBUG_LOCAL OSStatus	ListNameSpaces( void );
38DEBUG_LOCAL OSStatus	ReorderNameSpaces( void );
39
40DEBUG_LOCAL WCHAR *		CharToWCharString( const char *inCharString, WCHAR *outWCharString );
41DEBUG_LOCAL char *		GUIDtoString( const GUID *inGUID, char *outString );
42DEBUG_LOCAL OSStatus	StringToGUID( const char *inCharString, GUID *outGUID );
43
44DEBUG_LOCAL BOOL gToolQuietMode = FALSE;
45
46//===========================================================================================================================
47//	main
48//===========================================================================================================================
49
50int main( int argc, char *argv[] )
51{
52	OSStatus		err;
53
54	debug_initialize( kDebugOutputTypeMetaConsole );
55	debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
56
57	err = ProcessArgs( argc, argv );
58	return( (int) err );
59}
60
61//===========================================================================================================================
62//	Usage
63//===========================================================================================================================
64
65DEBUG_LOCAL void	Usage( void )
66{
67	fprintf( stderr, "\n" );
68	fprintf( stderr, "NSP Tool 1.0d1\n" );
69	fprintf( stderr, "  Name Space Provider Tool\n" );
70	fprintf( stderr, "\n" );
71
72	fprintf( stderr, "  -install <name> <guid> <path>   - Installs a Name Space Provider\n" );
73	fprintf( stderr, "\n" );
74	fprintf( stderr, "      <name> Name of the NSP\n" );
75	fprintf( stderr, "      <guid> GUID of the NSP\n" );
76	fprintf( stderr, "      <path> Path to the NSP file\n" );
77	fprintf( stderr, "\n" );
78
79	fprintf( stderr, "  -remove <guid>                  - Removes a Name Space Provider\n" );
80	fprintf( stderr, "\n" );
81	fprintf( stderr, "      <guid> GUID of the NSP\n" );
82	fprintf( stderr, "\n" );
83
84	fprintf( stderr, "  -enable/-disable <guid>         - Enables or Disables a Name Space Provider\n" );
85	fprintf( stderr, "\n" );
86	fprintf( stderr, "      <guid> GUID of the NSP\n" );
87	fprintf( stderr, "\n" );
88
89	fprintf( stderr, "  -list                           - Lists Name Space Providers\n" );
90	fprintf( stderr, "  -reorder                        - Reorders Name Space Providers\n" );
91	fprintf( stderr, "  -q                              - Enable quiet mode\n" );
92	fprintf( stderr, "  -h[elp]                         - Help\n" );
93	fprintf( stderr, "\n" );
94}
95
96//===========================================================================================================================
97//	ProcessArgs
98//===========================================================================================================================
99
100DEBUG_LOCAL int ProcessArgs( int argc, char* argv[] )
101{
102	OSStatus			err;
103	int					i;
104	const char *		name;
105	const char *		guid;
106	const char *		path;
107
108	if( argc <= 1 )
109	{
110		Usage();
111		err = 0;
112		goto exit;
113	}
114	for( i = 1; i < argc; ++i )
115	{
116		if( strcmp( argv[ i ], "-install" ) == 0 )
117		{
118			// Install
119
120			if( argc <= ( i + 3 ) )
121			{
122				fprintf( stderr, "\n### ERROR: missing arguments for %s\n\n", argv[ i ] );
123				Usage();
124				err = kParamErr;
125				goto exit;
126			}
127			name = argv[ ++i ];
128			guid = argv[ ++i ];
129			path = argv[ ++i ];
130
131			if( *name == '\0' )
132			{
133				name = "DotLocalNSP";
134			}
135			if( *guid == '\0' )
136			{
137				guid = "B600E6E9-553B-4a19-8696-335E5C896153";
138			}
139
140			err = InstallNSP( name, guid, path );
141			require_noerr( err, exit );
142		}
143		else if( strcmp( argv[ i ], "-remove" ) == 0 )
144		{
145			// Remove
146
147			if( argc <= ( i + 1 ) )
148			{
149				fprintf( stderr, "\n### ERROR: missing arguments for %s\n\n", argv[ i ] );
150				Usage();
151				err = kParamErr;
152				goto exit;
153			}
154			guid = argv[ ++i ];
155			if( *guid == '\0' )
156			{
157				guid = "B600E6E9-553B-4a19-8696-335E5C896153";
158			}
159
160			err = RemoveNSP( guid );
161			require_noerr( err, exit );
162		}
163		else if( ( strcmp( argv[ i ], "-enable" )  == 0 ) ||
164				 ( strcmp( argv[ i ], "-disable" ) == 0 ) )
165		{
166			BOOL		enable;
167
168			// Enable/Disable
169
170			enable = ( strcmp( argv[ i ], "-enable" ) == 0 );
171			if( argc <= ( i + 1 ) )
172			{
173				fprintf( stderr, "\n### ERROR: missing arguments for %s\n\n", argv[ i ] );
174				Usage();
175				err = kParamErr;
176				goto exit;
177			}
178			guid = argv[ ++i ];
179
180			err = EnableNSP( guid, enable );
181			require_noerr( err, exit );
182		}
183		else if( strcmp( argv[ i ], "-list" ) == 0 )
184		{
185			// List
186
187			err = ListNameSpaces();
188			require_noerr( err, exit );
189		}
190		else if( strcmp( argv[ i ], "-reorder" ) == 0 )
191		{
192			// Reorder
193
194			err = ReorderNameSpaces();
195			require_noerr( err, exit );
196		}
197		else if( strcmp( argv[ i ], "-q" ) == 0 )
198		{
199			gToolQuietMode = TRUE;
200		}
201		else if( ( strcmp( argv[ i ], "-help" ) == 0 ) ||
202				 ( strcmp( argv[ i ], "-h" ) == 0 ) )
203		{
204			// Help
205
206			Usage();
207			err = 0;
208			goto exit;
209		}
210		else
211		{
212			fprintf( stderr, "\n### ERROR: unknown argment: \"%s\"\n\n", argv[ i ] );
213			Usage();
214			err = kParamErr;
215			goto exit;
216		}
217	}
218	err = kNoErr;
219
220exit:
221	return( err );
222}
223
224#if 0
225#pragma mark -
226#endif
227
228//===========================================================================================================================
229//	InstallNSP
230//===========================================================================================================================
231
232OSStatus	InstallNSP( const char *inName, const char *inGUID, const char *inPath )
233{
234	OSStatus		err;
235	size_t			size;
236	WSADATA			wsd;
237	WCHAR			name[ 256 ];
238	GUID			guid;
239	WCHAR			path[ MAX_PATH ];
240
241	require_action( inName && ( *inName != '\0' ), exit, err = kParamErr );
242	require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
243	require_action( inPath && ( *inPath != '\0' ), exit, err = kParamErr );
244
245	size = strlen( inName );
246	require_action( size < sizeof_array( name ), exit, err = kSizeErr );
247	CharToWCharString( inName, name );
248
249	err = StringToGUID( inGUID, &guid );
250	require_noerr( err, exit );
251
252	size = strlen( inPath );
253	require_action( size < sizeof_array( path ), exit, err = kSizeErr );
254	CharToWCharString( inPath, path );
255
256	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
257	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
258	require_noerr( err, exit );
259
260	err = WSCInstallNameSpace( name, path, NS_DNS, 1, &guid );
261	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
262	WSACleanup();
263	require_noerr( err, exit );
264
265	if (!gToolQuietMode)
266	{
267		fprintf( stderr, "Installed NSP \"%s\" (%s) at %s\n", inName, inGUID, inPath );
268	}
269
270exit:
271	if( err != kNoErr )
272	{
273		fprintf( stderr, "### FAILED (%d) to install \"%s\" (%s) Name Space Provider at %s\n", err, inName, inGUID, inPath );
274	}
275	return( err );
276}
277
278//===========================================================================================================================
279//	RemoveNSP
280//===========================================================================================================================
281
282DEBUG_LOCAL OSStatus	RemoveNSP( const char *inGUID )
283{
284	OSStatus		err;
285	WSADATA			wsd;
286	GUID			guid;
287
288	require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
289
290	err = StringToGUID( inGUID, &guid );
291	require_noerr( err, exit );
292
293	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
294	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
295	require_noerr( err, exit );
296
297	err = WSCUnInstallNameSpace( &guid );
298	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
299	WSACleanup();
300	require_noerr( err, exit );
301
302	if (!gToolQuietMode)
303	{
304		fprintf( stderr, "Removed NSP %s\n", inGUID );
305	}
306
307exit:
308	if( err != kNoErr )
309	{
310		fprintf( stderr, "### FAILED (%d) to remove %s Name Space Provider\n", err, inGUID );
311	}
312	return( err );
313}
314
315//===========================================================================================================================
316//	EnableNSP
317//===========================================================================================================================
318
319DEBUG_LOCAL OSStatus	EnableNSP( const char *inGUID, BOOL inEnable )
320{
321	OSStatus		err;
322	WSADATA			wsd;
323	GUID			guid;
324
325	require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
326
327	err = StringToGUID( inGUID, &guid );
328	require_noerr( err, exit );
329
330	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
331	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
332	require_noerr( err, exit );
333
334	err = WSCEnableNSProvider( &guid, inEnable );
335	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
336	WSACleanup();
337	require_noerr( err, exit );
338
339	if (!gToolQuietMode)
340	{
341		fprintf( stderr, "Removed NSP %s\n", inGUID );
342	}
343
344exit:
345	if( err != kNoErr )
346	{
347		fprintf( stderr, "### FAILED (%d) to remove %s Name Space Provider\n", err, inGUID );
348	}
349	return( err );
350}
351
352//===========================================================================================================================
353//	ListNameSpaces
354//===========================================================================================================================
355
356DEBUG_LOCAL OSStatus	ListNameSpaces( void )
357{
358	OSStatus				err;
359	WSADATA					wsd;
360	bool					started;
361	int						n;
362	int						i;
363	DWORD					size;
364	WSANAMESPACE_INFO *		array;
365	char					s[ 256 ];
366
367	array 	= NULL;
368	started	= false;
369
370	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
371	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
372	require_noerr( err, exit );
373	started = true;
374
375	// Build an array of all the NSPs. Call it first with NULL to get the size, allocate a buffer, then get them into it.
376
377	size = 0;
378	n = WSAEnumNameSpaceProviders( &size, NULL );
379	err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
380	require_action( err == WSAEFAULT, exit, err = kUnknownErr );
381
382	array = (WSANAMESPACE_INFO *) malloc( size );
383	require_action( array, exit, err = kNoMemoryErr );
384
385	n = WSAEnumNameSpaceProviders( &size, array );
386	err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
387	require_noerr( err, exit );
388
389	fprintf( stdout, "\n" );
390	for( i = 0; i < n; ++i )
391	{
392		fprintf( stdout, "Name Space %d\n", i + 1 );
393		fprintf( stdout, "    NSProviderId:   %s\n", GUIDtoString( &array[ i ].NSProviderId, s ) );
394		fprintf( stdout, "    dwNameSpace:    %d\n", array[ i ].dwNameSpace );
395		fprintf( stdout, "    fActive:        %s\n", array[ i ].fActive ? "YES" : "NO" );
396		fprintf( stdout, "    dwVersion:      %d\n", array[ i ].dwVersion );
397		fprintf( stdout, "    lpszIdentifier: \"%s\"\n", array[ i ].lpszIdentifier );
398		fprintf( stdout, "\n" );
399	}
400	err = kNoErr;
401
402exit:
403	if( array )
404	{
405		free( array );
406	}
407	if( started )
408	{
409		WSACleanup();
410	}
411	if( err != kNoErr )
412	{
413		fprintf( stderr, "### FAILED (%d) to list Name Space Providers\n", err );
414	}
415	return( err );
416}
417
418//===========================================================================================================================
419//	ReorderNameSpaces
420//===========================================================================================================================
421
422DEBUG_LOCAL OSStatus	ReorderNameSpaces( void )
423{
424	OSStatus				err;
425	WSADATA					wsd;
426	bool					started;
427	int						n;
428	int						i;
429	DWORD					size;
430	WSANAMESPACE_INFO *		array;
431	WCHAR					name[ 256 ];
432	WCHAR					path[ MAX_PATH ];
433
434	array 	= NULL;
435	started	= false;
436
437	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
438	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
439	require_noerr( err, exit );
440	started = true;
441
442	// Build an array of all the NSPs. Call it first with NULL to get the size, allocate a buffer, then get them into it.
443
444	size = 0;
445	n = WSAEnumNameSpaceProviders( &size, NULL );
446	err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
447	require_action( err == WSAEFAULT, exit, err = kUnknownErr );
448
449	array = (WSANAMESPACE_INFO *) malloc( size );
450	require_action( array, exit, err = kNoMemoryErr );
451
452	n = WSAEnumNameSpaceProviders( &size, array );
453	err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
454	require_noerr( err, exit );
455
456	// Find the "Tcpip" NSP.
457
458	for( i = 0; i < n; ++i )
459	{
460		if( strcmp( array[ i ].lpszIdentifier, "Tcpip" ) == 0 )
461		{
462			break;
463		}
464	}
465	require_action( i < n, exit, err = kNotFoundErr );
466
467	// Uninstall it then re-install it to move it to the end.
468
469	size = (DWORD) strlen( array[ i ].lpszIdentifier );
470	require_action( size < sizeof_array( name ), exit, err = kSizeErr );
471	CharToWCharString( array[ i ].lpszIdentifier, name );
472
473	size = (DWORD) strlen( "%SystemRoot%\\System32\\mswsock.dll" );
474	require_action( size < sizeof_array( path ), exit, err = kSizeErr );
475	CharToWCharString( "%SystemRoot%\\System32\\mswsock.dll", path );
476
477	err = WSCUnInstallNameSpace( &array[ i ].NSProviderId );
478	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
479	require_noerr( err, exit );
480
481	err = WSCInstallNameSpace( name, path, NS_DNS, array[ i ].dwVersion, &array[ i ].NSProviderId );
482	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
483	require_noerr( err, exit );
484
485	// Success!
486
487	fprintf( stderr, "Reordered \"Tcpip\" NSP to to the bottom of the NSP chain\n" );
488	err = kNoErr;
489
490exit:
491	if( array )
492	{
493		free( array );
494	}
495	if( started )
496	{
497		WSACleanup();
498	}
499	if( err != kNoErr )
500	{
501		fprintf( stderr, "### FAILED (%d) to reorder Name Space Providers\n", err );
502	}
503	return( err );
504}
505
506#if 0
507#pragma mark -
508#endif
509
510//===========================================================================================================================
511//	CharToWCharString
512//===========================================================================================================================
513
514DEBUG_LOCAL WCHAR *	CharToWCharString( const char *inCharString, WCHAR *outWCharString )
515{
516	const char *		src;
517	WCHAR *				dst;
518	char				c;
519
520	check( inCharString );
521	check( outWCharString );
522
523	src = inCharString;
524	dst = outWCharString;
525	do
526	{
527		c = *src++;
528		*dst++ = (WCHAR) c;
529
530	}	while( c != '\0' );
531
532	return( outWCharString );
533}
534
535//===========================================================================================================================
536//	GUIDtoString
537//===========================================================================================================================
538
539DEBUG_LOCAL char *	GUIDtoString( const GUID *inGUID, char *outString )
540{
541	check( inGUID );
542	check( outString );
543
544	sprintf( outString, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
545		inGUID->Data1, inGUID->Data2, inGUID->Data3,
546		inGUID->Data4[ 0 ], inGUID->Data4[ 1 ], inGUID->Data4[ 2 ], inGUID->Data4[ 3 ],
547		inGUID->Data4[ 4 ], inGUID->Data4[ 5 ], inGUID->Data4[ 6 ], inGUID->Data4[ 7 ] );
548	return( outString );
549}
550
551//===========================================================================================================================
552//	StringToGUID
553//===========================================================================================================================
554
555DEBUG_LOCAL OSStatus	StringToGUID( const char *inCharString, GUID *outGUID )
556{
557	OSStatus			err;
558	int					n;
559	unsigned int		v[ 8 ];
560
561	check( inCharString );
562	check( outGUID );
563
564	n = sscanf( inCharString, "%lX-%hX-%hX-%02X%02X-%02X%02X%02X%02X%02X%02X",
565		&outGUID->Data1, &outGUID->Data2, &outGUID->Data3,
566		&v[ 0 ], &v[ 1 ], &v[ 2 ], &v[ 3 ], &v[ 4 ], &v[ 5 ], &v[ 6 ], &v[ 7 ] );
567	require_action( n == 11, exit, err = kFormatErr );
568
569	outGUID->Data4[ 0 ] = (unsigned char) v[ 0 ];
570	outGUID->Data4[ 1 ] = (unsigned char) v[ 1 ];
571	outGUID->Data4[ 2 ] = (unsigned char) v[ 2 ];
572	outGUID->Data4[ 3 ] = (unsigned char) v[ 3 ];
573	outGUID->Data4[ 4 ] = (unsigned char) v[ 4 ];
574	outGUID->Data4[ 5 ] = (unsigned char) v[ 5 ];
575	outGUID->Data4[ 6 ] = (unsigned char) v[ 6 ];
576	outGUID->Data4[ 7 ] = (unsigned char) v[ 7 ];
577	err = kNoErr;
578
579exit:
580	return( err );
581}
582