Build the one utility we need for now

It's for Homebrew
This commit is contained in:
Andrew Hyatt 2017-04-07 18:59:54 -07:00
parent 586a8d5f65
commit b1d05a7ba1
103 changed files with 29788 additions and 0 deletions

30
CMakeLists.txt Normal file
View File

@ -0,0 +1,30 @@
project(DSTools)
add_compile_options(
-nostdinc
)
add_darling_executable(dsmemberutil dsmbrutil/dsmbrutil.c)
install(TARGETS dsmemberutil DESTINATION libexec/darling/usr/bin)
install(FILES
dirt/dirt.1
dscacheutil/dscacheutil.1
dscacheutil/lookupd.1
dscl/dscl.1
dsconfigldap/dsconfigldap.1
dsmbrutil/dsmemberutil.1
dsmbrutil/memberd.1
DESTINATION libexec/darling/usr/share/man/man1
)
install(FILES
dsenableroot/dsenableroot.8
dserr/dserr.8
pwpolicy/pwpolicy.8
ugtools/dseditgroup.8
DESTINATION libexec/darling/usr/share/man/man8
)

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSObjCWrappers
*/
// All DSObjCWrappers Project Headers
#import <DSObjCWrappers/DSoAttributeUtils.h>
#import <DSObjCWrappers/DSoBuffer.h>
#import <DSObjCWrappers/DSoDataList.h>
#import <DSObjCWrappers/DSoDataNode.h>
#import <DSObjCWrappers/DSoDirectory.h>
#import <DSObjCWrappers/DSoException.h>
#import <DSObjCWrappers/DSoGroup.h>
#import <DSObjCWrappers/DSoNode.h>
#import <DSObjCWrappers/DSoNodeBrowserItem.h>
#import <DSObjCWrappers/DSoNodeConfig.h>
#import <DSObjCWrappers/DSoRecord.h>
#import <DSObjCWrappers/DSoStatus.h>
#import <DSObjCWrappers/DSoUser.h>

View File

@ -0,0 +1,50 @@
-[DSoDirectory initWithLocal]
-[DSoDirectory init]
-[DSoDirectory(DSoDirectoryPrivate) openLocalHost]
-[DSoDirectory searchNode]
-[DSoDirectory verifiedDirRef]
-[DSoBuffer initWithDir:]
-[DSoBuffer initWithDir:bufferSize:]
-[DSoBuffer init]
-[DSoDirectory dsDirRef]
-[DSoBuffer dsDataBuffer]
-[DSoBuffer dealloc]
-[DSoNode initWithDir:nodeRef:nodeName:]
-[DSoNode init]
-[DSoNode findUser:]
-[DSoSearchNode _findRecord:ofType:]
-[DSoDataList initWithDir:string:]
-[DSoDataList initWithDir:value:]
-[DSoDataList initWithDir:cString:]
-[DSoDataList initWithDir:cStrings:]
-[DSoDataList init]
-[DSoDataList dsDataList]
-[DSoDataList dealloc]
-[DSoDirectory findNode:]
-[DSoDirectory findNode:matchType:]
-[DSoDirectory findNode:matchType:useFirst:]
-[DSoDataList initWithDir:separator:pattern:]
-[DSoDataNode initWithDir:string:]
-[DSoDataNode initWithDir:cString:]
-[DSoNode dsNodeReference]
-[DSoDataNode dsDataNode]
-[DSoDataNode dealloc]
-[DSoRecord initInNode:recordRef:type:]
-[DSoUser initInNode:recordRef:]
-[DSoRecord(DSoRecordPrivate) initInNode:recordRef:]
-[DSoRecord init]
-[DSoNode directory]
-[DSoRecord getAttribute:]
-[DSoRecord getAttribute:allowBinary:]
-[DSoRecord getAttribute:index:allowBinary:]
+[DSoAttributeUtils getAttributeFromBuffer:allowBinary:]
+[DSoAttributeUtils _isBinaryAttribute:length:]
-[DSoRecord dealloc]
-[DSoNode dealloc]
-[DSoDirectory dealloc]
-[DSoDirectory(DSoDirectoryPrivate) close]
+[DSoException raiseWithStatus:]
+[DSoException name:reason:status:]
-[DSoException initWithName:reason:userInfo:]
+[DSoStatus sharedInstance]
-[DSoException dealloc]

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoAttributeUtils
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
@class DSoNode, DSoBuffer;
@interface DSoAttributeUtils : NSObject {
}
/*!
@method getAttributeFromBuffer:allowBinary:
@abstract this method takes a tDataBufferPtr and puts it into NSData or NSString
@discussion this method will take an existing tDataBufferPtr and determine
if it is a binary value or an UTF8String. Depending on the value
it will return a NSData or an NSString. If allowBinary is set
to NO, then it will return Hex encoded value instead.
*/
+ (id) getAttributeFromBuffer:(tDataBufferPtr)inBufferPtr
allowBinary:(BOOL)inAllowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
+ (NSDictionary*)getAttributesAndValuesInNode:(DSoNode*)inNode
fromBuffer:(DSoBuffer*)inBuf
listReference:(tAttributeListRef)inListRef
count:(unsigned long)inCount DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
+ (NSDictionary*)getAttributesAndValuesInNode:(DSoNode*)inNode
fromBuffer:(DSoBuffer*)inBuf
listReference:(tAttributeListRef)inListRef
count:(unsigned long)inCount
allowBinary:(BOOL)inAllowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
+ (NSArray*)getAttributesInNode:(DSoNode*)inNode
fromBuffer:(DSoBuffer*)inBuf
listReference:(tAttributeListRef)inListRef
count:(unsigned long)inCount DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
+ (NSArray*)getAttributesInNode:(DSoNode*)inNode
fromBuffer:(DSoBuffer*)inBuf
listReference:(tAttributeListRef)inListRef
count:(unsigned long)inCount
allowBinary:(BOOL)inAllowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

View File

@ -0,0 +1,234 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoAttributeUtils
*/
#import "DSoAttributeUtils.h"
#import "DSoDirectory.h"
#import "DSoNode.h"
#import "DSoBuffer.h"
#import "DSoException.h"
@interface DSoAttributeUtils(PrivateMethods)
+ (id) _getAttributesInNode:(DSoNode*)inNode
fromBuffer:(DSoBuffer*)inBuf
listReference:(tAttributeListRef)inListRef
count:(unsigned long)inCount
includeValues:(BOOL)inIncludeVals
allowBinary:(BOOL)inAllowBinary;
@end
@implementation DSoAttributeUtils
+ (NSDictionary*)getAttributesAndValuesInNode:(DSoNode*)inNode
fromBuffer:(DSoBuffer*)inBuf
listReference:(tAttributeListRef)inListRef
count:(unsigned long)inCount
{
return [DSoAttributeUtils _getAttributesInNode: inNode
fromBuffer: inBuf
listReference: inListRef
count: inCount
includeValues: YES
allowBinary: NO];
}
+ (NSDictionary*)getAttributesAndValuesInNode:(DSoNode*)inNode
fromBuffer:(DSoBuffer*)inBuf
listReference:(tAttributeListRef)inListRef
count:(unsigned long)inCount
allowBinary:(BOOL)inAllowBinary
{
return [DSoAttributeUtils _getAttributesInNode: inNode
fromBuffer: inBuf
listReference: inListRef
count: inCount
includeValues: YES
allowBinary: inAllowBinary];
}
+ (NSArray*)getAttributesInNode:(DSoNode*)inNode
fromBuffer:(DSoBuffer*)inBuf
listReference:(tAttributeListRef)inListRef
count:(unsigned long)inCount
{
return [DSoAttributeUtils _getAttributesInNode: inNode
fromBuffer: inBuf
listReference: inListRef
count: inCount
includeValues: NO
allowBinary: NO];
}
+ (NSArray*)getAttributesInNode:(DSoNode*)inNode
fromBuffer:(DSoBuffer*)inBuf
listReference:(tAttributeListRef)inListRef
count:(unsigned long)inCount
allowBinary:(BOOL)inAllowBinary
{
return [DSoAttributeUtils _getAttributesInNode: inNode
fromBuffer: inBuf
listReference: inListRef
count: inCount
includeValues: NO
allowBinary: inAllowBinary];
}
+ (BOOL) _isBinaryAttribute:(char *)inBuffer length:(unsigned long)inLength
{
BOOL returnValue = NO;
if( strlen(inBuffer) != inLength ) {
returnValue = YES;
}
// we'll add more here if necessary...
return returnValue;
}
+ (id) getAttributeFromBuffer:(tDataBufferPtr)inBufferPtr allowBinary:(BOOL)inAllowBinary
{
id returnValue = nil;
if( inBufferPtr->fBufferLength )
{
@try
{
returnValue = [NSString stringWithUTF8String: inBufferPtr->fBufferData];
// if the lengths don't match, we should it treat as binary
if( returnValue && strlen([returnValue UTF8String]) != inBufferPtr->fBufferLength ) {
returnValue = nil;
}
} @catch ( NSException *exception ) {
// must not have been a UTF8 string...
returnValue = nil;
}
if( returnValue == nil || [DSoAttributeUtils _isBinaryAttribute: inBufferPtr->fBufferData
length: inBufferPtr->fBufferLength] )
{
returnValue = [NSData dataWithBytes: inBufferPtr->fBufferData length: inBufferPtr->fBufferLength];
if( !inAllowBinary ) {
NSString *description = [returnValue description];
// make a string that contains just the hex, not including the '<>'
returnValue = [description substringWithRange: NSMakeRange(1,[description length]-2)];
}
}
} else {
returnValue = [NSString string];
}
return returnValue;
}
+ (id) _getAttributesInNode:(DSoNode*)inNode
fromBuffer:(DSoBuffer*)inBuf
listReference:(tAttributeListRef)inListRef
count:(unsigned long)inCount
includeValues:(BOOL)inIncludeVals
allowBinary:(BOOL)inAllowBinary
{
tAttributeValueListRef valueRef = 0;
tAttributeEntryPtr pAttrEntry = nil;
tAttributeValueEntryPtr pValueEntry = nil;
tDirStatus err = eDSNoErr;
char *attributeName = nil;
NSMutableArray *attributeValues = nil;
id attributes = nil;
unsigned long i = 0;
unsigned long j = 0;
// This is a multi-purpose routine, that might return an NSArray of the attribute names,
// or an NSDictionary of the attribute names and their values.
if (inIncludeVals)
attributes = [[NSMutableDictionary alloc] init];
else
attributes = [[NSMutableArray alloc] init];
for (i = 1; i <= inCount && !err; i++)
{
err = dsGetAttributeEntry([inNode dsNodeReference], [inBuf dsDataBuffer],inListRef,
i, &valueRef, &pAttrEntry);
if (!err)
{
attributeName = pAttrEntry->fAttributeSignature.fBufferData;
// If we should also include the values, then retrieve those and place them into the NSDictionary
if (inIncludeVals)
{
attributeValues = [[NSMutableArray alloc] initWithCapacity:pAttrEntry->fAttributeValueCount];
for (j =1; j <= pAttrEntry->fAttributeValueCount; j++)
{
err = dsGetAttributeValue([inNode dsNodeReference],[inBuf dsDataBuffer], j, valueRef, &pValueEntry );
if (err == eDSNoErr)
{
id value = [DSoAttributeUtils getAttributeFromBuffer: &pValueEntry->fAttributeValueData allowBinary: inAllowBinary];
[attributeValues addObject: value];
err = dsDeallocAttributeValueEntry([[inNode directory] dsDirRef], pValueEntry);
pValueEntry = nil;
}
else
{
break; // we'll release below
}
}
if (err == eDSNoErr)
{
[attributes setObject: attributeValues forKey:[NSString stringWithUTF8String:attributeName]];
}
[attributeValues release];
attributeValues = nil;
}
else // we aren't including the values, we are returning an NSArray of just the attribute names.
{
[attributes addObject:[NSString stringWithUTF8String:attributeName]];
}
dsCloseAttributeValueList(valueRef);
dsDeallocAttributeEntry([[inNode directory] dsDirRef], pAttrEntry);
} // end if (!err)
} // end for (...)
if (err)
{
[attributes release];
attributes = nil;
[DSoException raiseWithStatus:err];
}
return [attributes autorelease];
}
@end

130
DSObjCWrappers/DSoBuffer.h Normal file
View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoBuffer
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
@class DSoDirectory;
enum { kDefaultBufferSize = 128 } ;
/*!
* @class DSoBuffer
* This class is a wrapper object for a tDataBuffer data type
* in the Directory Services framework.
*
* While it is perfectly OK to use this class, it is primarily
* intended to be only used by the other classes of this framework.
* It is the intention that the classes for high-level data objects
* (Nodes, users, records, etc.)
* provide a sufficient Objective-C style interface to the necessary data
* and functionality, that the lower-level data types such as this one.
* can be avoided in favor of such types as NSArrays, NSStrings, and NSDictionarys.
*/
@interface DSoBuffer : NSObject {
DSoDirectory *mDir ;
tDataBufferPtr mBuffer ;
}
/*!
* @method initWithDir:
* @abstract Initialize with respect to a certain DS process reference.
* @param inDir The DS object in which to initialize this buffer.
*/
- (DSoBuffer*)initWithDir:(DSoDirectory*)inDir DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:
* @abstract Initialize with respect toa certain DS process reference,
* @discussion This method allows an initial buffer size to be specified.
* This is the most commonly used initialization method.
* @param inDir The DS object in which to initialize this buffer.
*/
- (DSoBuffer*)initWithDir:(DSoDirectory*)inDir bufferSize:(unsigned long)inBufferSize DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getBufferSize
* @abstract Get the maximum size, in bytes, of the buffer.
*/
- (unsigned long) getBufferSize DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getDataLength
* @abstract Get the actual length of data used, in bytes.
*/
- (unsigned long) getDataLength DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method setData:length:
* @abstract Set the data contents.
* @discussion Sets the data content when provided with
* a character array of data and the length of this data.
* @param inData A pointer to a character array of data.
* @param inLength The number of bytes to read from the data pointer.
*/
- (void)setData:(const void*)inData length:(unsigned long)inLength DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method appendData:length:
* @abstract Append to the data contents.
* @discussion Appends to the data content when provided with
* a character array of data and the length of this data.
* @param inData A pointer to a character array of data.
* @param inLength The number of bytes to read from the data pointer.
*/
- (void)appendData:(const void*)inData length:(unsigned long)inLength DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method setDataLength:
* @abstract Set an arbitrary length for the data length.
* @param inLength The new length to be considered as the length of data.
*/
- (void)setDataLength:(unsigned long)inLength DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method dsDataBuffer
* @abstract Method for accessing the low-level data type.
* @result A pointer to the internally wrapped tDataBuffer variable.
*/
- (tDataBufferPtr)dsDataBuffer DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method grow:
* @abstract Increase the buffer size.
* @discussion Causes the buffer size to grow to the specified
* size, preserving existing buffer data and length.
* @param inNewSize The new size in bytes for the buffer.
* @result Returns a pointer to the internal buffer struct
* simply as a convenience for checking that the operation
* succeeded. It should generally be ignored.
*/
- (tDataBufferPtr) grow:(unsigned long)inNewSize DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

179
DSObjCWrappers/DSoBuffer.m Normal file
View File

@ -0,0 +1,179 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoBuffer
*/
#import "DSoBuffer.h"
#import "DSoException.h"
#import "DSoDirectory.h"
@implementation DSoBuffer
#pragma mark Constructors & Desctructors
// ----------------------------------------------------------------------------
// Constructors & Desctructors
- (DSoBuffer*)init
{
[super init];
mBuffer = calloc(1, sizeof(tDataBuffer));
return self;
}
- (DSoBuffer*)initWithDir:(DSoDirectory*)inDir
{
return [self initWithDir:inDir bufferSize:kDefaultBufferSize];
}
- (DSoBuffer*)initWithDir:(DSoDirectory*)inDir bufferSize:(unsigned long)inBufferSize
{
[self init];
mDir = [inDir retain];
if (mBuffer)
free(mBuffer);
mBuffer = dsDataBufferAllocate([mDir dsDirRef], inBufferSize);
if (!mBuffer)
{
[self release];
[DSoException raiseWithStatus:eDSAllocationFailed];
}
return self;
}
- (void)dealloc
{
if (mBuffer)
dsDataBufferDeAllocate ([mDir dsDirRef], mBuffer) ;
[mDir release];
[super dealloc];
}
- (void)finalize
{
if (mBuffer)
dsDataBufferDeAllocate ([mDir dsDirRef], mBuffer) ;
[super finalize];
}
#pragma mark Public Accessors
// ----------------------------------------------------------------------------
// Public Accessors
- (unsigned long) getBufferSize
{
return mBuffer->fBufferSize ;
}
- (unsigned long) getDataLength
{
return mBuffer->fBufferLength ;
}
- (void)setData:(const void*)inData length:(unsigned long)inLength
{
mBuffer->fBufferLength = 0 ;
[self grow:inLength];
memcpy (mBuffer->fBufferData, inData, inLength) ;
mBuffer->fBufferLength = inLength ;
}
- (void)appendData:(const void*)inData length:(unsigned long)inLength
{
char *cpBuf;
if ((mBuffer->fBufferLength + inLength) > mBuffer->fBufferSize)
[self grow:(mBuffer->fBufferLength + inLength)] ;
cpBuf = mBuffer->fBufferData + mBuffer->fBufferLength ;
memcpy (cpBuf, inData, inLength) ;
mBuffer->fBufferLength += inLength ;
}
- (void)setDataLength:(unsigned long)inLength
{
if (inLength > mBuffer->fBufferSize)
[DSoException raiseWithStatus:eDSBufferTooSmall];
mBuffer->fBufferLength = inLength ;
}
- (tDataBufferPtr)dsDataBuffer
{
return mBuffer;
}
- (tDataBufferPtr) grow:(unsigned long)inNewSize
{
UInt32 ulTemp = 16;
tDataBufferPtr bufNew = nil;
DSRef dirRef = [mDir dsDirRef];
if (!inNewSize)
inNewSize = kDefaultBufferSize ;
if (mBuffer && (inNewSize <= mBuffer->fBufferSize))
return mBuffer ;
if (inNewSize == kDefaultBufferSize)
ulTemp = inNewSize ;
else
for ( ; ulTemp < inNewSize ; ulTemp <<= 1) ;
bufNew = dsDataBufferAllocate (dirRef, ulTemp) ;
if (!bufNew)
[DSoException raiseWithStatus:eDSAllocationFailed];
if (mBuffer && (ulTemp = mBuffer->fBufferLength))
memcpy (bufNew->fBufferData, mBuffer->fBufferData, ulTemp) ;
else
ulTemp = 0 ;
bufNew->fBufferLength = ulTemp ;
dsDataBufferDeAllocate (dirRef, mBuffer) ;
return (mBuffer = bufNew) ;
}
- (NSString*)description
{
int i = 0;
NSMutableString *bufferString = [[NSMutableString alloc] init];
NSString *retValue = nil;
for (i = 0; i < mBuffer->fBufferLength; i++)
{
if (mBuffer->fBufferData[i] > 126 || mBuffer->fBufferData[i] < 32)
[bufferString appendFormat:@"<%d>", mBuffer->fBufferData[i]];
else
[bufferString appendFormat:@"%c", mBuffer->fBufferData[i]];
}
retValue = [NSString stringWithFormat:@"%@ {\nBuffer Size:%ld\nBuffer Length:%ld\n%@\n}\n",
[super description], mBuffer->fBufferSize, mBuffer->fBufferLength, bufferString];
[bufferString release];
return retValue;
}
@end

View File

@ -0,0 +1,184 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoDataList
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
#import "DSoDirectory.h"
@class DSoDataNode;
/*!
* @class DSoDataList
* This class is a wrapper object for a tDataList data type
* in the Directory Services framework.
*
* While it is perfectly OK to use this class, it is primarily
* intended to be only used by the other classes of this framework.
* It is the intention that the classes for high-level data objects
* (Nodes, users, records, etc.)
* provide a sufficient Objective-C style interface to the necessary data
* and functionality, that the lower-level data types such as this one.
* can be avoided in favor of such types as NSArrays, NSStrings, and NSDictionarys.
*/
@interface DSoDataList : NSObject {
DSoDirectory *mDir;
tDataList mList;
}
/*!
* @method initWithDir:value:
* @abstract Initialize a data list with a single value.
* @discussion This will initialize the data list with one item: the
* contents of the given NSString or NSData.
* @param inDir The DS process object to initialize with.
* @param inValue The NSString or NSData to use for the single data item.
*/
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir value:(id)inValue DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:string:
* @abstract Initialize a data list with a single string.
* @discussion This will initialize the data list with one item: the
* contents of the given NSString.
* @param inDir The DS process object to initialize with.
* @param inString The NSString style string to use for the single data item.
*/
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir string:(NSString*)inString DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:values:
* @abstract Initialize a data list with an array of values.
* @discussion This will initialize the data list with a list of strings
or data in the specified array.
* @param inDir The DS process object to initialize with.
* @param inStrings The NSArray of NSString or NSData values to use for the list of data items.
*/
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir values:(NSArray*)inValues DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:strings:
* @abstract Initialize a data list with an array of strings.
* @discussion This will initialize the data list with a list of strings
in the specified array.
* @param inDir The DS process object to initialize with.
* @param inStrings The NSArray of NSString style strings to use for the list of data items.
*/
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir strings:(NSArray*)inStrings DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:cString:
* @abstract Initialize a data list with a single c-string.
* @discussion This will initialize the data list with one item: the
* contents of the given null terminated, c-style string.
* @param inDir The DS process object to initialize with.
* @param inString The null terminated C-style string to use for the single data item.
*/
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir cString:(const char*)inString DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:cStrings:...
* @abstract Initialize a data list with a list of c-strings.
* @discussion This will initialize the data list with the
* contents of the given list of null terminated, c-style strings.
* @param inDir The DS process object to initialize with.
* @param inString The list of strings to use for the data items, terminating with a nil.
*/
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir cStrings:(const char *)inString, ... DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:separator:pattern:
* @abstract Initialize a data list by separating a string.
* @discussion This will build the data list from the pieces of a string
* separated by a specified character.
* @param inDir The DS process object to initialize with.
* @param inSep The character on which to separate the string.
* @param inPattern The string to be separated into components.
*/
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir separator:(char)inSep pattern:(NSString*)inPattern DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDataList:
* @abstract Initialize with a copy of another data list.
* @discussion This method will initialize the list with copies
* of the contents of the given data list.
* @param inOrg The original data list to copy.
*/
- (DSoDataList*)initWithDataList:(DSoDataList*)inOrg DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:dsDataList:
* @abstract Initialize with an existing tDataList object.
* @discussion This method will initialize the object by wrapping
* an existing tDataList variable. A pointer to that variable is maintained,
* and the contents of the variable is freed when this object is deallocated.
* @param inDir The DS process object to initialize with.
* @param inList A pointer to the tDataList variable to use.
*/
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir dsDataList:(tDataListPtr)inList DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getcount
* @abstract Get the number of items in the list.
*/
- (unsigned long)getCount DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getDataLength
* @abstract Get the total length of data used in the data list.
*/
- (unsigned long)getDataLength DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method objectAtIndex:
* @abstract Get a specific data node from the list by index.
* @discussion This method returns a Data Node object wrapping the tDataNode
* data that is the inIndex'th item in this data list.
* @param inIndex The index of the data node to retrieve from the list. The first item has an index of '1'
* @result A DSoDataNode object wrapping the specified tDataNode item in the data list.
*/
- (DSoDataNode*)objectAtIndex:(unsigned long)inIndex DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method append
* @abstract Append a value to the list.
* @discussion A convenience method for appending a data node
* to the list whose contents are that of the specified NSData or NSString.
* @param inString A NSString or NSData containing the data to be appended to the list.
*/
- (void)append:(id)inValue DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method dsDataList
* @abstract Method for accessing the low-level data type.
* @result A pointer to the internally wrapped tDataList variable.
*/
- (tDataListPtr)dsDataList DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

View File

@ -0,0 +1,300 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoDataList
*/
#import "DSoDataList.h"
#import "DSoDataNode.h"
#import "DSoException.h"
@implementation DSoDataList
- (id)init
{
[super init];
mDir = nil;
return self;
}
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir value:(id)inValue
{
@try
{
if( self = [super init] )
{
tDirReference dsRef = [inDir dsDirRef];
tDirStatus nError = eDSNoErr;
if( [inValue isKindOfClass:[NSString class]] )
{
nError = dsAppendStringToListAlloc( dsRef, &mList, [inValue UTF8String] );
}
else if( [inValue isKindOfClass:[NSData class]] )
{
tDataNodePtr newNode = dsDataNodeAllocateBlock( dsRef, [inValue length], [inValue length], (tBuffer) [inValue bytes] );
nError = dsDataListInsertAfter( dsRef, &mList, newNode, 0 );
// we deallocate the datanode, cause the list creates a copy
dsDataBufferDeAllocate( dsRef, newNode ); // don't capture error here
}
else
{
@throw [NSException exceptionWithName: NSInvalidArgumentException reason: @"[DSoDataList initWithDir:value:] value is not a valid NSString nor NSData" userInfo: nil];
}
if( nError != eDSNoErr ) {
[DSoException raiseWithStatus: nError];
}
mDir = [inDir retain];
}
} @catch( NSException *exception ) {
[self release];
@throw;
}
return self;
}
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir string:(NSString*)inString
{
return [self initWithDir: inDir value: inString];
}
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir values:(NSArray*)inValues
{
@try
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSEnumerator *valEnum = [inValues reverseObjectEnumerator]; // go in reverse
tDirReference dsRef = [inDir dsDirRef];
id object;
tDirStatus nError = eDSNoErr;
[super init];
while( object = [valEnum nextObject] )
{
tDataNodePtr newNode = nil;
if( [object isKindOfClass:[NSString class]] )
{
newNode = dsDataNodeAllocateString( dsRef, [object UTF8String] );
}
else if( [object isKindOfClass:[NSData class]] )
{
newNode = dsDataNodeAllocateBlock( dsRef, [object length], [object length], (tBuffer) [object bytes] );
}
else
{
@throw [NSException exceptionWithName: NSInvalidArgumentException reason: @"[DSoDataList initWithDir:values:] values contains non NSString nor NSData" userInfo: nil];
}
// we build the list in reverse so we always add to the head of the list
nError = dsDataListInsertAfter( dsRef, &mList, newNode, 0 );
// we deallocate the datanode, cause the list creates a copy
dsDataBufferDeAllocate( dsRef, newNode );
if( nError != eDSNoErr ) {
[DSoException raiseWithStatus: nError];
}
}
[pool drain];
mDir = [inDir retain];
} @catch( NSException *exception ) {
[self release];
@throw;
}
return self;
}
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir strings:(NSArray*)inStrings
{
return [self initWithDir: inDir values: inStrings];
}
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir cString:(const char*)inString
{
return [self initWithDir:inDir cStrings: inString, NULL];
}
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir cStrings:(const char *)inString, ...
{
tDirStatus nError = eDSNoErr;
va_list args;
va_start (args, inString) ;
[self init];
if (inString != NULL)
{
tDirReference dsRef = [inDir dsDirRef];
nError = dsBuildListFromStringsAllocV (dsRef, &mList, inString, args) ;
}
va_end (args) ;
if (nError) {
[self release];
[DSoException raiseWithStatus:nError];
}
mDir = [inDir retain];
return self;
}
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir separator:(char)inSep pattern:(NSString*)inPattern
{
char szSep[] = { inSep, '\0' } ;
[self init];
tDataList *tempList = dsBuildFromPath ([inDir dsDirRef], [inPattern UTF8String], szSep) ;
if (tempList == NULL) {
[self release];
[DSoException raiseWithStatus:eDSAllocationFailed];
}
mList = *tempList;
free( tempList );
mDir = [inDir retain];
return self;
}
- (DSoDataList*)initWithDataList:(DSoDataList*)inOrg
{
[self init];
mDir = inOrg->mDir;
tDataList *tempList = dsDataListCopyList ([mDir dsDirRef], [inOrg dsDataList]) ;
if (tempList == NULL) {
[self release];
[DSoException raiseWithStatus:eDSAllocationFailed];
}
mList = *tempList;
free( tempList );
[mDir retain]; // Since we didn't error, now we retain the object.
return self;
}
- (DSoDataList*)initWithDir:(DSoDirectory*)inDir dsDataList:(tDataListPtr)inList
{
[self init];
mDir = [inDir retain];
if (inList)
{
tDataList *tempList = dsDataListCopyList( [inDir dsDirRef], inList );
if( tempList == NULL )
{
[self release];
[DSoException raiseWithStatus:eDSAllocationFailed];
}
mList = *tempList;
free( tempList );
}
return self;
}
- (void)dealloc
{
dsDataListDeallocate ([mDir dsDirRef], &mList) ;
[mDir release];
[super dealloc];
}
- (void)finalize
{
dsDataListDeallocate ([mDir dsDirRef], &mList) ;
[super finalize];
}
- (unsigned long)getCount
{
return dsDataListGetNodeCount (&mList) ;
}
- (unsigned long)getDataLength
{
return dsGetDataLength (&mList) ;
}
- (DSoDataNode*)objectAtIndex:(unsigned long)inIndex
{
tDataNodePtr dnTemp = nil;
tDirStatus nError = dsDataListGetNodeAlloc ([mDir dsDirRef], &mList, inIndex, &dnTemp);
if (nError)
[DSoException raiseWithStatus:nError] ;
return [[[DSoDataNode alloc] initWithDir:mDir dsDataNode:dnTemp] autorelease];
}
- (void)append:(id)inValue
{
tDirStatus nError = eDSNoErr;
tDataNodePtr newNode = nil;
tDirReference dsRef = [mDir dsDirRef];
if( [inValue isKindOfClass:[NSString class]] )
{
newNode = dsDataNodeAllocateString( dsRef, [inValue UTF8String] );
}
else if( [inValue isKindOfClass:[NSData class]] )
{
newNode = dsDataNodeAllocateBlock( dsRef, [inValue length], [inValue length], (tBuffer) [inValue bytes] );
}
else
{
@throw [NSException exceptionWithName: NSInvalidArgumentException reason:@"[DSoDataList append:] value is not a valid NSString nor NSData" userInfo:nil];
}
nError = dsDataListInsertAfter( dsRef, &mList, newNode, dsDataListGetNodeCount(&mList) );
if( nError != eDSNoErr ) {
[DSoException raiseWithStatus: nError];
}
}
- (tDataListPtr)dsDataList
{
return &mList;
}
@end

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoDataNode
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
#import "DSoDirectory.h"
/*!
* @class DSoDataNode
* This class is a wrapper object for a tDataNode data type
* in the Directory Services framework.
*
* While it is perfectly OK to use this class, it is primarily
* intended to be only used by the other classes of this framework.
* It is the intention that the classes for high-level data objects
* (Nodes, users, records, etc.)
* provide a sufficient Objective-C style interface to the necessary data
* and functionality, that the lower-level data types such as this one.
* can be avoided in favor of such types as NSArrays, NSStrings, and NSDictionarys.
*/
@interface DSoDataNode : NSObject {
DSoDirectory *mDir;
tDataNodePtr mNode;
}
/*!
* @method initWithDir:bufferSize:dataLength:data:
* @abstract Initialize a data node with raw data.
* @discussion This will initialize the data node with a character
* array of data and specified buffer size and length.
* @param inDir The DS process object to initialize with.
* @param inBufSize The size to use for the data node's buffer.
* @param inDataLength The length of the data to be stored in the data node.
* @param inData A pointer to an array of characters containing the data to be stored.
*/
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir bufferSize:(unsigned long)inBufSize dataLength:(unsigned long)inDataLength data:(const void*)inData DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:value:
* @abstract Initialize a data node with a value.
* @discussion This will initialize the data node with the
* contents of the given NSString or NSData, with both the data length
* and buffer size set to the length of that object.
* @param inDir The DS process object to initialize with.
* @param inValue The NSString or NSData style value to use for the data.
*/
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir value:(id)inValue DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:string:
* @abstract Initialize a data node with a string.
* @discussion This will initialize the data node with the
* contents of the given NSString, with both the data length
* and buffer size set to the length of that string.
* @param inDir The DS process object to initialize with.
* @param inString The NSString style string to use for the data.
*/
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir string:(NSString*)inString DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:cString:
* @abstract Initialize a data node with a C-string.
* @discussion This will initialize the data node with the
* contents of a standard C-style, null-terminated string
* (character array), with both the data length
* and buffer size set to the length of that string.
* @param inDir The DS process object to initialize with.
* @param inString The null terminated C-style string to use for the data.
*/
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir cString:(const char*)inString DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:dsDataNode:
* @abstract Initialize with a tDataNode object.
* @discussion This will initialize the object with an existing
* tDataNode variable. It stores the pointer to the variable
* and the contents of the variable is freed when this object is deallocated.
* @param inDir The DS process object to initialize with.
* @param inNode A pointer to the tDataNode variable.
*/
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir dsDataNode:(tDataNode*)inNode DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithDir:copyOfDsDataNode:
* @abstract Initialize with a copy of a tDataNode object.
* @discussion This will initialize the object with a copy of an existing
* tDataNode variable. Only the copied variable is freed
* when this object is deallocated.
* @param inDir The DS process object to initialize with.
* @param inNode A pointer to the tDataNode variable.
*/
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir copyOfDsDataNode:(tDataNode*)inNode DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
// accessors.
/*!
* @method getBufferSize
* @abstract Get the size of the data node's buffer.
*/
- (unsigned long) getBufferSize DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getDataLength
* @abstract Get the length of valid data in the data node's buffer.
*/
- (unsigned long) getDataLength DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method setDataLength:
* @abstract Sets the length of valid data in the data node's buffer.
* @param inLength The new length to use for the data node's buffer.
*/
- (void) setDataLength:(unsigned long)inLength DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method dsDataNode
* @abstract Method for accessing the low-level data type.
* @result A pointer to the internally wrapped tDataNode variable.
*/
- (tDataNodePtr) dsDataNode DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoDataNode
*/
#import "DSoDataNode.h"
#import "DSoException.h"
@implementation DSoDataNode
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir bufferSize:(unsigned long)inBufSize
dataLength:(unsigned long)inDataLength data:(const void*)inData
{
[self init];
mNode = dsDataNodeAllocateBlock ([inDir dsDirRef], inBufSize, inDataLength, (void*)inData);
if (!mNode) {
[self release];
[DSoException raiseWithStatus:eDSAllocationFailed];
}
mDir = [inDir retain];
return self;
}
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir value:(id)inValue
{
if( self = [self init] )
{
if( [inValue isKindOfClass:[NSString class]] )
{
mNode = dsDataNodeAllocateString( [inDir dsDirRef], [inValue UTF8String] );
}
else if( [inValue isKindOfClass:[NSData class]] )
{
mNode = dsDataNodeAllocateBlock( [inDir dsDirRef], [inValue length], [inValue length], (tBuffer) [inValue bytes] );
}
else if ( inValue != nil )
{
[self release];
@throw [NSException exceptionWithName: NSInvalidArgumentException reason: @"[DSoDataNode initWithDir:value:] value is not a valid NSString nor NSData" userInfo: nil];
}
if( mNode == nil )
{
[self release];
return nil;
}
}
return self;
}
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir string:(NSString*)inString;
{
return [self initWithDir:inDir cString:[inString UTF8String]];
}
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir cString:(const char*)inString;
{
[self init];
mDir = [inDir retain];
mNode = dsDataNodeAllocateString ([inDir dsDirRef], inString);
if (!mNode) {
[self release];
[DSoException raiseWithStatus:eDSAllocationFailed];
}
return self;
}
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir dsDataNode:(tDataNode*)inNode;
{
[self init];
mDir = [inDir retain];
mNode = inNode;
if (!mNode) {
[self release];
[DSoException raiseWithStatus:eDSAllocationFailed];
}
return self;
}
- (DSoDataNode*)initWithDir:(DSoDirectory*)inDir copyOfDsDataNode:(tDataNode*)inNode;
{
[self init];
mDir = [inDir retain];
mNode = dsDataNodeAllocateBlock ([inDir dsDirRef], inNode->fBufferSize,
inNode->fBufferLength, (void*)inNode->fBufferData);
if (!mNode) {
[self release];
[DSoException raiseWithStatus:eDSAllocationFailed];
}
return self;
}
- (void)dealloc
{
if (mNode)
dsDataNodeDeAllocate ([mDir dsDirRef], mNode) ;
[mDir release];
[super dealloc];
}
- (void)finalize
{
if (mNode)
dsDataNodeDeAllocate ([mDir dsDirRef], mNode) ;
[super finalize];
}
// Inline accessors.
- (unsigned long) getBufferSize
{
return dsDataNodeGetSize (mNode) ;
}
- (unsigned long) getDataLength
{
return dsDataNodeGetLength (mNode) ;
}
- (void) setDataLength:(unsigned long)inLength
{
tDirStatus nError = dsDataNodeSetLength (mNode, inLength) ;
if (nError)
[DSoException raiseWithStatus:nError];
}
- (tDataNodePtr) dsDataNode;
{
return mNode;
}
- (NSString*)description
{
int i;
NSMutableString *bufferString = [[NSMutableString alloc] init];
NSString *retValue;
for (i = 0; i < mNode->fBufferLength; i++)
{
if (mNode->fBufferData[i] > 126 || mNode->fBufferData[i] < 32)
[bufferString appendFormat:@"<%d>", mNode->fBufferData[i]];
else
[bufferString appendFormat:@"%c", mNode->fBufferData[i]];
}
retValue = [NSString stringWithFormat:@"%@ {\nNode Size:%ld\nBuffer Length:%ld\n%@\n}\n",
[super description], mNode->fBufferSize, mNode->fBufferLength, bufferString];
[bufferString release];
return retValue;
}
@end

View File

@ -0,0 +1,189 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoDirectory
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
@class DSoNode, DSoSearchNode;
typedef tDirReference DSRef ;
/*!
* @class DSoDirectory
* @abstract Class for communication with a Directory Services process.
* @discussion This class provides connectivity to a Directory Services process,
* either on the localhost, or on a remote host using DS-Proxy.
* In addition to providing connectivity, the class provides methods
* for retrieving and opening nodes. These methods should be used
* to open nodes, rather than instantiating DSoNode objects manually.
*/
@interface DSoDirectory : NSObject {
@protected
NSRecursiveLock *mDirRefLock;
DSRef mDirRef;
DSoNode *mLocalNode;
DSoSearchNode *mSearchNode;
NSString *proxyHostname;
NSString *proxyUsername;
NSString *proxyPassword;
NSArray *mRecordTypes;
NSArray *mAttributeTypes;
}
/*!
* @method initWithLocal
* @abstract Open a connection to the local machine's DS process.
*/
- (id)initWithLocal DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithLocalPath
* @abstract Open a connection to the local machine's Local Only DS process.
*/
- (id)initWithLocalPath:(NSString*)filePath DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initWithHost:user:password:
* @abstract Open a connection to a remote machine's DS process.
* @discussion With an admin's username and password, one can connect
* to a remote DS process, rather than the local machine's process.
* @param hostName The FQDN or IP address of the remote host.
* @param inUser An administrator's username.
* @param inPassword The administrator's password.
*/
- (id)initWithHost:(NSString*)hostName user:(NSString*)inUser password:(NSString*)inPassword DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method nodeCount
* @abstract Finds the number of nodes registered by DS.
*/
- (unsigned long) nodeCount DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findNodeNames:matchType:
* @abstract Finds the list of node names registered by DS.
* Returns an empty array if no matching results are found.
* @result An array of NSString objects containing the node names.
*/
- (NSArray*) findNodeNames:(NSString*)inPattern matchType:(tDirPatternMatch)inType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findNode:
* @abstract Find and open a DS Node.
* @discussion Invokes findNode:matchType: with matchType an actual pattern to match.
*/
- (DSoNode*) findNodeViaEnum: (int)inPattern DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findNode:
* @abstract Find and open a DS Node.
* @discussion Invokes findNode:matchType: with matchType set to eDSExact.
*/
- (DSoNode*) findNode: (NSString*)inPattern DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findNode:matchType:
* @abstract Find and open a DS Node.
* @discussion Invokes findNode:matchType:useFirst: with useFirst set to YES.
*/
- (DSoNode*) findNode: (NSString*)inPattern
matchType: (tDirPatternMatch)inType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findNode:matchType:useFirst:
* @abstract Find and open a DS Node.
* @discussion Finds a DS node whose name matches the given parameters.
* The node is then opened and wrapped in a DSoNode object.
* @param inPattern The name pattern of the node to find.
* @param inType The type of pattern matching to perform.
* @param useFirst Documenation forthcoming.
* @result A DSoNode object representing the found and opened node.
*/
- (DSoNode*) findNode: (NSString*)inPattern
matchType: (tDirPatternMatch)inType
useFirst: (BOOL)inUseFirst DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findNodeNames
* @abstract Finds the list of all node names registered by DS.
* @result An array of NSString objects containing the node names.
*/
- (NSArray*) findNodeNames DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method nodeBrowserItems
* @abstract Finds the all top level items for the node browser.
* @result An array of DSoNodeBrowserItem objects.
*/
- (NSArray*) nodeBrowserItems DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method standardRecordTypes
* @abstract Retrieves all defined standard record types from the config node.
* @result An array of strings of the record types.
*/
- (NSArray*) standardRecordTypes DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method standardAttributeTypes
* @abstract Retrieves all defined standard attribute types from the config node.
* @result An array of strings of the attribute types.
*/
- (NSArray*) standardAttributeTypes DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method localNode
* @abstract Convenience method to find and open the local node.
*/
- (DSoNode*) localNode DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method searchNode
* @abstract Convenience method to find and open
* the (authentication) search node.
*/
- (DSoSearchNode*) searchNode DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method verifiedDirRef
* @abstract Method for accessing the low-level data type.
* @discussion This method differs from dsDirRef in that it
* first verifies the reference for validity. If it fails
* the check, then the connection is re-opened.
* @result The Directory Services reference value for this connection.
*/
- (DSRef)verifiedDirRef DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method dsDirRef
* @abstract Method for accessing the low-level data type.
* @result The Directory Services reference value for this connection.
*/
- (DSRef)dsDirRef DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

View File

@ -0,0 +1,686 @@
/*
* Copyright (c) 2003-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoDirectory
*/
#import "DSoDirectory.h"
#import "DSoDirectoryPriv.h"
#import <unistd.h>
#import "DSoNode.h"
#import "DSoBuffer.h"
#import "DSoDataList.h"
#import "DSoException.h"
#import "DSoNodeConfig.h"
#import "DSoDataNode.h"
#import "DSoNodeBrowserItem.h"
// ----------------------------------------------------------------------------
// Public Methods.
#pragma mark ***** Public Methods *****
@implementation DSoDirectory
- (id)init
{
[super init];
mDirRef = 0;
mLocalNode = nil;
mSearchNode = nil;
proxyHostname = nil;
proxyUsername = nil;
proxyPassword = nil;
mDirRefLock = [[NSRecursiveLock alloc] init];
return self;
}
// Open a connection to the local machine.
- (id)initWithLocal
{
@try {
[self init];
[self openLocalHost];
} @catch( NSException *exception ) {
[self release];
@throw;
}
return self;
}
// Open a connection to the local machine.
- (id)initWithLocalPath:(NSString*)filePath
{
@try {
[self init];
[self openLocalOnlyWithLocalPath:filePath];
} @catch( NSException *exception ) {
[self release];
@throw;
}
return self;
}
// Open a conection to a remote machine using DS Proxy.
- (id)initWithHost:(NSString*)hostName user:(NSString*)inUser password:(NSString*)inPassword
{
@try {
[self init];
[self openHost:hostName user:inUser password:inPassword];
// Save the hostname, username and password in case we
// lose the connection and have to re-establish it
proxyHostname = [hostName retain];
proxyUsername = [inUser retain];
proxyPassword = [inPassword retain];
} @catch( NSException *exception ) {
[self release];
@throw;
}
return self;
}
- (void)dealloc
{
[self close];
[mDirRefLock release];
if (proxyHostname != nil)
{
[proxyHostname release];
[proxyUsername release];
[proxyPassword release];
}
[mRecordTypes release];
[mAttributeTypes release];
[super dealloc];
}
- (void)finalize
{
[self close];
[super finalize];
}
- (DSRef)verifiedDirRef
{
tDirStatus nError = eDSNoErr;
[mDirRefLock lock];
@try
{
// DirRef initialized, check its validity.
// Important that ref count not changed!
if (!mDirRef || (nError = dsVerifyDirRefNum (mDirRef)))
{
// Reopen the reference
[self reopen];
}
} @catch( NSException *exception ) {
@throw;
} @finally {
[mDirRefLock unlock];
}
return mDirRef;
}
- (unsigned long) nodeCount
{
DSRef refTemp = [self verifiedDirRef];
UInt32 ulCount = 0;
tDirStatus nError = dsGetDirNodeCount(refTemp, &ulCount);
if (nError)
[DSoException raiseWithStatus:nError];
return (unsigned long)ulCount;
}
- (NSArray*) findNodeNames:(NSString*)inPattern matchType:(tDirPatternMatch)inType
{
tDirStatus nError = eDSNoErr;
tDataListPtr dlpNodeName = nil;
tContextData continueData = 0;
DSRef refTemp = 0;
DSoBuffer *bufNodeList = nil;
unsigned long i = 0;
UInt32 ulCount = 0;
char *szpTemp = nil;
NSString *sNodeName = nil;
NSMutableArray *resultList = nil;
refTemp = [self verifiedDirRef];
bufNodeList = [[DSoBuffer alloc] initWithDir:self bufferSize:1024];
resultList = [NSMutableArray array];
// Generate a list of matching nodes.
do {
if (inPattern) {
DSoDataList *dlPattern = [[DSoDataList alloc] initWithDir:self separator:'/' pattern:inPattern];
nError = dsFindDirNodes (refTemp, [bufNodeList dsDataBuffer], [dlPattern dsDataList],
inType, &ulCount, &continueData) ;
[dlPattern release];
}
else
{
nError = dsFindDirNodes (refTemp, [bufNodeList dsDataBuffer], NULL,
inType, &ulCount, &continueData) ;
}
if (nError == eDSBufferTooSmall)
{
unsigned long size = [bufNodeList getBufferSize];
[bufNodeList grow:size + size];
continue;
}
// Validate results.
if (nError) {
[bufNodeList release];
[DSoException raiseWithStatus:nError];
}
resultList = [NSMutableArray arrayWithCapacity:ulCount];
for (i = 1; i <= ulCount; i++)
{
nError = dsGetDirNodeName (refTemp, [bufNodeList dsDataBuffer], i, &dlpNodeName);
if (nError)
{
[bufNodeList release];
[DSoException raiseWithStatus:nError];
}
szpTemp = dsGetPathFromList (refTemp, dlpNodeName, "/") ;
sNodeName = [NSString stringWithUTF8String:szpTemp];
[resultList addObject:sNodeName];
free (szpTemp) ;
dsDataListDeallocate (refTemp, dlpNodeName) ;
free (dlpNodeName) ;
}
} while (continueData != 0 || nError == eDSBufferTooSmall);
if (continueData != 0)
dsReleaseContinueData(refTemp, continueData);
[bufNodeList release];
return resultList; // Already autoreleased.
}
// Return an instantiated version of a particular node.
//
- (DSoNode*) findNode: (NSString*)inPattern
{
return [self findNode:inPattern matchType:eDSExact];
}
- (DSoNode*) findNodeViaEnum: (int)inPattern
{
return [self findNode:nil matchType:inPattern];
}
- (DSoNode*) findNode: (NSString*)inPattern
matchType: (tDirPatternMatch)inType
{
return [self findNode:inPattern matchType:inType useFirst:YES];
}
- (DSoNode*) findNode: (NSString*)inPattern
matchType: (tDirPatternMatch)inType
useFirst: (BOOL)inUseFirst
{
tDirStatus nError = eDSNoErr;
tDirNodeReference refNode = 0;
tDataListPtr dlpNodeName = nil;
DSRef refTemp = 0;
DSoBuffer *bufNodeList = nil;
UInt32 ulCount = 0;
char *szpTemp = nil;
NSString *sNodeName = nil;
DSoNode *opTemp = nil;
// Find the first (should be only) exact match if we have a full name.
// Before going any further, check the node list for a match.
if (inPattern && (inType == eDSExact) && inUseFirst)
{
DSoDataList *dlNodeName;
// If we have a full name, do not validate it, simply open it here.
refTemp = [self verifiedDirRef];
dlNodeName = [[DSoDataList alloc] initWithDir:self separator:'/' pattern:inPattern];
nError = dsOpenDirNode (refTemp, [dlNodeName dsDataList], &refNode);
[dlNodeName release];
if (nError)
{
[DSoException raiseWithStatus:nError];
}
if ([inPattern hasPrefix:@"/Search"]) {
opTemp = [[DSoSearchNode alloc] initWithDir:self nodeRef:refNode nodeName:inPattern];
} else if ([inPattern hasPrefix:@"/Configure"]) {
opTemp = [[DSoNodeConfig alloc] initWithDir:self nodeRef:refNode nodeName:inPattern];
} else {
opTemp = [[DSoNode alloc] initWithDir:self nodeRef:refNode nodeName:inPattern];
}
return [opTemp autorelease];
}
refTemp = [self verifiedDirRef];
bufNodeList = [[DSoBuffer alloc] initWithDir:self];
// Generate a list of matching nodes.
do {
if (inPattern)
{
DSoDataList *dlPattern = [[DSoDataList alloc] initWithDir:self separator:'/' pattern:inPattern];
nError = dsFindDirNodes (refTemp, [bufNodeList dsDataBuffer], [dlPattern dsDataList],
inType, &ulCount, NULL) ;
[dlPattern release];
}
else
{
nError = dsFindDirNodes (refTemp, [bufNodeList dsDataBuffer], NULL,
inType, &ulCount, NULL) ;
}
} while (nError == eDSBufferTooSmall);
// Validate results.
if( nError == eDSNoErr )
{
if (ulCount <= 0) {
nError = eDSUnknownNodeName;
} else if (!inUseFirst && (ulCount > 1)) {
nError = eDSNodeNotFound;
}
}
if( nError ) {
[bufNodeList release];
[DSoException raiseWithStatus:nError];
}
// Get the first matching, canonical node name from DS.
nError = dsGetDirNodeName (refTemp, [bufNodeList dsDataBuffer], 1, &dlpNodeName);
[bufNodeList release];
if (nError)
[DSoException raiseWithStatus:nError];
szpTemp = dsGetPathFromList (refTemp, dlpNodeName, "/") ;
sNodeName = [NSString stringWithUTF8String:szpTemp];
free (szpTemp) ;
// Create a DSoNode from the first entry and add it to the map.
nError = dsOpenDirNode (refTemp, dlpNodeName, &refNode) ;
dsDataListDeallocate (refTemp, dlpNodeName) ;
// Deallocate() only frees the nodes, not the tDataList.
free (dlpNodeName) ;
if (nError)
{
[DSoException raiseWithStatus:nError];
}
switch (inType) {
case eDSAuthenticationSearchNodeName:
case eDSContactsSearchNodeName:
case eDSNetworkSearchNodeName:
opTemp = [[DSoSearchNode alloc] initWithDir:self nodeRef:refNode nodeName:sNodeName];
break;
case eDSConfigNodeName:
opTemp = [[DSoNodeConfig alloc] initWithDir:self nodeRef:refNode nodeName:inPattern];
break;
default:
opTemp = [[DSoNode alloc] initWithDir:self nodeRef:refNode nodeName:sNodeName];
break;
}
return [opTemp autorelease];
}
/*!
* @method findNodeNames
* @abstract Finds the list of all node names registered by DS.
* Returns an empty array if no matching results are found.
* @result An array of NSString objects containing the node names.
*/
- (NSArray*) findNodeNames
{
tDirStatus nError = eDSNoErr;
tDataListPtr dlpNodeName = nil;
tContextData continueData = 0;
DSRef refTemp = 0;
DSoBuffer *bufNodeList = nil;
unsigned long i = 0;
UInt32 ulCount = 0;
char *szpTemp = nil;
NSString *sNodeName = nil;
NSMutableArray *resultList = nil;
refTemp = [self verifiedDirRef];
bufNodeList = [[DSoBuffer alloc] initWithDir:self bufferSize:1024];
resultList = [NSMutableArray array];
// Generate a list of matching nodes.
do {
nError = dsGetDirNodeList (refTemp, [bufNodeList dsDataBuffer],
&ulCount, &continueData) ;
if (nError == eDSBufferTooSmall)
{
unsigned long size = [bufNodeList getBufferSize];
[bufNodeList grow:size + size];
continue;
}
// Validate results.
if (nError) {
[bufNodeList release];
[DSoException raiseWithStatus:nError];
}
resultList = [NSMutableArray arrayWithCapacity:ulCount];
for (i = 1; i <= ulCount; i++)
{
nError = dsGetDirNodeName (refTemp, [bufNodeList dsDataBuffer], i, &dlpNodeName);
if (nError)
{
[bufNodeList release];
[DSoException raiseWithStatus:nError];
}
szpTemp = dsGetPathFromList (refTemp, dlpNodeName, "/") ;
sNodeName = [NSString stringWithUTF8String:szpTemp];
[resultList addObject:sNodeName];
free (szpTemp) ;
dsDataListDeallocate (refTemp, dlpNodeName) ;
free (dlpNodeName) ;
}
} while (continueData != 0 || nError == eDSBufferTooSmall);
if (continueData != 0)
dsReleaseContinueData(refTemp, continueData);
[bufNodeList release];
return resultList; // Already autoreleased.
}
/*!
* @method nodeBrowserItems
* @abstract Finds the all top level items for the node browser.
* @result An array of DSoNodeBrowserItem objects.
*/
- (NSArray*) nodeBrowserItems
{
NSMutableArray* browserItems = nil;
NSArray* nodeNames = [self findNodeNames];
NSMutableSet* firstComponents = [NSMutableSet set];
NSEnumerator* nodeNameEnum = [nodeNames objectEnumerator];
NSString* nodeName = nil;
while ((nodeName = (NSString*)[nodeNameEnum nextObject]) != nil)
{
NSArray* pathComponents = [nodeName pathComponents];
if ([pathComponents count] > 1)
{
[firstComponents addObject:[pathComponents objectAtIndex:1]];
}
}
browserItems = [NSMutableArray arrayWithCapacity:[firstComponents count]];
nodeNameEnum = [firstComponents objectEnumerator];
while ((nodeName = (NSString*)[nodeNameEnum nextObject]) != nil)
{
DSoNodeBrowserItem* item = [[DSoNodeBrowserItem alloc] initWithName:nodeName directory:self];
[browserItems addObject:item];
[item release];
}
return browserItems; // Already autoreleased.
}
/*!
* @method standardRecordTypes
* @abstract Retrieves all defined standard record types from the config node.
* @result An array of strings of the record types.
*/
- (NSArray*) standardRecordTypes
{
if (mRecordTypes == nil)
{
DSoNodeConfig* config = (DSoNodeConfig*)[[DSoNodeConfig alloc] initWithDir:self];
mRecordTypes = [[config findRecordNames:@kDSRecordsAll
ofType:kDSStdRecordTypeRecordTypes
matchType:eDSExact] retain];
[config release];
}
return mRecordTypes;
}
/*!
* @method standardAttributeTypes
* @abstract Retrieves all defined standard attribute types from the config node.
* @result An array of strings of the attribute types.
*/
- (NSArray*) standardAttributeTypes
{
if (mAttributeTypes == nil)
{
DSoNodeConfig* config = (DSoNodeConfig*)[[DSoNodeConfig alloc] initWithDir:self];
mAttributeTypes = [[config findRecordNames:@kDSRecordsAll
ofType:kDSStdRecordTypeAttributeTypes
matchType:eDSExact] retain];
[config release];
}
return mAttributeTypes;
}
// Convenience methods to create well-known nodes.
- (DSoNode*) localNode
{
return [self findNode:nil matchType:eDSLocalNodeNames useFirst:YES];
}
- (DSoSearchNode*) searchNode
{
DSRef refTemp = 0;
DSoBuffer *bufNodeList = nil;
DSoSearchNode *searchNode = nil;
tDataListPtr dlpName = 0;
tDirNodeReference refNode = 0;
tDirStatus nError = eDSNoErr;
UInt32 ulCount = 0 ;
char *szpTemp = nil;
NSString *sNodeName = nil;
unsigned long ulTries = 10;
// See findNode: above for similar comments.
for ( ; (ulTries-- && !searchNode) ; sleep (3)) {
// function creates and returns a DSSearchNode, not a DSoNode.
// Most of FindNode() is duplicated here because this
// function creates and returns a DSSearchNode, similar to a DSoNode.
refTemp = [self verifiedDirRef];
bufNodeList = [[DSoBuffer alloc] initWithDir:self];
do {
nError = dsFindDirNodes(refTemp, [bufNodeList dsDataBuffer], NULL, eDSSearchNodeName, &ulCount, NULL);
if (nError == eDSBufferTooSmall) {
[bufNodeList grow: [bufNodeList getBufferSize] * 2];
}
} while (nError == eDSBufferTooSmall);
if (nError != 0 || (ulCount != 1))
{
[bufNodeList release];
continue ;
}
if (nError = dsGetDirNodeName (refTemp, [bufNodeList dsDataBuffer], 1, &dlpName))
{
[bufNodeList release];
continue ;
}
[bufNodeList release];
szpTemp = dsGetPathFromList (refTemp, dlpName, "/") ;
sNodeName = [NSString stringWithUTF8String:szpTemp] ;
free (szpTemp) ;
// Open the node manually and create an instance of DSSearchNode.
nError = dsOpenDirNode (refTemp, dlpName, &refNode) ;
dsDataListDeallocate (refTemp, dlpName) ;
// Deallocate() only frees the nodes, not the tDataList.
free (dlpName) ;
if (!nError) {
searchNode = [[DSoSearchNode alloc] initWithDir:self nodeRef:refNode nodeName:sNodeName];
return [searchNode autorelease] ;
}
if (nError != eDSUnknownNodeName)
{
break ;
}
}
return [searchNode autorelease];
}
- (tDirReference)dsDirRef
{
return mDirRef;
}
@end
// ----------------------------------------------------------------------------
// Private Methods
#pragma mark ***** Private Methods *****
@implementation DSoDirectory (DSoDirectoryPrivate)
- (void)openLocalHost
{
tDirStatus nError = eDSNoErr;
[mDirRefLock lock];
if (!mDirRef)
nError = dsOpenDirService(&mDirRef);
[mDirRefLock unlock];
if (nError)
[DSoException raiseWithStatus:nError];
}
- (void)openLocalOnlyWithLocalPath:(NSString *)filePath
{
tDirStatus nError = eDSNoErr;
[mDirRefLock lock];
if (!mDirRef)
nError = dsOpenDirServiceLocal(&mDirRef, [filePath UTF8String]);
[mDirRefLock unlock];
if (nError)
[DSoException raiseWithStatus:nError];
}
- (void)openHost:(NSString*)hostName user:(NSString*)inUser password:(NSString*)inPassword
{
DSoBuffer *step = nil;
DSoBuffer *stepResponse = nil;
DSoDataNode *authMethod = nil;
UInt32 length = 0;
tDirStatus status = eDSNoErr;
NSData *userNameData = nil;
NSData *passwordData = nil;
step = [[DSoBuffer alloc] initWithDir:nil bufferSize:2048];
stepResponse = [[DSoBuffer alloc] initWithDir:nil bufferSize:2048];
authMethod = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:nil cString:kDSStdAuthNodeNativeClearTextOK];
userNameData = [inUser dataUsingEncoding:NSUTF8StringEncoding];
length = [userNameData length];
[step setData:&length length:sizeof(length)];
[step appendData:[userNameData bytes] length:length];
passwordData = [inPassword dataUsingEncoding:NSUTF8StringEncoding];
length = [passwordData length];
[step appendData:&length length:sizeof(length)];
[step appendData:[passwordData bytes] length:length];
status = dsOpenDirServiceProxy(&mDirRef, [hostName cString], 0, [authMethod dsDataNode], [step dsDataBuffer], [stepResponse dsDataBuffer], NULL);
[step release];
[stepResponse release];
[authMethod release];
if (status != eDSNoErr) {
[[DSoException name:@"DSOpenDirServiceErr" reason:@"Cannot open Directory Services Proxy." status:status] raise];
}
}
- (void)close
{
[mDirRefLock lock];
if (mDirRef)
{
dsCloseDirService(mDirRef);
mDirRef = 0;
}
[mDirRefLock unlock];
}
// This method assumes that the mDirRef has been invalidated
// and will not close the reference.
- (void)reopen
{
// If the proxyUsername is not null, then we have a proxy connection.
[self close];
if (proxyHostname)
[self openHost:proxyHostname user:proxyUsername password:proxyPassword];
else
[self openLocalHost];
}
- (DSoNodeConfig*)configNode
{
return [[[DSoNodeConfig alloc] initWithDir:self] autorelease];
}
@end

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoDirectoryPrivate
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
@class DSoNodeConfig;
@interface DSoDirectory (DSoDirectoryPrivate)
- (void)openLocalHost;
- (void)openLocalOnlyWithLocalPath:(NSString *)filePath;
- (void)openHost:(NSString*)hostName user:(NSString*)inUser password:(NSString*)inPassword;
- (void)close;
- (void)reopen;
- (DSoNodeConfig*)configNode;
@end

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoException
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
#import "DSoStatus.h"
/*!
* @defined kDSoExceptionStatusKey
* @discussion The NSString key for the status that is stored
* in the userInfo dictionary of the Exception.
* This value can also be retrieved through the -status
* method.
*/
#define kDSoExceptionStatusKey @"status"
/*!
* @class DSoException This class sub-classes NSException, adding the ability
* to easily store and retrieve a DS tDirStatus status number in the NSException's
* userInfo dictionary.
*/
@interface DSoException : NSException {
DSoStatus *_dsStat;
}
/*!
* @method name:reason:status:
* @abstract Create an autoreleased exception.
* @discussion Create an autoreleased exception and initialize it
* with the specified name, reason, and Directory Services status.
* @param name The name of the exception.
* @param reason A String with the reason for the exception.
* @param status The tDirStatus enumerated DS status value.
*/
+ (DSoException*) name:(NSString*)name reason:(NSString*)reason status:(tDirStatus)status DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method raiseWithStatus:
* @abstract Create and raise a simple DS exception.
* @discussion This method creates and raises a DS exception with
* the specified status and no name or reason.
* @param inStatus The status to use for the excpeption.
*/
+ (void) raiseWithStatus:(tDirStatus)inStatus DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method status
* @abstract Get the DS status number of the DS exception.
*/
- (tDirStatus) status DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method statusString
* @abstract Get the enumerated string representation of the status number.
* @result An NSString of the value.
*/
- (NSString*) statusString DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method statusCString
* @abstract Get the enumerated string representation of the status number.
* @result A null terminated c-string of the value.
*/
- (const char*) statusCString DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoException
*/
#import "DSoException.h"
@implementation DSoException
+ (DSoException*) name:(NSString*)inName reason:(NSString*)inReason status:(tDirStatus)inStatus
{
DSoException *selfInstance = nil;
NSDictionary *statusDict = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt:inStatus] forKey:kDSoExceptionStatusKey];
selfInstance = [[self alloc] initWithName:inName reason:inReason userInfo:statusDict];
return [selfInstance autorelease];
}
+ (void) raiseWithStatus:(tDirStatus)inStatus;
{
[[DSoException name:nil reason:nil status:inStatus] raise];
}
- (id)initWithName:(NSString *)inname reason:(NSString *)inreason userInfo:(NSDictionary *)inuserInfo
{
_dsStat = [[DSoStatus sharedInstance] retain];
return [super initWithName:inname reason:inreason userInfo:inuserInfo];
}
- (void) dealloc
{
[_dsStat release];
[super dealloc];
}
- (void) finalize
{
[super finalize];
}
- (tDirStatus) status
{
if ([self userInfo] != nil) {
NSNumber *statusNumber = [[self userInfo] objectForKey:kDSoExceptionStatusKey];
if (statusNumber != nil)
return [statusNumber intValue];
}
return eDSNoErr;
}
- (NSString*) statusString
{
return [_dsStat stringForStatus:[self status]];
}
- (const char*) statusCString
{
NSString *s = [self statusString];
return s == nil ? nil : [s cString];
}
@end

74
DSObjCWrappers/DSoGroup.h Normal file
View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoGroup
*/
#import <Foundation/Foundation.h>
#include <DirectoryService/DirectoryService.h>
#include <unistd.h> // for gid_t
#import "DSoRecord.h"
@class DSoUser;
/*!
* @class DSoGroup This class represents a record of standard type Group.
* It provides convenience methods for retrieving
* common types of information found in a group record.
*/
@interface DSoGroup : DSoRecord {
}
/*!
* @method initInNode:name:
* @abstract Create a new group in a node.
* @discussion This method is to initalize a new group.
* It will create a record in the specified node
* of type kDSStdRecordTypeGroups.
* @param inParent The node in which to create this record.
* @param inName The name of the group record.
*/
- (id)initInNode:(DSoNode*)inParent name:(NSString*)inName DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getGid
* @abstract Retrieve the gid number of this group.
* @discussion This retrieves the GroupID, or gid number
* of this group.
*/
- (gid_t) getGid DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method isMember:
* @abstract Determine if a user is a member of this group.
* @discussion This method will determine if the specified
* user is listed as a member of this group.
* @param inUser The user to check.
*/
- (BOOL) isMember:(DSoUser*)inUser DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

95
DSObjCWrappers/DSoGroup.m Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoGroup
*/
#import "DSoGroup.h"
#import "DSoDirectory.h"
#import "DSoNode.h"
#import "DSoUser.h"
#import "DSoException.h"
#import "DSoRecordPriv.h"
#import <membership.h>
@implementation DSoGroup
// ----------------------------------------------------------------------------
// ¥ DSGroup Public Class Methods
// ----------------------------------------------------------------------------
#pragma mark **** DSGroup Public Class Methods ****
- (id)initInNode:(DSoNode*)inParent recordRef:(tRecordReference)inRecRef
{
[super initInNode:inParent recordRef:inRecRef];
mType = [[NSString alloc] initWithCString:kDSStdRecordTypeGroups];
return self;
}
- (id)initInNode:(DSoNode*)inParent name:(NSString*)inName
{
return [super initInNode:inParent type:kDSStdRecordTypeGroups name:inName];
}
// ----------------------------------------------------------------------------
// ¥ DSGroup Public Instance Methods
// ----------------------------------------------------------------------------
#pragma mark **** DSGroup Public Instance Methods ****
- (gid_t) getGid
{
NSString *sGid = [self getAttribute:kDS1AttrPrimaryGroupID] ;
NSScanner *gidScanner = [[NSScanner alloc] initWithString:sGid];
long long gid = -1; //nogroup
[gidScanner scanLongLong:&gid];
[gidScanner release];
return (gid_t)gid;
}
- (BOOL) isMember:(DSoUser*)inUser
{
uuid_t user_uuid;
uuid_t group_uuid;
int isMember;
if ([inUser getGid] == [self getGid])
return YES;
if ( mbr_uid_to_uuid([inUser getUid], user_uuid) == 0 ) {
if ( mbr_gid_to_uuid([self getGid], group_uuid) == 0 ) {
if ( mbr_check_membership(user_uuid, group_uuid, &isMember) == 0 && isMember != 0 ) {
return YES;
}
}
}
return NO;
}
@end

441
DSObjCWrappers/DSoNode.h Normal file
View File

@ -0,0 +1,441 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoNode
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
#define kDSOAttrRecordType @"dsoAttrTypeWrapper:RecordType"
@class DSoDirectory, DSoRecord, DSoGroup, DSoUser;
/*!
* @class DSoNode
* @abstract Class representing a Directory Services Node. (tDirNodeReference)
* @discussion This class provides a representation of the Directory Services node.
* It provides useful operations required of a node as well
* as providing attribute information about the node.
*
* Note: In methods where a Record Type is required, the type is a C String
* as defined by constants in &lt;DirectoryServices/DirServicesConst.h&gt;
*/
@interface DSoNode : NSObject {
DSoDirectory *mDirectory;
NSString* mNodeName ; // canonical, from DS.
BOOL mIsAuthenticated;
BOOL mSupportsSetAttributeValues;
tDirNodeReference mNodeRef;
DSoGroup *mAdminGroup; // legacy code cached this group, so we will for now as well
NSLock *mCacheLock;
NSArray *mTypeList;
}
/**** Instance methods. ****/
/*!
* @method getAttributeFirstValue:
* @abstract Retrieve the first value of an attribute type.
* @discussion Convenince method for retrieving the first (and usually only)
* value of the requested attribute type.
*
* Invokes getAttribute: and grabs the first value of the array it returns.
* @param inAttributeType The DS attribute type constant to get values for.
*/
- (NSString*) getAttributeFirstValue:(const char*)inAttributeType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAttributeFirstValue:allowBinary:
* @abstract Retrieve the first value of an attribute type, allowing binary or only text
* @discussion Convenience method to retrieve the first (and usually only) value of
the requested attribute type. If allowBinary is set, it will return an
NSData, otherwise an NSString is returned. If no value is available it will
return nil.
*/
- (id) getAttributeFirstValue:(const char *)inAttributeType allowBinary:(BOOL)inAllowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAttribute:
* @abstract Retrieve a list of the attribute values of the given attribute type.
* @param inAttributeType The DS attribute type constant to get values for.
* @result An array of NSStrings with the values of the requested attribute type.
*/
- (NSArray*) getAttribute:(const char*)inAttributeType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAttribute:allowBinary:
* @abstract Retrieve a list of the attribute values of the given attribute type.
* @param inAttributeType The DS attribute type constant to get values for.
inAllowBinary Whether or not to return binary NSData or just NSStrings
* @result An array of NSStrings or NSData with the values of the requested attribute type.
*/
- (NSArray*) getAttribute:(const char*)inAttributeType allowBinary:(BOOL)inAllowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAllAttributes
* @abstract Retrieve the attribute types and values for this node.
* @discussion The keys of the dictionary are NSStrings matching the
DS attribute type constants and the values of the dictionary
are NSStrings of the corresponding values of that attribute type.
*/
- (NSDictionary*) getAllAttributes DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAllAttributesAllowingBinary:
* @abstract Retrieve the attribute types and values for this node,
allowing binary data.
* @discussion The keys of the dictionary are NSStrings matching the
DS attribute type constants and the values of the dictionary
are NSStrings or NSData (if data is binary) of the corresponding
values of that attribute type.
*/
- (NSDictionary*) getAllAttributesAllowingBinary:(BOOL)allowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getName
* @abstract The Directory Services name of this node.
*/
- (NSString*) getName DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findRecordTypes
* @abstract Retrieve a list of the record types this node contains.
* @result An array of NSStrings whose values are equal to the C string, DS Record type constants.
*/
- (NSArray*) findRecordTypes DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method hasRecordsOfType:
* @abstract Determine if the node contains any records of the specified type.
* @param inType The type of record to check for.
* @result YES if there exists at least 1 record of the specified type.
*/
- (BOOL) hasRecordsOfType:(const char*)inType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findRecordNames:andAttributes:ofType:matchType:
* @abstract Retrieve a matching list of record names.
* @discussion Searches the node for records whose names match the specified parameters
and returns a list of the matching record names (not full records).
Returns an empty array if no matching results are found.
*
* All parameters except for inAttributes must be non-null.
* @param inName The name (or name substring) to search for.
* @param inAttributes List of attribute types to return the values for.
* @param inType The type of record to search for.
* @param inMatchType The type of patterm matching to use (tDirPatternMatch).
* @result An NSArray of NSDictionarys whose keys are the attribute type name and whose values
* are a an NSArray of attribute values. It will always include the attribute kDSNAttrRecordName.
*/
- (NSArray*) findRecordNames:(NSString*)inName andAttributes:(NSArray*)inAttributes ofType:(const char*)inType matchType:(tDirPatternMatch)inMatchType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findRecordNames:ofType:matchType:
* @abstract Retrieve a matching list of record names.
* @discussion Searches the node for records whose names match the specified parameters
* and returns a list of the matching record names (not full records).
* Returns an empty array if no matching results are found.
* All parameters must be non-null. This method just calls
* -findRecordNames:andAttributes:ofType:matchType:
* with inAttributes set to nil.
* @param inName The name (or name substring) to search for.
* @param inType The type of record to search for.
* @param inMatchType The type of patterm matching to use (tDirPatternMatch).
* @result An NSArray of NSStrings whose values are the names of the matching records.
*/
- (NSArray*) findRecordNames:(NSString*)inName ofType:(const char*)inType matchType:(tDirPatternMatch)inMatchType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findRecordNamesOfTypes:withAttribute:value:matchType:
* @abstract Retrieve a list of record names with matching attribute values.
* @discussion Searches the node for records of the specified record types
* that have the specified attribute with the specified value.
* @param inTypes Array of NSStrings of the record types to search for.
* @param inAttrib The attribute type constant to search on.
* @param inValue The attribute value NSData or NSString to search for.
* @param inMatchType The type of pattern matching to use for the search.
* @result An NSArray of NSStrings whose values are the names of the matching records.
*/
- (NSArray*) findRecordNamesOfTypes:(NSArray*)inTypes withAttribute:(const char*)inAttrib value:(id)inValue matchType:(tDirPatternMatch)inMatchType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findRecordsOfTypes:withAttribute:value:matchType:
* @abstract Retrieve a list of records with matching attribute values.
* @discussion Searches the node for records of the specified record types
* that have the specified attribute with the specified value.
* @param inTypes Array of NSStrings of the record types to search for.
* @param inAttrib The attribute type constant to search on.
* @param inValue The attribute value NSData or NSString to search for.
* @param inMatchType The type of pattern matching to use for the search.
* @result An Array of NSDictionarys whose keys are the attribute types of the records
* and the values are NSArrays of the attribute values.
*/
- (NSArray*) findRecordsOfTypes:(NSArray*)inTypes withAttribute:(const char*)inAttrib value:(id)inValue matchType:(tDirPatternMatch)inMatchType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findRecordsOfTypes:withAttribute:value:matchType:allowBinary:
* @abstract Retrieve a list of records with matching attribute values.
* @discussion Searches the node for records of the specified record types
* that have the specified attribute with the specified value.
* @param inTypes Array of NSStrings of the record types to search for.
* @param inAttrib The attribute type constant to search on.
* @param inValue The attribute value NSData or NSString to search for.
* @param inMatchType The type of pattern matching to use for the search.
* @param inAllowBinary Boolean determines if call will return NSData (YES) or NSString (NO)
* @result An Array of NSDictionarys whose keys are the attribute types of the records
* and the values are NSArrays of the attribute values.
*/
- (NSArray*) findRecordsOfTypes:(NSArray*)inTypes withAttribute:(const char*)inAttrib value:(id)inValue matchType:(tDirPatternMatch)inMatchType allowBinary:(BOOL)inAllowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findRecordsOfTypes:withAttribute:value:matchType:retrieveAttributes:
* @abstract Retrieve a list of records with matching attribute values.
* @discussion Searches the node for records of the specified record types
* that have the specified attribute with the specified value.
* Only retrieve the specified list of attribute types.
* @param inTypes Array of NSStrings of the record types to search for.
* @param inAttrib The attribute type constant to search on.
* @param inValue The attribute value of type NSData or NSString to search for.
* @param inMatchType The type of pattern matching to use for the search.
* @param inAttribsToRetrieve Array of NSStrings of the attribute types to return in the result.
* @result An Array of NSDictionarys whose keys are the requested attribute types
* of the records and the values are NSArrays of the attribute values.
*/
- (NSArray*) findRecordsOfTypes:(NSArray*)inTypes withAttribute:(const char*)inAttrib value:(id)inValue matchType:(tDirPatternMatch)inMatchType retrieveAttributes:(NSArray*)inAttribsToRetrieve DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findRecordsOfTypes:withAttribute:value:matchType:retrieveAttributes:allowBinary:
* @abstract Retrieve a list of records with matching attribute values.
* @discussion Searches the node for records of the specified record types
* that have the specified attribute with the specified value.
* Only retrieve the specified list of attribute types.
* @param inTypes Array of NSStrings of the record types to search for.
* @param inAttrib The attribute type constant to search on.
* @param inValue The attribute value of type NSData or NSString to search for.
* @param inMatchType The type of pattern matching to use for the search.
* @param inAttribsToRetrieve Array of NSStrings of the attribute types to return in the result.
* @param inAllowBinary Boolean determines if call will return NSData (YES) or NSString (NO)
* @result An Array of NSDictionarys whose keys are the requested attribute types
* of the records and the values are NSArrays of the attribute values.
*/
- (NSArray*) findRecordsOfTypes:(NSArray*)inTypes withAttribute:(const char*)inAttrib value:(id)inValue matchType:(tDirPatternMatch)inMatchType retrieveAttributes:(NSArray*)inAttribsToRetrieve allowBinary:(BOOL)inAllowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findRecord:ofType:
* @abstract Find a record in the node.
* @discussion Retrieves a record object for a record in the node
* matching the specified name and type.
* @param inName The name of the record.
* @param inType The type of the record.
*/
- (DSoRecord*) findRecord:(NSString*)inName ofType:(const char*)inType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findUser:
* @abstract Find a user in the node.
* @discussion Invokes findRecord:ofType: with ofType set to kDSStdRecordTypeUsers.
* @param inName The record name of the user.
*/
- (DSoUser*) findUser:(NSString*)inName DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method findGroup:
* @abstract Find a group in the node.
* @discussion Invokes findRecord:ofType: with ofType set to kDSStdRecordTypeGroups.
* @param inName The record name of the group.
*/
- (DSoGroup*) findGroup:(NSString*)inName DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method newRecord:ofType:
* @abstract Create a new record in the node.
* @param inName The name of the new record.
* @param inType The type of the record.
*/
- (DSoRecord*) newRecord:(NSString*)inName ofType:(const char*)inType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method authenticateName:withPassword:
* @abstract Check a user's password for validity.
* @discussion Invokes authenticateName:withPassword:authOnly:
* with authOnly set to YES.
*/
- (tDirStatus) authenticateName:(NSString*)inName
withPassword: (NSString*)inPasswd DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method authenticateName:withPassword:authOnly:
* @abstract Authenticates a user in this node.
* @discussion Will attempt to authenticate a user with this node.
It optionally will persistently authenticate the user to this node
for future operations.
Simply invokes authenticateWithBufferItems:authType:authOnly:
with the name and password as the buffer items, and kDSStdAuthNodeNativeClearTextOK
kDSStdAuthNodeNativeClearTextOK as the auth type.
* @param inName The username.
* @param inPasswd The password to try.
* @param inAuthOnly Specify whether the password should just be checked (YES) or
whether the node should be authenticated to.
*/
- (tDirStatus) authenticateName:(NSString*)inName
withPassword: (NSString*)inPasswd
authOnly: (BOOL)inAuthOnly DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method authenticateWithBufferItems:authType:authOnly:
* @abstract Authenticate a user to the node
* @discussion Generic method to authenticate a user to the node. The item
* in buffer will vary according to the authentication type that is
* passed in. Basically this is slightly higher layer of dsDoDirNodeAuth().
* @param inBufferItems An array of items to pack into the buffer for dsDoDirNodeAuth().
* @param inAuthType The DS authentication type to be used (must be supported by the node).
* @param inAuthOnly Specify whether the password should just be checked (YES) or
* whether the node should be authenticated too.
*/
- (tDirStatus) authenticateWithBufferItems: (NSArray*)inBufferItems
authType: (const char*)inAuthType
authOnly: (BOOL)inAuthOnly DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method authenticateWithBufferItems:authType:authOnly:responseBufferItems:
* @abstract Authenticate a user to the node
* @discussion Generic method to authenticate a user to the node. The item
* in buffer will vary according to the authentication type that is
* passed in. Basically this is slightly higher layer of dsDoDirNodeAuth().
* @param inBufferItems An array of items to pack into the buffer for dsDoDirNodeAuth().
* @param inAuthType The DS authentication type to be used (must be supported by the node).
* @param inAuthOnly Specify whether the password should just be checked (YES) or
* whether the node should be authenticated too.
* @param outBufferItems An array of items returned from the buffer for dsDoDirNodeAuth().
*/
- (tDirStatus) authenticateWithBufferItems: (NSArray*)inBufferItems
authType: (const char*)inAuthType
authOnly: (BOOL)inAuthOnly
responseBufferItems: (NSArray**)outBufferItems DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method customCall:inputData:outputData:
* @abstract Use a custom call on the node
* @discussion Generic method to access custom calls on the node. The input
* and output data will vary based on which custom call is used.
* Basically this is slightly higher layer of dsDoPlugInCustomCall().
* @param number Number identifying which custom call to perform (usually plug-in specific).
* @param inputData Data to pass as input to the custom call.
* @param outputData Data returned from the custom call.
*/
- (tDirStatus)customCall:(int)number inputData:(NSData*)inputData
outputData:(NSMutableData*)outputData DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (tDirStatus)customCall:(int)number
sendPropertyList:(id)propList
withAuthorization:(void*)authExternalForm DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (tDirStatus)customCall:(int)number
sendData:(NSData*)data
withAuthorization:(void*)authExternalForm DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method customCall:sendItems:outputData:
* @abstract Use a custom call on the node
* @discussion Generic method to access custom calls on the node. The input
* and output data will vary based on which custom call is used.
* Basically this is slightly higher layer of dsDoPlugInCustomCall().
* @param number Number identifying which custom call to perform (usually plug-in specific).
* @param items Array of items to pack into the input buffer.
* @param outputData Data returned from the custom call.
*/
- (tDirStatus)customCall:(int)number sendItems:(NSArray*)items
outputData:(NSMutableData*)outputData DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (tDirStatus)customCall:(int)number
withAuthorization:(void*)authExternalForm DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (tDirStatus)customCall:(int)number
receiveData:(NSMutableData*)outputData
withAuthorization:(void*)authExternalForm
sizeCall:(int)sizeNumber DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method adminGroup
* @abstract Convenience method to get the admin group from this node.
*/
- (DSoGroup*) adminGroup DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method directory
* @abstract Gets the Directory object that contains this node.
*/
- (DSoDirectory*) directory DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method dsNodeReference
* @abstract Method for accessing the low-level data type.
* @result The Directory Services node reference value for this node.
*/
- (tDirNodeReference)dsNodeReference DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
// "protected" methods
// This is for internal use only, and is only a "hand pass off" object,
// thus we do not need to worry abour retain counts on the object contained here-in.
typedef struct {
DSoNode *node;
tRecordReference recordRef;
} RecID;
/*!
* @method initWithDir:nodeRef:nodeName:
* @abstract Initializes the receiver with the necessary information.
* @discussion Initializes the receiver with a pointer to inDir, which it sends
* a retain message to; a copy of the inNodeRef; and a pointer to inNodeName.
* which it also retains.
*
* This should never be called directly. Instead, instances should
* be created with DSoDirectory's findNode: methods.
*/
- (id)initWithDir:(DSoDirectory*)inDir nodeRef:(tDirNodeReference)inNodeRef
nodeName:(NSString*)inNodeName DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (RecID) _findRecord: (NSString*)inName
ofType: (const char*)inType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (BOOL)usesMultiThreaded DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (void)setUsesMultiThreaded:(BOOL)inValue DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (BOOL)supportsSetAttributeValues DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (void)setSupportsSetAttributeValues:(BOOL)inValue DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end
// The Search node is a subclass of DSoNode because it must override _FindRecord
// to find the first match's home node.
@interface DSoSearchNode: DSoNode {
}
@end

1160
DSObjCWrappers/DSoNode.m Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoNodeBrowserItem
*/
#import <Foundation/Foundation.h>
@class DSoDirectory, DSoNode;
@interface DSoNodeBrowserItem : NSObject {
DSoDirectory* _dir;
NSString* _path;
BOOL useNode;
DSoNode* _node;
NSMutableArray* _children;
}
- (DSoNodeBrowserItem*)initWithName:(NSString*)name directory:(DSoDirectory*)dir DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (DSoNodeBrowserItem*)initWithPath:(NSString*)path directory:(DSoDirectory*)dir DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (NSString*)name DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (NSString*)path DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (DSoNode*)node DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (BOOL)loadedChildren DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (BOOL)hasChildren DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (NSArray*)children DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (NSArray*)registeredChildrenPaths DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (DSoNodeBrowserItem*)childWithName:(NSString*)name DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (int)compareNames:(DSoNodeBrowserItem*)item DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoNodeBrowserItem
*/
#import "DSoNodeBrowserItem.h"
#import <DSObjCWrappers/DSObjCWrappers.h>
#ifndef kDSNAttrSubNodes
#define kDSNAttrSubNodes "dsAttrTypeStandard:SubNodes"
#endif
@implementation DSoNodeBrowserItem
- (DSoNodeBrowserItem*)initWithName:(NSString*)name directory:(DSoDirectory*)dir
{
self = [super init];
_path = [[@"/" stringByAppendingString:name] retain];
_dir = [dir retain];
useNode = NO;
return self;
}
- (DSoNodeBrowserItem*)initWithPath:(NSString*)path directory:(DSoDirectory*)dir
{
self = [super init];
_path = [path copy];
_dir = [dir retain];
useNode = YES;
return self;
}
- (void)dealloc
{
[_path release];
[_node release];
[_dir release];
[_children release];
[super dealloc];
}
- (void)finalize
{
[super finalize];
}
- (NSString*)name
{
return [_path lastPathComponent];
}
- (NSString*)path
{
return _path;
}
- (DSoNode*)node
{
@try
{
if (_node == nil && useNode)
{
_node = [[_dir findNode:[self path]] retain];
}
} @catch( NSException *exception ) {
// ignore any exceptions here
}
// give up after one failure
if (_node == nil)
useNode = NO;
return _node;
}
- (BOOL)loadedChildren
{
return _children != nil;
}
- (BOOL)hasChildren
{
if (_children != nil) {
return [_children count] > 0;
} else {
return [[self registeredChildrenPaths] count] > 0;
}
}
- (NSArray*)registeredChildrenPaths
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSArray *findResults = nil;
NSArray *nameComponents = nil;
NSString *name = nil;
unsigned long i = 0;
unsigned long count = 0;
int currentComponentCount = 0;
int iCompCount = 0;
NSMutableSet *childSet = [NSMutableSet set];
NSString *path = [self path];
NSArray *subNodes = nil;
@try
{
findResults = [_dir findNodeNames:path matchType:eDSStartsWith];
count = [findResults count];
// examine results to find only immediate child nodes.
// We do this by comparing the number of components in the node names
// using "/" as the component divider.
currentComponentCount = [[path pathComponents] count];
for (i = 0; i < count; i++)
{
name = [findResults objectAtIndex:i];
nameComponents = [name pathComponents];
iCompCount = [nameComponents count];
if (iCompCount == currentComponentCount + 1)
{
[childSet addObject:name];
}
else if (iCompCount > currentComponentCount + 1)
{
[childSet addObject:[NSString pathWithComponents:[nameComponents
subarrayWithRange:NSMakeRange(0,currentComponentCount+1)]]];
}
}
} @catch( NSException *exception ) {
// ignore exceptions here
}
subNodes = [[childSet allObjects] retain];
[pool drain];
return [subNodes autorelease];
}
- (NSArray*)children
{
// children could come from either dsFindDirNodes/dsGetDirNodeList,
// or dsGetDirNodeInfo on the current node
if (_children == nil)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSArray *findResults = nil;
NSString *name = nil;
NSMutableSet *childSet = [NSMutableSet set];
NSEnumerator *childEnum = nil;
NSArray *subNodes = nil;
_children = [NSMutableArray new];
@try
{
findResults = [self registeredChildrenPaths];
[childSet addObjectsFromArray:findResults];
} @catch( NSException *exception ) {
// ignore exceptions here
}
@try
{
subNodes = [[self node] getAttribute:kDSNAttrSubNodes];
[childSet addObjectsFromArray:subNodes];
} @catch( NSException *exception ) {
// ignore exceptions here
}
childEnum = [childSet objectEnumerator];
while ((name = (NSString*)[childEnum nextObject]) != nil)
{
DSoNodeBrowserItem* item = [[DSoNodeBrowserItem alloc] initWithPath:name
directory:_dir];
[_children addObject:item];
[item release];
}
[pool drain];
}
return _children;
}
- (DSoNodeBrowserItem*)childWithName:(NSString*)name
{
NSArray* children = [self children];
NSEnumerator* childEnum = [children objectEnumerator];
DSoNodeBrowserItem* child = nil;
while ((child = [childEnum nextObject]) != nil)
{
if ([[child name] isEqualToString:name])
return child;
}
return nil;
}
- (int)compareNames:(DSoNodeBrowserItem*)item
{
return [[self name] caseInsensitiveCompare:[item name]];
}
@end

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoNodeConfig
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
#import "DSoNode.h"
@class DSoDirectory;
@interface DSoNodeConfig : DSoNode {
}
- (DSoNodeConfig*) initWithDir:(DSoDirectory*)inDir DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (NSArray*) getPluginList DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (NSDictionary*)getAttributesAndValuesForPlugin:(NSString*)inPluginName DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (BOOL)pluginEnabled:(NSString*)inPluginName DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (void)setPlugin:(NSString*)inPluginName enabled:(BOOL)enabled DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (void)setPlugin:(NSString*)inPluginName enabled:(BOOL)enabled withAuthorization:(void*)inAuthExtForm DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

View File

@ -0,0 +1,323 @@
/*
* Copyright (c) 2003-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoNodeConfig
*/
#import "DSoNodeConfig.h"
#import "DSoBuffer.h"
#import "DSoDirectory.h"
#import "DSoRecord.h"
#import "DSoAttributeUtils.h"
#import "DSoDataList.h"
#import "DSoException.h"
#import "DSoRecordPriv.h"
#include <Security/Authorization.h>
#include <DirectoryService/DirServicesConstPriv.h>
@implementation DSoNodeConfig
- (DSoNodeConfig*)init
{
[super init];
[mTypeList release];
mTypeList = [[NSArray alloc] initWithObjects:
@kDSStdRecordTypePlugins,
@kDSStdRecordTypeAttributeTypes,
@kDSStdRecordTypeRecordTypes,
nil];
return self;
}
- (DSoNodeConfig*)initWithDir:(DSoDirectory*)inDir
{
tDataListPtr dlpNodeName = nil;
DSRef dirRef = 0;
DSoBuffer *bufNodeList = nil;
const char *cNodeName = nil;
UInt32 nodeCount = 0;
tDirStatus nError = eDSNoErr;
tContextData context = 0;
[self init];
dirRef = [inDir verifiedDirRef];
bufNodeList = [[DSoBuffer alloc] initWithDir:inDir];
do {
nError = dsFindDirNodes (dirRef, [bufNodeList dsDataBuffer], NULL,
eDSConfigNodeName, &nodeCount, &context) ;
if (nError == eDSBufferTooSmall) {
[bufNodeList grow: [bufNodeList getBufferSize] * 2];
}
} while (nError == eDSBufferTooSmall);
if (context != 0) {
dsReleaseContinueData(dirRef, context);
}
nError = dsGetDirNodeName (dirRef, [bufNodeList dsDataBuffer], 1, &dlpNodeName);
cNodeName = dsGetPathFromList (dirRef, dlpNodeName, "/") ;
mNodeName = [[NSString alloc] initWithCString:cNodeName];
free ((void *) cNodeName) ;
nError = dsOpenDirNode (dirRef, dlpNodeName, &mNodeRef) ;
dsDataListDeallocate (dirRef, dlpNodeName) ;
free (dlpNodeName) ;
mDirectory = [inDir retain];
[bufNodeList release];
return self;
}
- (DSoRecord*) findRecord:(NSString*)inName ofType:(const char*)inType
{
return [[[DSoRecord alloc] initInNode:self type:inType name:inName create:NO] autorelease] ;
}
- (NSArray*) getPluginList
{
return [self findRecordNames:@kDSRecordsAll
ofType:kDSStdRecordTypePlugins
matchType:eDSExact];
}
- (NSDictionary*)getAttributesAndValuesForPlugin:(NSString*)inPluginName
{
tContextData localcontext = 0;
tRecordEntryPtr pRecEntry = nil;
tAttributeListRef attrListRef = 0;
DSoDataList *recName = nil;
DSoDataList *recType = [[DSoDataList alloc] initWithDir:mDirectory cString:kDSStdRecordTypePlugins];
DSoDataList *attrType = [[DSoDataList alloc] initWithDir:mDirectory cString:kDSAttributesAll];
DSoBuffer *recordBuf = [[DSoBuffer alloc] initWithDir:mDirectory bufferSize:4096];
id pluginAttributes = nil;
tDirStatus err = eDSNoErr;
UInt32 i = 0;
UInt32 returnCount = 0;
UInt32 totalCount = 0;
UInt16 len = 0;
id sysVersion = [self getAttribute: kDS1AttrOperatingSystemVersion];
if (sysVersion == nil || [sysVersion isEqual: @"10.6"]) {
recName = [[DSoDataList alloc] initWithDir:mDirectory cString:kDSRecordsAll];
}
else {
recName = [[DSoDataList alloc] initWithDir:mDirectory cString:[inPluginName UTF8String]];
}
do {
err = dsGetRecordList([self dsNodeReference], [recordBuf dsDataBuffer], [recName dsDataList], eDSExact, [recType dsDataList],
[attrType dsDataList], FALSE, &returnCount, &localcontext);
if (err == eDSBufferTooSmall) {
[recordBuf grow: [recordBuf getBufferSize] * 2];
continue;
}
for (i = 1; i <= returnCount && pluginAttributes == nil; i++) {
err = dsGetRecordEntry([self dsNodeReference], [recordBuf dsDataBuffer], i, &attrListRef, &pRecEntry);
if (err == eDSNoErr) {
memcpy(&len, &pRecEntry->fRecordNameAndType.fBufferData, 2);
if (!strncmp([inPluginName UTF8String], pRecEntry->fRecordNameAndType.fBufferData + 2, len)) {
pluginAttributes = [DSoAttributeUtils getAttributesAndValuesInNode: self
fromBuffer: recordBuf
listReference: attrListRef
count: pRecEntry->fRecordAttributeCount];
}
dsDeallocRecordEntry([mDirectory dsDirRef], pRecEntry);
dsCloseAttributeList(attrListRef);
}
}
totalCount += returnCount;
} while (pluginAttributes == nil && (err == eDSBufferTooSmall || (err == eDSNoErr && localcontext != 0)));
if (localcontext != 0) {
dsReleaseContinueData([self dsNodeReference], localcontext);
}
[recordBuf release];
[recName release];
[attrType release];
[recType release];
if (err)
[DSoException raiseWithStatus:err];
return pluginAttributes;
}
- (BOOL)pluginEnabled:(NSString*)inPluginName
{
NSDictionary *pluginAttribs = [self getAttributesAndValuesForPlugin:inPluginName];
return [[(NSArray*)[pluginAttribs objectForKey:@kDS1AttrFunctionalState] objectAtIndex:0] isEqualToString:@"Active"];
}
- (void)setPlugin:(NSString*)inPluginName enabled:(BOOL)enabled
{
[self setPlugin:inPluginName enabled:enabled withAuthorization:NULL];
}
- (void)setPlugin:(NSString*)inPluginName enabled:(BOOL)enabled withAuthorization:(void*)inAuthExtForm
{
tContextData localcontext = 0;
tRecordEntryPtr pRecEntry = NULL;
tAttributeEntryPtr pAttrEntry = NULL;
tAttributeValueEntryPtr pAttrValueEntry = NULL;
tAttributeListRef attrListRef = 0;
tAttributeValueListRef attrValueListRef = 0;
char* nameStr = NULL;
DSoDataList *recName = [(DSoDataList*)[DSoDataList alloc] initWithDir:mDirectory cString:kDSRecordsAll];
DSoDataList *recType = [(DSoDataList*)[DSoDataList alloc] initWithDir:mDirectory cString:kDSStdRecordTypePlugins];
DSoDataList *attrType = [(DSoDataList*)[DSoDataList alloc] initWithDir:mDirectory cString:kDSAttributesAll];
DSoBuffer *recordBuf = [[DSoBuffer alloc] initWithDir:mDirectory bufferSize:4096];
tDirStatus err = eDSNoErr;
UInt32 i, j, returnCount = 0;
BOOL wasEnabled = NO;
int pluginIndex = 0;
do {
returnCount = 0;
err = dsGetRecordList([self dsNodeReference], [recordBuf dsDataBuffer],
[recName dsDataList], eDSExact, [recType dsDataList], [attrType dsDataList],
FALSE, &returnCount, &localcontext);
if (err == eDSBufferTooSmall)
{
[recordBuf grow:2 * [recordBuf getBufferSize]];
continue;
}
for (i = 1; i <= returnCount; i++)
{
err = dsGetRecordEntry([self dsNodeReference],[recordBuf dsDataBuffer],i,&attrListRef, &pRecEntry );
if (err == eDSNoErr)
err = dsGetRecordNameFromEntry( pRecEntry, &nameStr );
if (nameStr != NULL && strcmp([inPluginName UTF8String], nameStr) == 0)
{
// Get all attributes
for ( j = 1; j <= pRecEntry->fRecordAttributeCount; j++ )
{
err = dsGetAttributeEntry( [self dsNodeReference], [recordBuf dsDataBuffer], attrListRef, j,
&attrValueListRef, &pAttrEntry );
if (err != eDSNoErr || pAttrEntry == NULL) continue;
if (!strcmp(pAttrEntry->fAttributeSignature.fBufferData,kDS1AttrFunctionalState))
{
// Get only one attribute value even if there are more
err = dsGetAttributeValue( [self dsNodeReference],
[recordBuf dsDataBuffer], 1, attrValueListRef,
&pAttrValueEntry );
if ( err == eDSNoErr && pAttrValueEntry != NULL
&& pAttrValueEntry->fAttributeValueData.fBufferData != NULL)
{
wasEnabled = strcmp(pAttrValueEntry->fAttributeValueData.fBufferData,
"Active") == 0;
}
}
else if (!strcmp(pAttrEntry->fAttributeSignature.fBufferData,kDS1AttrPluginIndex))
{
err = dsGetAttributeValue( [self dsNodeReference],
[recordBuf dsDataBuffer], 1, attrValueListRef,
&pAttrValueEntry );
if ( err == eDSNoErr )
{
pluginIndex = pAttrValueEntry->fAttributeValueData.fBufferLength;
}
}
dsCloseAttributeValueList( attrValueListRef );
attrValueListRef = 0;
if ( pAttrValueEntry != NULL ) {
dsDeallocAttributeValueEntry( [mDirectory dsDirRef], pAttrValueEntry );
pAttrValueEntry = NULL;
}
if ( pAttrEntry != NULL ) {
dsDeallocAttributeEntry( [mDirectory dsDirRef], pAttrEntry );
pAttrEntry = NULL;
}
} // loop over j -- all attributes
i = returnCount; // Abort the search loop by forcing the iterator to the max.
if (localcontext != 0)
{
dsReleaseContinueData([self dsNodeReference], localcontext);
localcontext = 0;
}
}
if (nameStr != NULL)
{
free(nameStr);
nameStr = NULL;
}
dsDeallocRecordEntry([mDirectory dsDirRef], pRecEntry);
dsCloseAttributeList(attrListRef);
}
} while (err == eDSBufferTooSmall || (err == eDSNoErr && localcontext != 0));
if (localcontext != 0) {
dsReleaseContinueData([self dsNodeReference], localcontext);
}
if (err == eDSNoErr && wasEnabled != enabled) {
// need to toggle the state
AuthorizationExternalForm authExtForm;
if (inAuthExtForm == NULL) {
bzero(&authExtForm,sizeof(authExtForm));
inAuthExtForm = &authExtForm;
}
err = [self customCall:1000+pluginIndex withAuthorization:inAuthExtForm];
}
[recordBuf release];
[recName release];
[attrType release];
[recType release];
if (err)
[DSoException raiseWithStatus:err];
}
- (NSArray*) findRecordTypes
{
NSMutableArray *setOfTypes = (NSMutableArray*)[super findRecordTypes];
if ([setOfTypes count] > 0)
return setOfTypes;
setOfTypes = [mTypeList mutableCopy];
// Alphabetize the list.
[setOfTypes sortUsingSelector:@selector(caseInsensitiveCompare:)];
return [setOfTypes autorelease];
}
@end

312
DSObjCWrappers/DSoRecord.h Normal file
View File

@ -0,0 +1,312 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoRecord
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
@class DSoDirectory, DSoNode, DSoDataNode, DSoBuffer;
/*!
* @class DSoRecord
* @abstract Class representing a Directory Services node record.
* @discussion This class provides a wrapper around the DS record reference.
* It provides useful functions for retrieving information about the record.
*/
@interface DSoRecord : NSObject {
DSoNode *mParent ;
tRecordReference mRecRef ;
NSString *mName ;
NSString *mType;
// Grab a pointer to the node's associated Directory object for convenience,
// but it won't be retained; we retain the node, which is already retaining the directory
DSoDirectory *mDirectory;
}
/**** Instance methods. ****/
/*!
* @method initInNode:recordRef:type:
* @abstract Initialize object with an existing record reference and a type string.
* @discussion This should never be invoked directly. Record objects should
* be retrieved with the methods for doing so that DSoNode provides.
* @param inParent The Node object that contains this record.
* @param inRecRef The DS record reference number referring to this record.
* @param inType The DS string constant for type of this record.
*/
- (DSoRecord*)initInNode:(DSoNode*)inParent recordRef:(tRecordReference)inRecRef type:(const char*)inType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method initInNode:type:name:
* @abstract Initialize object with a type string and record name.
* @discussion This should never be invoked directly. Record objects should
* be created with the methods for doing so that DSoNode provides.
* This method will create a brand new object to be inserted
* into the specified node as the specified type with the specified name.
* @param inParent The Node object that will contain this record.
* @param inType The DS string constant for the type of this record.
* @param inName The record name for this record.
*/
- (DSoRecord*)initInNode:(DSoNode*)inParent type:(const char*)inType name:(NSString*)inName DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
// simple accessors.
/*!
* @method getName
* @abstract Retrieve the record's name.
*/
- (NSString*)getName DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getType
* @abstract Retrieve the record's DS type string constant.
*/
- (const char*)getType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method node
* @abstract Retrieve a pointer to the Record's container node.
*/
- (DSoNode*)node DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
// Calculation methods.
/*!
* @method attributeCount
* @abstract Retrieve the number of attribute types this record has.
*/
- (unsigned long)attributeCount DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
//- (NSArray*)getAttributeTypes;
/*!
* @method getAllAttributes
* @abstract Retrieve a list of the attribute types this record has.
* @result An array of NSString objects whose values are the names of the attribute types.
*/
- (NSArray*)getAllAttributes DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAllAttributesAndValues
* @abstract Retrieve a dictionary of all the attributes and values for this record.
* @result An NSDictionary whose keys are the attribute type names
* and whose values are NSArray objects containing a list of the values
* for that attribute type.
*/
- (NSDictionary*)getAllAttributesAndValues DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAttributes:
* @abstract Retrieve a dictionary of the specified attributes and values for this record.
* @result An NSDictionary whose keys are the attribute type names
* and whose values are NSArray objects containing a list of the values
* for that attribute type.
*/
- (NSDictionary*)getAttributes:(NSArray*)inAttributes DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAttribute:
* @abstract Get the first value of a specific attribute type.
* @discussion Record attributes, or attribute types, can contain
* multiple values.
* This method will return the first value of the specified attribute.
* @result An NSString containing the first value of the given attribute type.
*/
- (NSString*)getAttribute:(const char*)inAttributeType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (id)getAttribute:(const char*)inAttributeType allowBinary:(BOOL)inAllowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAttribute:index:
* @abstract Get a particular value of a specific attribute type.
* @discussion Record attributes, or attribute types, can contain
* multiple values.
* This method will return a specific value as identified
* by its (1-based) index in the list of values.
* @param inAttributeType The DS constant for a known attribute type or the string for an unknown type.
* @param inIndex The index of the value desired. The first value has an index of '1'.
* @result An NSString containing the first value of the given attribute type.
*/
- (NSString*)getAttribute:(const char*)inAttributeType index:(unsigned long)inIndex DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (id)getAttribute:(const char*)inAttributeType index:(unsigned long)inIndex allowBinary:(BOOL)inAllowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAttribute:range:
* @abstract Get a particular value of a specific attribute type.
* @discussion Record attributes, or attribute types, can contain
* multiple values.
* This method will return a list of values in the specified range.
* @param inAttributeType The DS constant for a known attribute type or the string for an unknown type.
* @param inRange An NSRange values specifying the desired range. The first value has a location of 1.
* @result An array of NSString objects containing the values of the desired attribute.
*/
- (NSArray*)getAttribute:(const char*)inAttributeType range:(NSRange)inRange DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
- (NSArray*)getAttribute:(const char*)inAttributeType range:(NSRange)inRange allowBinary:(BOOL)inAllowBinary DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getAttributeValueCount:
* @abstract Get the number of values for an attribute type.
* @discussion Returns the number of values in the record for the
* specified attribute type.
* @param inAttributeType The DS constant for a known attribute type or the string for an unknown type.
* @result The number of values.
*/
- (unsigned long)getAttributeValueCount:(const char*)inAttributeType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method setAttribute:value:
* @abstract Create an attribute and give it a single value.
* @discussion Invokes setAttribute:values: with values set to an
* single valued array containing inAttributeValue.
* @param inAttributeType The DS constant for a known attribute type or the string for an unknown type.
* @param inAttributeValue An NSString or NSData object containing the value of the new attribute.
*/
- (void)setAttribute:(const char*)inAttributeType value:(id)inAttributeValue DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method setAttribute:values:
* @abstract Create an attribute and set its values.
* @discussion This method will create an attribute of the given
* attribute type with values of those contained in the specified array.
*
* If this attribute already exists, its values get overwritten by the new values.
* @param inAttributeType The DS constant for a known attribute type or the string for an unknown type.
* @param inAttributeValues An array of NSString or NSData objects containing the values of the new attribute.
*/
- (void)setAttribute:(const char*)inAttributeType values:(NSArray*)inAttributeValues DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method addAttribute:values:
* @abstract Add values to an existing attribute, merging values.
* @discussion Invokes addAttribute:values:mergeValues: with mergeValues set to YES.
*/
- (void)addAttribute:(const char*)inAttributeType values:(NSArray*)inAttributeValues DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method addAttribute:values:mergeValues:
* @abstract Add values to an existing attribute, merging values.
* @discussion This will add a values to an existing attribute type. If the
* provided attribute and value already exist, then this method
* will not add it again if mergVals is set to YES, otherwise it
* will add the value a second time if mergVals is set to NO.
* @param inAttributeType The DS constant for a known attribute type.
* @param inAttributeValues An array of NSString objects containing the values to add.
* @param mergVals NO or YES depending on if you want to add the value again or not.
*/
- (void)addAttribute:(const char*)inAttributeType values:(NSArray*)inAttributeValues mergeValues:(BOOL)mergVals DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method changeAttribute:oldValue:newValue:
* @abstract Change an existing attribute value to a new value.
* @discussion This method will look for an existing attribute value
* and replace that value with a new value.
* @param inAttributeType The DS constant for a known attribute type.
* @param inAttrValue The existing old value to be changed.
* @param inNewAttrValue The new value to replace the old value.
*/
- (void)changeAttribute:(const char*)inAttributeType oldValue:(NSString*)inAttrValue newValue:(id)inNewAttrValue DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method changeAttribute:index:newValue:
* @abstract Change an existing attribute value to a new value.
* @discussion This method will replace an existing attribute value
* as referenced by its 1-based index, and replace it with a new value.
* @param inAttributeType The DS constant for a known attribute type.
* @param inIndex The index of the old value to change The first value has an index of '1'
* @param inNewAttrValue The new value to replace the old value.
*/
- (void)changeAttribute:(const char*)inAttributeType index:(unsigned int)inIndex newValue:(id)inNewAttrValue DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method attributeExists:withValue:
* @abstract Determines whether an attribute value exists.
* @discussion Searches the record for the given record type and
* determines whether it contains the given value.
* @param inAttributeType The DS constant for a known attribute type.
* @param inAttributeValue The value to search for.
* @result YES if the value exists for this attribute, NO otherwise.
*/
- (BOOL)attributeExists:(const char*)inAttributeType withValue:(id)inAttributeValue DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method removeAttribute:
* @abstract Remove an attribute type and its values.
* @discussion Removes an attribute (type) and all its values.
* @param inAttributetype The DS constant for a known attribute type in the record.
*/
- (void)removeAttribute:(const char*)inAttributeType DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method removeAttribute:value:
* @abstract Remove a value from an attribute type by value.
* @discussion Removes an existing value of the specified
* attribute type.
* @param inAttributetype The DS constant for a known attribute type in the record.
* @param inAttributeValue The value to remove NSData or NSString.
*/
- (void)removeAttribute:(const char*)inAttributeType value:(id)inAttributeValue DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method removeAttribute:values:
* @abstract Remove a list of values from an attribute type by value names.
* @discussion Removes existing values of the specified
* attribute type as identified by the values themselves.
* @param inAttributetype The DS constant for a known attribute type in the record.
* @param inAttributeValues Array of NSStrings or NSDatas with the values to remove.
*/
- (void)removeAttribute:(const char*)inAttributeType values:(NSArray*)inAttributeValues DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method removeAttribute:index:
* @abstract Remove a value from an attribute type by index.
* @discussion Removes an existing value as identified by its index
* of the specified attribute type.
* @param inAttributetype The DS constant for a known attribute type in the record.
* @param inIndex The index of the value to remove.
*/
- (void)removeAttribute:(const char*)inAttributeType index:(unsigned int)inIndex DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method removeRecord
* @abstract Remove this record from the node.
* @discussion This method will immediately remove the record this object
* represents from the Directory Services node that it belongs to.
* After calling this method, this object should be sent a "release" message
* since any further operations on the object will result in Exceptions
* being raised, or unpredictable results.
*/
- (void)removeRecord DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
// Other methods.
/*!
* @method dsRecordReference
* @abstract Method for accessing the low-level data type.
* @result The DS record reference number for this record.
*/
- (tRecordReference)dsRecordReference DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

886
DSObjCWrappers/DSoRecord.m Normal file
View File

@ -0,0 +1,886 @@
/*
* Copyright (c) 2003-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoRecord
*/
#import "DSoRecord.h"
#import "DSoRecordPriv.h"
#import "DSoNode.h"
#import "DSoBuffer.h"
#import "DSoDataNode.h"
#import "DSoDataList.h"
#import "DSoGroup.h"
#import "DSoUser.h"
#import "DSoException.h"
#import "DSoAttributeUtils.h"
@class DSoUser, DSoGroup;
#define DS_API_IS_UNSUPPORTED(err) (err == eNotHandledByThisNode \
|| err == eNotYetImplemented \
|| err == eNoLongerSupported \
|| err == eUnknownAPICall)
@implementation DSoRecord
// ----------------------------------------------------------------------------
// ¥ DSRecord Public Instance Methods
// ----------------------------------------------------------------------------
#pragma mark **** Public Instance Methods ****
// ctor & dtor
- (id)init
{
[super init];
mDirectory = nil;
mParent = nil;
mName = nil;
mRecRef = 0;
return self;
}
- (DSoRecord*)initInNode:(DSoNode*)inParent recordRef:(tRecordReference)inRecRef type:(const char*)inType
{
DSoRecord *returnRec = self;
// If the type is a known type for which we have a more specialized sub-class,
// then return an object of that type.
if (!strcmp(inType, kDSStdRecordTypeUsers))
returnRec = [[DSoUser alloc] initInNode:inParent recordRef:inRecRef];
else if (!strcmp(inType, kDSStdRecordTypeGroups))
returnRec = [[DSoGroup alloc] initInNode:inParent recordRef:inRecRef];
else
{
[self initInNode:inParent recordRef:inRecRef];
mType = [[NSString alloc] initWithCString:inType];
}
if (returnRec != self)
[self release];
return returnRec;
}
- (DSoRecord*)initInNode:(DSoNode*)inParent type:(const char*)inType name:(NSString*)inName
{
return [self initInNode:inParent type:inType name:inName create:YES];
}
- (void)dealloc
{
if (mRecRef)
dsCloseRecord(mRecRef);
[mParent release];
[mName release];
[mType release];
[super dealloc];
}
- (void)finalize
{
if (mRecRef)
dsCloseRecord(mRecRef);
[super finalize];
}
// Inline accessors.
- (NSString*)getName
{
return mName;
}
- (const char*)getType
{
return [mType UTF8String];
}
- (DSoNode*)node
{
return mParent;
}
// Casting operators.
- (tRecordReference)dsRecordReference
{
return mRecRef;
}
/******************
* attributeCount *
******************/
- (unsigned long)attributeCount
{
tDirStatus nError = eDSNoErr;
tRecordEntryPtr recordInfo = nil;
unsigned long count = 0;
if (nError = dsGetRecordReferenceInfo(mRecRef, &recordInfo))
[DSoException raiseWithStatus:nError];
count = recordInfo->fRecordAttributeCount;
if (nError = dsDeallocRecordEntry([[mParent directory] dsDirRef], recordInfo))
[DSoException raiseWithStatus:nError];
return count;
}
/****************
* GetAttribute *
****************/
- (NSArray*)getAllAttributes
{
return [self _getAllAttributesIncludeValues:NO];
}
- (NSDictionary*)getAllAttributesAndValues
{
return [self _getAllAttributesIncludeValues:YES];
}
- (NSDictionary*)getAttributes:(NSArray*)inAttributes
{
return [self _getAttributes:inAttributes includeValues:YES];
}
- (NSString*)getAttribute:(const char*)inAttributeType
{
return [self getAttribute: inAttributeType allowBinary: NO];
}
- (id)getAttribute:(const char*)inAttributeType allowBinary:(BOOL)inAllowBinary
{
id returnValue = nil;
// we want to catch the exception here, as the user is just asking for the attribute.
// If there isn't one, we should just return nil
@try
{
returnValue = [self getAttribute: inAttributeType index: 1 allowBinary: inAllowBinary];
} @catch( NSException *exception ) {
// ignore all exceptions
}
return returnValue;
}
- (NSString*)getAttribute:(const char*)inAttributeType index:(unsigned long)inIndex
{
return [self getAttribute: inAttributeType index: inIndex allowBinary: NO];
}
- (id)getAttribute:(const char*)inAttributeType index:(unsigned long)inIndex allowBinary:(BOOL)inAllowBinary
{
tDirStatus err ;
DSRef dirRef = [mDirectory verifiedDirRef];
tAttributeValueEntryPtr pAttrVal = nil;
DSoDataNode *type = nil;
NSString *sValue = nil;
type = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
err = dsGetRecordAttributeValueByIndex (mRecRef, [type dsDataNode], inIndex, &pAttrVal);
[type release];
if (err)
[DSoException raiseWithStatus:err];
sValue = [DSoAttributeUtils getAttributeFromBuffer: &pAttrVal->fAttributeValueData allowBinary: inAllowBinary];
dsDeallocAttributeValueEntry (dirRef, pAttrVal) ;
return sValue;
}
/*********************
* GetAttributeRange *
*********************/
// get a list of attribute values of given type in given range
- (NSArray*)getAttribute:(const char*)inAttributeType range:(NSRange)inRange
{
return [self getAttribute: inAttributeType range: inRange allowBinary: NO];
}
- (NSArray*)getAttribute:(const char*)inAttributeType range:(NSRange)inRange allowBinary:(BOOL)inAllowBinary
{
tDirStatus err = eDSNoErr;
DSRef dirRef = [mDirectory verifiedDirRef];
tAttributeValueEntryPtr pAttrVal = nil;
unsigned long i = 0;
DSoDataNode *type = nil;
NSMutableArray *valueList = [[NSMutableArray alloc] initWithCapacity:inRange.length];
type = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
for (i = inRange.location; i < (inRange.location + inRange.length); i++)
{
err = dsGetRecordAttributeValueByIndex (mRecRef, [type dsDataNode], i, &pAttrVal);
if (err)
{
[valueList release];
[type release];
[DSoException raiseWithStatus:err];
}
[valueList addObject: [DSoAttributeUtils getAttributeFromBuffer: &pAttrVal->fAttributeValueData allowBinary: inAllowBinary]];
dsDeallocAttributeValueEntry (dirRef, pAttrVal) ;
pAttrVal = nil;
}
[type release];
return [valueList autorelease];
}
/*************************
* getAttributeValueCount *
**************************/
- (unsigned long)getAttributeValueCount:(const char*)inAttributeType
{
tAttributeEntryPtr pAttrEntry = nil;
DSoDataNode *attrType = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
tDirStatus err = eDSNoErr;
unsigned long valueCount = 0;
err = dsGetRecordAttributeInfo(mRecRef, [attrType dsDataNode], &pAttrEntry);
[attrType release];
if (err)
[DSoException raiseWithStatus:err];
valueCount = pAttrEntry->fAttributeValueCount;
dsDeallocAttributeEntry([mDirectory dsDirRef], pAttrEntry);
return valueCount;
}
/*****************
* SetAttributes *
*****************/
- (void)setAttribute:(const char*)inAttributeType value:(id)inAttributeValue
{
// this call can throw, make an autorelease array so it gets released
[self setAttribute:inAttributeType values:[NSArray arrayWithObject:inAttributeValue]];
}
- (void)setAttribute:(const char*)inAttributeType values:(NSArray*)inAttributeValues
{
tDirStatus err = eDSNoErr;
DSoDataNode *attrType = nil;
DSoDataNode *attrValue = nil;
DSoDataList *attrValuesList = nil;
register unsigned int i = 0;
unsigned long count = [inAttributeValues count];
tAttributeEntryPtr entryPtr = nil;
tAttributeValueEntryPtr attrPtr = nil;
tDataNodePtr attrTypeNodePtr = NULL;
DSRef dirRef = 0;
// Make sure the directory is valid.
dirRef = [mDirectory verifiedDirRef];
attrType = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
attrTypeNodePtr = [attrType dsDataNode]; // convenience pointer to avoid a lot of method calls.
if ([mParent supportsSetAttributeValues])
{
attrValuesList = [[DSoDataList alloc] initWithDir: mDirectory values: inAttributeValues];
err = dsSetAttributeValues (mRecRef, attrTypeNodePtr, [attrValuesList dsDataList]);
[attrValuesList release];
if (DS_API_IS_UNSUPPORTED(err))
{
// not supported by this node, fall back to the old approach
[mParent setSupportsSetAttributeValues:NO];
}
else if (err != eDSEmptyDataList)
{
[attrType release];
if (err)
[DSoException raiseWithStatus:err];
dsFlushRecord( mRecRef );
return;
}
}
// initialize the first value:
attrValue = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory value:[inAttributeValues objectAtIndex:0]];
// For simplicity, try to just remove current attribute if it exists
@try
{
err = dsRemoveAttribute (mRecRef, attrTypeNodePtr) ;
// If the attribute can't be removed then try to delete all but the
// first value and replace the first value with the new first value
if (err) {
err = dsGetRecordAttributeInfo (mRecRef, attrTypeNodePtr, (tAttributeEntryPtr *) &entryPtr);
if (!err && entryPtr->fAttributeValueCount > 0)
{
// Delete all but the first value.
for (i = 2 ; i <= entryPtr->fAttributeValueCount; i++)
{
err = dsGetRecordAttributeValueByIndex (mRecRef, attrTypeNodePtr, 1, (tAttributeValueEntryPtr *) &attrPtr);
if (!err)
{
err = dsRemoveAttributeValue(mRecRef, attrTypeNodePtr,
attrPtr->fAttributeValueID);
dsDeallocAttributeValueEntry(dirRef, attrPtr);
attrPtr = nil;
}
if (err)
[DSoException raiseWithStatus:err];
}
// Now replace the first value with the new first value
err = dsGetRecordAttributeValueByIndex (mRecRef, attrTypeNodePtr, 1, (tAttributeValueEntryPtr *) &attrPtr);
if (!err)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Want this method to be memory contained
id firstObject = [inAttributeValues objectAtIndex:0];
const char *newFirstValue = NULL;
unsigned long newFirstValueLen = 0;
tAttributeValueEntryPtr newValueEntry;
if( [firstObject isKindOfClass:[NSString class]] )
{
newFirstValue = [firstObject UTF8String];
newFirstValueLen = strlen( newFirstValue );
}
else if( [firstObject isKindOfClass:[NSData class]] )
{
newFirstValue = [firstObject bytes];
newFirstValueLen = [firstObject length];
}
else
{
@throw [NSException exceptionWithName: NSInvalidArgumentException reason: @"[DSoRecord setAttribute:values:] values contained non NSData nor NSString" userInfo: nil];
}
newValueEntry = dsAllocAttributeValueEntry(dirRef, attrPtr->fAttributeValueID, (void *)newFirstValue, newFirstValueLen );
// We're done with attrPtr, dealloc it
dsDeallocAttributeValueEntry(dirRef, attrPtr);
attrPtr = nil;
// Set the first value, then dealloc the valueEntry item.
err = dsSetAttributeValue(mRecRef, attrTypeNodePtr, newValueEntry);
dsDeallocAttributeValueEntry(dirRef, newValueEntry);
[pool drain];
}
if (err)
[DSoException raiseWithStatus:err];
}
else {
// if there was an error getting the record attribute info, then maybe the attribute
// didn't ever exist and we can just add it.
err = dsAddAttribute (mRecRef, attrTypeNodePtr, 0, [attrValue dsDataNode]);
if (err)
[DSoException raiseWithStatus:err];
}
dsDeallocAttributeEntry(dirRef, entryPtr);
entryPtr = nil;
}
else
{
// The former attribute was successfully removed, add the first new attribute.
err = dsAddAttribute (mRecRef, [attrType dsDataNode], 0, [attrValue dsDataNode]);
if (err)
[DSoException raiseWithStatus:err];
}
} @catch( NSException *exception ) {
[attrType release]; // need to release this cause we don't release until the end normally
@throw;
} @finally {
if (attrPtr != nil)
dsDeallocAttributeValueEntry(dirRef, attrPtr);
if (entryPtr != nil)
dsDeallocAttributeEntry(dirRef, entryPtr);
[attrValue release];
}
for (i = 1; i < count; i++)
{
DSoDataNode *dnValue = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory value:[inAttributeValues objectAtIndex:i]];
err = dsAddAttributeValue (mRecRef, attrTypeNodePtr, [dnValue dsDataNode]);
[dnValue release];
if (err)
{
[attrType release];
[DSoException raiseWithStatus:err];
}
}
dsFlushRecord( mRecRef );
[attrType release];
}
/*****************
* AddAttributes *
*****************/
// Add each attribute to the attribute list; if that particular attribute value
// exists and mergeValues == true, don't add a duplicate
- (void)addAttribute:(const char*)inAttributeType values:(NSArray*)inAttributeValues
{
[self addAttribute:inAttributeType values:inAttributeValues mergeValues:YES];
}
- (void)addAttribute:(const char*)inAttributeType values:(NSArray*)inAttributeValues mergeValues:(BOOL)inMergVals
{
register unsigned int i = 0;
tDirStatus err = eDSNoErr ;
DSoDataNode *attrType = nil;
unsigned long count = [inAttributeValues count];
[mDirectory verifiedDirRef];
attrType = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
for (i = 0; i < count; i++)
{
if (!inMergVals
|| ![self attributeExists:inAttributeType withValue:[inAttributeValues objectAtIndex:i]]) {
DSoDataNode *dnValue;
dnValue = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory value:[inAttributeValues objectAtIndex:i]];
err = dsAddAttributeValue (mRecRef, [attrType dsDataNode], [dnValue dsDataNode]);
[dnValue release];
if (err)
{
[attrType release];
[DSoException raiseWithStatus:err];
}
}
}
dsFlushRecord( mRecRef );
[attrType release];
}
/*******************
* ChangeAttribute *
*******************/
// change the attribute whose value is inAttrValue to inNewAttrValue
- (void)changeAttribute:(const char*)inAttributeType oldValue:(NSString*)inAttrValue newValue:(id)inNewAttrValue
{
tDirStatus err = eDSNoErr;
tAttributeValueEntryPtr attrValuePtr= nil;
tAttributeValueEntryPtr newValue = nil;
DSRef dirRef = [mDirectory verifiedDirRef];
DSoDataNode *attrType = nil;
unsigned long newValueLen = 0;
const char *newValuePtr = NULL;
attrType = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
@try
{
attrValuePtr = [self getAttrValuePtrForTypeNode:attrType value:inAttrValue];
} @catch (NSException *exception ) {
[attrType release];
@throw;
}
if( [inNewAttrValue isKindOfClass:[NSString class]] )
{
newValuePtr = [inNewAttrValue UTF8String];
newValueLen = strlen( newValuePtr );
}
else if( [inNewAttrValue isKindOfClass:[NSData class]] )
{
newValuePtr = [inNewAttrValue bytes];
newValueLen = [inNewAttrValue length];
}
else
{
[attrType release];
@throw [NSException exceptionWithName: NSInvalidArgumentException reason: @"[DSoRecord changeAttribute:oldValue:newValue:] new value was not NSData nor NSString" userInfo: nil];
}
newValue = dsAllocAttributeValueEntry( dirRef, attrValuePtr->fAttributeValueID, (void *)newValuePtr, newValueLen ) ;
dsDeallocAttributeValueEntry (dirRef, attrValuePtr) ;
if (newValue == nil)
{
[attrType release];
[DSoException raiseWithStatus:eDSAllocationFailed];
}
err = dsSetAttributeValue (mRecRef, [attrType dsDataNode], newValue);
[attrType release];
dsDeallocAttributeValueEntry (dirRef, newValue) ;
if (err)
[DSoException raiseWithStatus:err];
dsFlushRecord( mRecRef );
}
- (void)changeAttribute:(const char*)inAttributeType index:(unsigned int)inIndex newValue:(id)inNewAttrValue
{
tDirStatus err = eDSNoErr;
tAttributeValueEntryPtr attrValuePtr= nil;
tAttributeValueEntryPtr newValue = nil ;
DSRef dirRef = [mDirectory verifiedDirRef];
DSoDataNode *attrType = nil;
const char *newValuePtr = NULL;
unsigned long newValueLen = 0;
attrType = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
err = dsGetRecordAttributeValueByIndex (mRecRef, [attrType dsDataNode],
inIndex, &attrValuePtr);
if (err)
{
[attrType release];
[DSoException raiseWithStatus:err];
}
if( [inNewAttrValue isKindOfClass:[NSString class]] )
{
newValuePtr = [inNewAttrValue UTF8String];
newValueLen = strlen( newValuePtr );
}
else if( [inNewAttrValue isKindOfClass:[NSData class]] )
{
newValuePtr = [inNewAttrValue bytes];
newValueLen = [inNewAttrValue length];
}
else
{
[attrType release];
@throw [NSException exceptionWithName: NSInvalidArgumentException reason: @"[DSoRecord changeAttribute:index:newValue:] value was not NSData nor NSString" userInfo: nil];
}
newValue = dsAllocAttributeValueEntry( dirRef, attrValuePtr->fAttributeValueID, (void *)newValuePtr, newValueLen ) ;
dsDeallocAttributeValueEntry (dirRef, attrValuePtr) ;
if (newValue == nil)
{
[attrType release];
[DSoException raiseWithStatus:eDSAllocationFailed];
}
err = dsSetAttributeValue (mRecRef, [attrType dsDataNode], newValue);
[attrType release];
dsDeallocAttributeValueEntry (dirRef, newValue) ;
if (err)
[DSoException raiseWithStatus:err];
dsFlushRecord( mRecRef );
}
/*******************
* AttributeExists *
*******************/
- (BOOL)attributeExists:(const char*)inAttributeType withValue:(id)inAttributeValue
{
DSRef dirRef = [mDirectory verifiedDirRef];
DSoDataNode *attrType = nil;
tAttributeValueEntryPtr attrPtr = nil;
BOOL bExists = NO ;
if (!inAttributeValue || [inAttributeValue length] == 0)
return NO;
attrType = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
@try
{
attrPtr = [self getAttrValuePtrForTypeNode:attrType value:inAttributeValue];
dsDeallocAttributeValueEntry (dirRef, attrPtr) ;
bExists = YES ;
} @catch (NSException *exception ) {
// ignore any exceptions here.
}
[attrType release];
return bExists;
}
- (void)removeAttribute:(const char*)inAttributeType
{
DSoDataNode *attrType = nil;
tDirStatus nError = eDSNoErr;
if (!inAttributeType || inAttributeType[0] == '\0')
return;
attrType = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
nError = dsRemoveAttribute (mRecRef, [attrType dsDataNode]) ;
[attrType release];
if (nError)
[DSoException raiseWithStatus:nError];
dsFlushRecord( mRecRef );
}
- (void)removeAttribute:(const char*)inAttributeType value:(id)inAttributeValue
{
// this call can throw, make an autorelease array so it gets released
[self removeAttribute:inAttributeType values:[NSArray arrayWithObject:inAttributeValue]];
}
- (void)removeAttribute:(const char*)inAttributeType values:(NSArray*)inAttributeValues
{
tDirStatus nError = eDSNoErr;
tAttributeValueEntryPtr attrValuePtr = nil;
DSRef dirRef = [mDirectory verifiedDirRef];
DSoDataNode *attrType = nil;
int i = 0;
int cnt = 0;
if (inAttributeValues == nil)
return;
attrType = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
cnt = [inAttributeValues count];
for (i = 0; i < cnt; i++)
{
@try
{
attrValuePtr = [self getAttrValuePtrForTypeNode:attrType value:[inAttributeValues objectAtIndex:i]];
} @catch( NSException *exception ) {
[attrType release];
@throw;
}
nError = dsRemoveAttributeValue (mRecRef, [attrType dsDataNode], attrValuePtr->fAttributeValueID);
dsDeallocAttributeValueEntry (dirRef, attrValuePtr) ;
}
[attrType release];
if (nError)
[DSoException raiseWithStatus:nError];
dsFlushRecord( mRecRef );
}
- (void)removeAttribute:(const char*)inAttributeType index:(unsigned int)inIndex
{
tDirStatus nError = eDSNoErr;
tAttributeValueEntryPtr attrValuePtr = nil;
DSRef dirRef = [mDirectory verifiedDirRef];
DSoDataNode *attrType = nil;
attrType = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inAttributeType];
nError = dsGetRecordAttributeValueByIndex (mRecRef, [attrType dsDataNode],
inIndex, &attrValuePtr);
if (nError)
{
[attrType release];
[DSoException raiseWithStatus:nError];
}
nError = dsRemoveAttributeValue (mRecRef, [attrType dsDataNode], attrValuePtr->fAttributeValueID);
dsDeallocAttributeValueEntry (dirRef, attrValuePtr);
[attrType release];
if (nError)
[DSoException raiseWithStatus:nError];
dsFlushRecord( mRecRef );
}
- (void)removeRecord
{
tDirStatus err ;
if (err = dsDeleteRecord (mRecRef))
[DSoException raiseWithStatus:err];
// mRecRef will now be invalid... should I set it to 0 to trigger any asserts on anything that tries to use it?
}
@end
#pragma mark
// ----------------------------------------------------------------------------
// Protected Instance Methods
// ----------------------------------------------------------------------------
#pragma mark **** Protected Instance Methods ****
@implementation DSoRecord (DSoRecordPrivate)
- (DSoRecord*)initInNode:(DSoNode*)inParent recordRef:(tRecordReference)inRecRef
{
[self init];
mParent = [inParent retain];
mDirectory = [inParent directory];
mRecRef = inRecRef;
mName = [[self getAttribute:kDSNAttrRecordName] retain];
return self;
}
- (DSoRecord*)initInNode:(DSoNode*)inParent type:(const char*)inType name:(NSString*)inName create:(BOOL)inShouldCreate
{
tDirStatus nError;
[self init];
mDirectory = [inParent directory];
if (inShouldCreate)
{
DSoDataNode *type, *name;
type = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory cString:inType];
name = [(DSoDataNode*)[DSoDataNode alloc] initWithDir:mDirectory string:inName];
nError = dsCreateRecordAndOpen ([inParent dsNodeReference], [type dsDataNode],
[name dsDataNode], &mRecRef) ;
[type release];
[name release];
if (nError)
[DSoException raiseWithStatus:nError];
}
mName = [inName retain];
mParent = [inParent retain];
mType = [[NSString alloc] initWithCString:inType];
if( [mType isEqualToString:@kDSStdRecordTypeUsers] ||
[mType isEqualToString:@kDSStdRecordTypeGroups] ||
[mType isEqualToString:@kDSStdRecordTypeComputerLists] ||
[mType isEqualToString:@kDSStdRecordTypeComputers] )
{
CFUUIDRef uuidRef = CFUUIDCreate( NULL );
NSString* uuidString = [(NSString*)CFUUIDCreateString( NULL, uuidRef ) autorelease];
CFRelease( uuidRef );
[self setAttribute:kDS1AttrGeneratedUID value:uuidString];
}
return self;
}
/*
* _getAllAttributesIncludeValues:
*
* This method makes the following assumptions:
* 1) The short names (RecordName) of all records in the node for this record
* are unique.
* 2) dsGetRecordList() will always return first the record whose RecordName
* matches the record search name criteria, and any records whose RealNames
* match the search name critera will never be returned first.
*/
- (id)_getAllAttributesIncludeValues:(BOOL)inIncludeVals
{
return [self _getAttributes:[NSArray arrayWithObject:@kDSAttributesAll] includeValues:inIncludeVals];
}
- (id)_getAttributes:(NSArray*)inAttributes includeValues:(BOOL)inIncludeVals
{
tContextData localcontext = 0;
tRecordEntryPtr pRecEntry = nil;
tAttributeListRef attrListRef = 0;
DSoBuffer *recordBuf = nil;
DSoDataList *recName = [(DSoDataList*)[DSoDataList alloc] initWithDir:mDirectory string:mName];
DSoDataList *recType = [(DSoDataList*)[DSoDataList alloc] initWithDir:mDirectory string:mType];
DSoDataList *attrType = [(DSoDataList*)[DSoDataList alloc] initWithDir:mDirectory values:inAttributes];
id userAttributes = nil;
tDirStatus err = eDSNoErr;
UInt32 returnCount = 0;
UInt32 foundCount = 0;
// default to an 8k buffer initially, the inline DS buffer is 16k so plenty of room
recordBuf = [[DSoBuffer alloc] initWithDir:mDirectory bufferSize:8192];
do {
err = dsGetRecordList([mParent dsNodeReference], [recordBuf dsDataBuffer], [recName dsDataList], eDSExact, [recType dsDataList], [attrType dsDataList], !inIncludeVals, &returnCount, &localcontext);
if (!err && returnCount > 0)
{
err = dsGetRecordEntry([mParent dsNodeReference],[recordBuf dsDataBuffer],1,&attrListRef, &pRecEntry );
foundCount += returnCount;
if (inIncludeVals)
{
userAttributes = [DSoAttributeUtils getAttributesAndValuesInNode: mParent
fromBuffer: recordBuf
listReference: attrListRef
count: pRecEntry->fRecordAttributeCount];
}
else
{
userAttributes = [DSoAttributeUtils getAttributesInNode: mParent
fromBuffer: recordBuf
listReference: attrListRef
count: pRecEntry->fRecordAttributeCount];
}
if (pRecEntry != NULL)
{
dsDeallocRecordEntry([mDirectory dsDirRef], pRecEntry);
}
if (attrListRef != 0)
{
dsCloseAttributeList(attrListRef);
}
}
else if (err == eDSBufferTooSmall)
{
[recordBuf grow:2 * [recordBuf getBufferSize]];
}
} while (err == eDSBufferTooSmall || (err == eDSNoErr && localcontext != 0));
if (localcontext != 0)
dsReleaseContinueData([mParent dsNodeReference], localcontext);
[recordBuf release];
[recName release];
[attrType release];
[recType release];
if (err)
[DSoException raiseWithStatus:err];
else if (foundCount != 1)
[[DSoException name:@"eDSInvalidRecordName"
reason:@"DSoRecord's getAllAttributes failed because more than one matching name was found in the node. This should never happen."
status:eDSInvalidRecordName] raise];
return userAttributes;
}
/***************************
* _GetAttrValuePtrByValue *
***************************/
- (tAttributeValueEntryPtr) getAttrValuePtrForTypeNode:(DSoDataNode*)inAttrType value:(id)inAttrValue
{
register unsigned int i = 1 ;
tDirStatus err ;
tAttributeEntryPtr entryPtr ;
tAttributeValueEntryPtr attrPtr ;
DSRef dirRef = [mDirectory dsDirRef];
const char *pAttrValue = nil;
int pAttrValueLen = 0;
if( [inAttrValue isKindOfClass:[NSString class]] ) {
pAttrValue = [inAttrValue UTF8String];
pAttrValueLen = strlen( pAttrValue );
} else if( [inAttrValue isKindOfClass:[NSData class]] ) {
pAttrValue = [inAttrValue bytes];
pAttrValueLen = [inAttrValue length];
} else {
@throw [NSException exceptionWithName: NSInvalidArgumentException reason: @"[DSoRecord getAttrValuePtrForTypeNode:] value was not NSString nor NSData" userInfo: nil];
}
if (err = dsGetRecordAttributeInfo (mRecRef, [inAttrType dsDataNode], &entryPtr))
[DSoException raiseWithStatus:err];
#warning can use dsGetAttributeValueByValue instead of looping values
while (i <= entryPtr->fAttributeValueCount) {
// walk through the list of values for this attribute
if (err = dsGetRecordAttributeValueByIndex (mRecRef, [inAttrType dsDataNode], i++,
&attrPtr))
continue ;
// if the lengths are the same and the contents are the same
if (pAttrValueLen == attrPtr->fAttributeValueData.fBufferLength &&
memcmp(pAttrValue, attrPtr->fAttributeValueData.fBufferData, attrPtr->fAttributeValueData.fBufferLength) == 0) {
dsDeallocAttributeEntry (dirRef, entryPtr) ;
return attrPtr ;
}
dsDeallocAttributeValueEntry (dirRef, attrPtr) ;
}
dsDeallocAttributeEntry (dirRef, entryPtr) ;
[DSoException raiseWithStatus:eDSAttributeNotFound];
return nil; // For the sake of the compiler not complaining
}
@end

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoRecordPrivate
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
@class DSoDirectory, DSoNode, DSoDataNode, DSoBuffer;
@interface DSoRecord (DSoRecordPrivate)
- (DSoRecord*)initInNode:(DSoNode*)inParent recordRef:(tRecordReference)inRecRef;
- (DSoRecord*)initInNode:(DSoNode*)inParent type:(const char*)inType name:(NSString*)inName create:(BOOL)inShouldCreate;
- (id)_getAllAttributesIncludeValues:(BOOL)inIncludeVals;
- (id)_getAttributes:(NSArray*)inAttributes includeValues:(BOOL)inIncludeVals;
- (tAttributeValueEntryPtr) getAttrValuePtrForTypeNode:(DSoDataNode*)inAttrType value:(id)inAttrValue;
@end

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoStatus
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
@interface DSoStatus : NSObject {
NSDictionary *_errDict;
}
+(DSoStatus*)sharedInstance DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
-(NSString*) stringForStatus:(int)value DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method cStringForStatus
* @abstract Retrieve the tDirStatus enum label as a string.
* @discussion This will retrieve a C String of the tDirStatus enum label
* for the given tDirStatus and must be freed by the caller.
*/
-(char*) cStringForStatus:(int)value DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoStatus
*/
#import "DSoStatus.h"
static DSoStatus *_sharedInstance = nil;
@implementation DSoStatus
-(void) dealloc
{
if( self == _sharedInstance ) {
_sharedInstance = nil;
}
[super dealloc];
}
-(void) finalize
{
if( self == _sharedInstance ) {
_sharedInstance = nil;
}
[super finalize];
}
+(DSoStatus*)sharedInstance
{
if (_sharedInstance == nil) {
_sharedInstance = [[DSoStatus alloc] init];
}
return _sharedInstance;
}
-(NSString*) stringForStatus:(int)value
{
NSString *returnValue = @"Unknown status code";
char *dsError = dsCopyDirStatusName( (SInt32) value );
if ( dsError != NULL ) {
returnValue = [NSString stringWithUTF8String: dsError];
free( dsError );
}
return returnValue;
}
-(char*) cStringForStatus:(int)value
{
return(dsCopyDirStatusName((long)value));
}
@end

109
DSObjCWrappers/DSoUser.h Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoUser
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
#import <unistd.h> // for uid_t and gid_t
#import "DSoRecord.h"
/*!
* @class DSoUser This class represents a record of standard type User.
* It provides convenience methods for retrieving
* common types of information found in a user record.
*/
@interface DSoUser : DSoRecord {
}
/*!
* @method initInNode:name:
* @abstract Create a new user in a node.
* @discussion This method is to initalize a new user.
* It will create a record in the specified node
* of type kDSStdRecordTypeUsers.
* @param inParent The node in which to create this record.
* @param inName The name of the user record.
*/
- (id)initInNode:(DSoNode*)inParent name:(NSString*)inName DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getUid
* @abstract Retrieve the uid number of the user.
* @discussion This retrieves the UniqueID, or uid number
* of a user.
*/
- (uid_t) getUid DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method getGid
* @abstract Retrieve the primary gid number of the user.
* @discussion This retrieves the GroupID, or gid number
* of the primary group of this user user.
*/
- (gid_t) getGid DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method authenticate:
* @abstract Check the user's password.
* @discussion This takes a password and checks
* it for authenticity. It does not authenticate the user
* to its node. See DSoNode's
* authenticateName:withPassword:authOnly:
* @result Returns eDSNoErr if the password is correct,
* else the status of the authentication attempt.
*/
- (tDirStatus) authenticate:(NSString*)inPassword DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method setPassword:
* @abstract Set a new password for the user.
* @discussion Takes a new password from an NSString and does a
* doDirNodeAuth() with the setpassword Auth Method.
* @result Will raise an exception if it fails.
*/
- (void) setPassword:(NSString*)inNewPassword DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method changePassword:toNewPassword:
* @abstract Change a user's password from one to another.
* @discussion Takes the old and new password and does a
* doDirNodeAuth() with the changepassword Auth Method.
* @result Will raise an exception if it fails.
*/
- (void)changePassword:(NSString*)inOldPassword toNewPassword:(NSString*)inNewPassword DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
/*!
* @method isAdmin
* @abstract Determine if the user is an admin for this node.
* @discussion This method determines if the user is
* in the member list of the admin group for the user's node.
*/
- (BOOL) isAdmin DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER;
@end

133
DSObjCWrappers/DSoUser.m Normal file
View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSoUser
*/
#import "DSoUser.h"
#import "DSoNode.h"
#import "DSoGroup.h"
#import "DSoBuffer.h"
#import "DSoDataNode.h"
#import "DSoException.h"
#import "DSoRecordPriv.h"
@implementation DSoUser
- (id)initInNode:(DSoNode*)inParent recordRef:(tRecordReference)inRecRef
{
[super initInNode:inParent recordRef:inRecRef];
mType = [[NSString alloc] initWithCString:kDSStdRecordTypeUsers];
return self;
}
- (id)initInNode:(DSoNode*)inParent name:(NSString*)inName
{
return [super initInNode:inParent type:kDSStdRecordTypeUsers name:inName];
}
// ----------------------------------------------------------------------------
// ¥ DSUser Public Instance Methods
// ----------------------------------------------------------------------------
#pragma mark **** DSUser Public Instance Methods ****
- (uid_t) getUid
{
NSString *sUid = [self getAttribute:kDS1AttrUniqueID] ;
NSScanner *uidScanner = [[NSScanner alloc] initWithString:sUid];
long long uid;
BOOL success = [uidScanner scanLongLong:&uid];
[uidScanner release];
if (success)
return (uid_t)uid;
else
return (uid_t) -2 ; // nobody
}
- (gid_t) getGid
{
NSString *sGid = [self getAttribute:kDS1AttrPrimaryGroupID] ;
NSScanner *gidScanner = [[NSScanner alloc] initWithString:sGid];
long long gid;
BOOL success = [gidScanner scanLongLong:&gid];
[gidScanner release];
if (success)
return (gid_t)gid;
else
return (gid_t) -1 ; // nogroup
}
- (tDirStatus) authenticate:(NSString*)inPassword
{
return [mParent authenticateName:[self getName] withPassword:inPassword] ;
}
- (void) setPassword:(NSString*)inNewPassword
{
NSArray *nameAndPassword = [[NSArray alloc] initWithObjects:[self getName], inNewPassword, nil];
tDirStatus status = [mParent authenticateWithBufferItems:nameAndPassword
authType:kDSStdAuthSetPasswdAsRoot authOnly:NO];
[nameAndPassword release];
if(status != eDSNoErr)
[DSoException raiseWithStatus:status];
}
- (void)changePassword:(NSString*)inOldPassword toNewPassword:(NSString*)inNewPassword
{
NSArray *oldAndNewPassword = [[NSArray alloc] initWithObjects:[self getName], inOldPassword, inNewPassword, nil];
tDirStatus status = [mParent authenticateWithBufferItems:oldAndNewPassword
authType:kDSStdAuthChangePasswd authOnly:NO];
[oldAndNewPassword release];
if(status != eDSNoErr)
[DSoException raiseWithStatus:status];
}
- (BOOL) isAdmin
{
BOOL bAdmin = NO;
if ([self getUid] == 0)
return YES;
@try
{
bAdmin = [[mParent adminGroup] isMember:self];
} @catch( DSoException *exception ) { // only catching DSoExceptions, let NSException go..
// If this is not a eDSRecordNotFound (meaning there is no admin group),
// rethrow the exception, letting default NO be the return for eDSRecordNotFound.
if( [exception status] != eDSRecordNotFound ) {
@throw;
}
}
return bAdmin;
}
@end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>DSObjCWrappers</string>
<key>CFBundleIdentifier</key>
<string>com.apple.DSObjCWrappers.Framework</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>DSObjCWrappersFramework</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>10.7</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(RC_ProjectSourceVersion)</string>
</dict>
</plist>

1205
commonC/dscommon.c Normal file

File diff suppressed because it is too large Load Diff

121
commonC/dscommon.h Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header dscommon
* Record access methods via the DirectoryService API.
*/
#ifndef _dscommon_h_
#define _dscommon_h_ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <curses.h>
#include <sys/types.h>
#include <sys/param.h>
#include <unistd.h>
#include <termios.h>
#include <pwd.h>
#include <DirectoryService/DirectoryService.h>
#ifdef __cplusplus
extern "C" {
#endif
#pragma mark -
#pragma mark Text Input Routines
void intcatch ( int dontcare);
char* read_passphrase ( const char *prompt,
int from_stdin);
#pragma mark -
#pragma mark DS API Support Routines
bool singleAttributeValueMissing ( tDirReference inDSRef,
tDirNodeReference inDSNodeRef,
char* inRecordType,
char* inAttributeType,
char* inAttributeValue,
SInt32 *outResult,
bool inVerbose);
char* createNewuid ( tDirReference inDSRef,
tDirNodeReference inDSNodeRef,
bool inVerbose);
char* createNewgid ( tDirReference inDSRef,
tDirNodeReference inDSNodeRef,
bool inVerbose);
char* createNewGUID ( bool inVerbose);
SInt32 addRecordParameter ( tDirReference inDSRef,
tDirNodeReference inDSNodeRef,
tRecordReference inRecordRef,
char* inAttrType,
char* inAttrName,
bool inVerbose);
tRecordReference createAndOpenRecord ( tDirReference inDSRef,
tDirNodeReference inDSNodeRef,
char* inRecordName,
char* inRecordType,
SInt32 *outResult,
bool inVerbose);
SInt32 getAndOutputRecord ( tDirReference inDSRef,
tDirNodeReference inDSNodeRef,
char* inRecordName,
char* inRecordType,
bool inVerbose);
tDirNodeReference getNodeRef ( tDirReference inDSRef,
char* inNodename,
char* inUsername,
char* inPassword,
bool inVerbose);
char* getSingleRecordAttribute ( tDirReference inDSRef,
tDirNodeReference inDSNodeRef,
char* inRecordName,
char* inRecordType,
char* inAttributeType,
SInt32 *outResult,
bool inVerbose);
tRecordReference openRecord ( tDirReference inDSRef,
tDirNodeReference inDSNodeRef,
char* inRecordName,
char* inRecordType,
SInt32 *outResult,
bool inVerbose);
bool UserIsMemberOfGroup ( tDirReference inDSRef,
tDirNodeReference inDSNodeRef,
const char* shortName,
const char* groupName );
#ifdef __cplusplus
}
#endif
#endif // _dscommon_h_

47
commonC/dstools_version.c Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* dstools_version.c
* DSTools
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dstools_version.h"
//-----------------------------------------------------------------------------
// dsToolAppleVersionExit
//
// prints the build version to stdout.
//-----------------------------------------------------------------------------
void dsToolAppleVersionExit( const char *toolName )
{
printf( "%s, Apple Inc., Version %s (build %s)\n", toolName, TOOLS_VERSION, BUILD_VERSION );
exit( 0 );
}

37
commonC/dstools_version.h Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef BUILD_VERSION
#define BUILD_VERSION "engineering"
#define TOOLS_VERSION "engineering"
#endif
#ifdef __cplusplus
extern "C" {
#endif
void dsToolAppleVersionExit( const char *toolName );
#ifdef __cplusplus
};
#endif

107
dirt/DSAuthenticate.h Normal file
View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSAuthenticate
* DSAuthenticate provides access to authentication functionality
* in Directory Services.
* It provides routines for authenticating a user against the
* local node, search path, or a specific named node.
* It will also search the authentication search policy to find
* a user without authenticating that user.
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirectoryService.h>
#import "DSException.h"
#import "DSStatus.h"
#define kBufferBlockSize 512
@interface DSAuthenticate : NSObject {
tDirReference _DirRef;
tDirNodeReference _SearchNodeRef;
tDirPatternMatch _SearchNodeNameToUse;
char *_SearchObjectType; // Is either user or group.
NSMutableArray *_MasterUserList;
DSStatus *_dsStat;
@private
}
- (void) dealloc;
- (void) reset;
// ============================================================================
// Configuring the object
//
- (void)useAuthenticationSearchPath; // Default
- (void)useContactSearchPath;
- (void)searchForUsers; //Default
- (void)searchForGroups;
// ============================================================================
// Wrapper methods for Directory Service Utility functions
//
- (void)allocateDataBuffer:(tDataBufferPtr*)buffer
withNumberOfBlocks:(unsigned short) numberOfBlocks
shouldReallocate:(BOOL) reAllocate;
- (tDirStatus)deallocateDataBuffer:(tDataBufferPtr)buffer;
- (tDirStatus)deallocateDataList:(tDataListPtr)list;
- (tDirStatus)deallocateDataNode:(tDataNodePtr)node;
// ============================================================================
// Private utility methods for accessing, obtaining and opening
// directory nodes.
//
- (tDataBufferPtr) retrieveLocalNode;
- (tDataBufferPtr) retrieveSearchPathNode;
- (tDataListPtr) getNodeNameForBuffer:(tDataBufferPtr)buffer;
- (tDirNodeReference) openDirNodeWithName:(tDataListPtr)nodeName;
// ============================================================================
// Private methods for performing search functionality in
// Directory Services.
//
- (tDirStatus)fetchRecordListOnSearchNodeMatchingName:(NSString*)inUsername;
- (tDirStatus)fetchRecordListOnNode:(tDirNodeReference)nodeRefToSearch matchingName:(NSString*)inUsername;
- (NSString*)nodePathStrForSearchNodeRecordNumber:(unsigned long)recordNumber;
// ============================================================================
// Public methods for accessing the Directory Service functions
// that this class provides.
//
- (tDirStatus)authOnNodePath:(NSString*)nodePathStr username:(NSString*)inUsername password:(NSString*)inPassword;
- (tDirStatus)authenticateInNodePathStr:(NSString*)nodePathStr username:(NSString*)inUsername
password:(NSString*)inPassword;
- (tDirStatus)authenticateInNode:(tDirNodeReference)userNode username:(NSString*)inUsername
password:(NSString*)inPassword;
- (tDirStatus)authUserOnLocalNode:(NSString*)inUsername password:(NSString*)inPassword;
- (tDirStatus)authUserOnSearchPath:(NSString*)inUsername password:(NSString*)inPassword;
- (NSArray*)getListOfNodesWithUser:(NSString*)inUsername;
@end

921
dirt/DSAuthenticate.m Normal file
View File

@ -0,0 +1,921 @@
/*
* Copyright (c) 2000-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSAuthenticate
*/
#import "DSAuthenticate.h"
#import <Security/checkpw.h>
extern BOOL doVerbose;
@implementation DSAuthenticate
- init
{
tDirStatus status = eDSNoErr;
[super init];
_SearchNodeRef = 0;
_dsStat = [[DSStatus sharedInstance] retain];
[self useAuthenticationSearchPath];
[self searchForUsers];
if (doVerbose)
{
printf("---> dsOpenDirService() ........................ ");
fflush(stdout);
}
status = dsOpenDirService(&_DirRef);
if (doVerbose)
{
[_dsStat printOutErrorMessage:"Status" withStatus:status];
}
if (status != eDSNoErr)
{
[[DSException name:@"DSOpenDirServiceErr" reason:@"Cannot open Directory Services." status:status] raise];
[_dsStat release];
}
_MasterUserList = [[NSMutableArray alloc] init];
return self;
}
- (void) dealloc
{
if (_SearchNodeRef != 0)
dsCloseDirNode(_SearchNodeRef);
if (_DirRef != 0)
dsCloseDirService(_DirRef);
if (_MasterUserList != nil)
[_MasterUserList release];
[_dsStat release];
[super dealloc];
}
- (void) reset
{
if (_SearchNodeRef != 0)
{
dsCloseDirNode(_SearchNodeRef);
_SearchNodeRef = 0;
}
[self useAuthenticationSearchPath];
[self searchForUsers];
if (_MasterUserList != nil)
[_MasterUserList release];
_MasterUserList = [[NSMutableArray alloc] init];
}
// ------------------------------------------------------------------
// useAuthenticationSearchPath
//
// Set this object to use the Authentication search node.
// This is the default behavior.
// ------------------------------------------------------------------
- (void)useAuthenticationSearchPath
{
_SearchNodeNameToUse = eDSSearchNodeName;
}
// ------------------------------------------------------------------
// useContactSearchPath
//
// Set this object to use the Contacts search node, instead of
// the Authentication search node.
// ------------------------------------------------------------------
- (void)useContactSearchPath
{
_SearchNodeNameToUse = eDSContactsSearchNodeName;
}
// ------------------------------------------------------------------
// searchForUsers
//
// Set this object to search for users.
// This is the default behavior.
// ------------------------------------------------------------------
- (void)searchForUsers
{
_SearchObjectType = kDSStdRecordTypeUsers;
}
// ------------------------------------------------------------------
// searchForGroups
//
// Set this object to search for groups, instead of users.
// ------------------------------------------------------------------
- (void)searchForGroups
{
_SearchObjectType = kDSStdRecordTypeGroups;
}
// ============================================================================
// Wrapper methods for Directory Service Utility functions
//
// These methods provide wrappers for some DS utility functions.
// Most of the wrapped functions require
// an argument that is a reference to an open Directory server.
// These automatically provide that reference from the class's
// members.
// ------------------------------------------------------------------
// allocateDataBuffer: withNumberOfBlocks: shouldReallocate:
//
// Allocates memory for the passed in tDataBufferPtr. It expects
// an argument with the number of blocks of memory to allocate,
// where the block size is specified in the class's header file.
// The final parameter specifies whether the buffer has previously
// been allocated memory and should thus be deallocated before
// allocating the new amount.
// ------------------------------------------------------------------
- (void)allocateDataBuffer:(tDataBufferPtr*)buffer
withNumberOfBlocks:(unsigned short) numberOfBlocks
shouldReallocate:(BOOL) reAllocate
{
if (reAllocate == YES)
{
tDirStatus status;
status = dsDataBufferDeAllocate(_DirRef, *buffer);
}
*buffer = dsDataBufferAllocate(_DirRef, numberOfBlocks*kBufferBlockSize);
}
// ------------------------------------------------------------------
// deallocateDataBuffer:
//
// Deallocate memory previously allocated to a tDataBuffer.
// ------------------------------------------------------------------
- (tDirStatus)deallocateDataBuffer:(tDataBufferPtr)buffer
{
if (buffer != NULL)
{
tDirStatus status = dsDataBufferDeAllocate(_DirRef, buffer);
return status;
}
else
return eDSNoErr;
}
// ------------------------------------------------------------------
// deallocateDataList:
//
// Deallocate memory previously allocated to a tDataList.
// The memory allocated to the tDataList pointer object
// must also be free'd manually.
// ------------------------------------------------------------------
- (tDirStatus)deallocateDataList:(tDataListPtr)list;
{
if (list != NULL)
{
tDirStatus status = dsDataListDeAllocate(_DirRef, list, TRUE);
free(list);
return status;
}
else
return eDSNoErr;
}
// ------------------------------------------------------------------
// deallocateDataNode:
//
// Deallocate memory previously allocated to a tDataNode.
// ------------------------------------------------------------------
- (tDirStatus)deallocateDataNode:(tDataNodePtr)node;
{
if (node != NULL)
{
tDirStatus status = dsDataNodeDeAllocate(_DirRef, node);
return status;
}
else
return eDSNoErr;
}
// ============================================================================
// Private utility methods for accessing obtaining and opening
// directory nodes.
// ------------------------------------------------------------------
// retrieveLocalNode
//
// Uses dsFindDirNodes to find and return a pointer to a tDataBuffer
// that should only contain one item: the name of the local node.
// ------------------------------------------------------------------
- (tDataBufferPtr) retrieveLocalNode
{
UInt32 count = 0;
tDataBufferPtr buffer = NULL;
tDirStatus status = eDSNoErr;
[self allocateDataBuffer:&buffer withNumberOfBlocks:4 shouldReallocate: NO];
if (doVerbose)
{
printf("---> dsFindDirNodes() for Local Node .......... ");
fflush(stdout);
}
do {
status = dsFindDirNodes(_DirRef, buffer, NULL, eDSLocalNodeNames, &count, NULL);
if (status == eDSBufferTooSmall) {
UInt32 newSize = buffer->fBufferSize * 2;
dsDataBufferDeAllocate(_DirRef, buffer);
buffer = dsDataBufferAllocate(_DirRef, newSize);
}
} while (status == eDSBufferTooSmall);
if (doVerbose)
{
[_dsStat printOutErrorMessage:"Status" withStatus:status];
}
return buffer;
}
// ------------------------------------------------------------------
// retrieveSearchPathNode
//
// Uses dsFindDirNodes to find and return a pointer to a tDataBuffer
// that should only contain one item: the name of the selected search node
// that is identified by the instance variable _SearchNodeNameToUse.
// ------------------------------------------------------------------
- (tDataBufferPtr) retrieveSearchPathNode
{
UInt32 count = 0;
tDataBufferPtr buffer = NULL;
tDirStatus status = eDSNoErr;
[self allocateDataBuffer:&buffer withNumberOfBlocks:4 shouldReallocate: NO];
if (doVerbose)
{
printf("---> dsFindDirNodes() for Search Node .......... ");
fflush(stdout);
}
do {
status = dsFindDirNodes(_DirRef, buffer, NULL, _SearchNodeNameToUse, &count, NULL);
if (status == eDSBufferTooSmall) {
UInt32 newSize = buffer->fBufferSize * 2;
dsDataBufferDeAllocate(_DirRef, buffer);
buffer = dsDataBufferAllocate(_DirRef, newSize);
}
} while (status == eDSBufferTooSmall);
if (doVerbose)
{
[_dsStat printOutErrorMessage:"Status" withStatus:status];
}
return buffer;
}
// ------------------------------------------------------------------
// getNodeNameForBuffer:
//
// Takes a pointer to a tDataBuffer that represents a list of nodes
// and grabs the name of the first item in the buffer.
// It returns the pointer to a tDataList object that
// encapsulates the name of the node.
// ------------------------------------------------------------------
- (tDataListPtr) getNodeNameForBuffer:(tDataBufferPtr)buffer
{
tDataListPtr tdlist = NULL;
tDirStatus status = eDSNoErr;
tdlist = dsDataListAllocate(_DirRef);
status = dsGetDirNodeName(_DirRef, buffer, 1, &tdlist);
return tdlist;
}
// ------------------------------------------------------------------
// openDirNodeWithName:
//
// Takes a pointer to a tDataList that encapsulates the name
// of a directory node, and opens that node. It returns a
// reference to the open node.
// ------------------------------------------------------------------
- (tDirNodeReference)openDirNodeWithName:(tDataListPtr)inNodeName
{
tDirNodeReference fNodeRef = 0;
tDirStatus status = eDSNoErr;
if ( (doVerbose) && (inNodeName != nil) && (inNodeName->fDataListHead->fBufferData != nil) )
{
printf("---> dsOpenDirNode() for node named: %s ...", inNodeName->fDataListHead->fBufferData);
fflush(stdout);
}
status = dsOpenDirNode(_DirRef, inNodeName, &fNodeRef);
if (doVerbose)
{
printf("\t");
[_dsStat printOutErrorMessage:"Status" withStatus:status];
}
return fNodeRef;
}
// ============================================================================
// Private methods for performing search functionality in
// Directory Services.
// ------------------------------------------------------------------
// fetchRecordListOnSearchNodeMatchingName:
//
// Peforms a search for the specified inUsername on the search path
// node that is currently referenced by this object, and adds matching
// nodes to this object's master list of found records.
// See also -fetchRecordListOnNode: matchingName:
// ------------------------------------------------------------------
- (tDirStatus)fetchRecordListOnSearchNodeMatchingName:(NSString*)inUsername
{
tDataListPtr nodeName = nil;
tDataBufferPtr nodeBuffer = nil;
tDirNodeReference nodeRef = 0;
tDirStatus status = eDSNoErr;
nodeBuffer = [self retrieveSearchPathNode];
nodeName = [self getNodeNameForBuffer:nodeBuffer];
nodeRef = [self openDirNodeWithName:nodeName];
status = [self fetchRecordListOnNode:nodeRef matchingName:inUsername];
dsCloseDirNode(nodeRef);
[self deallocateDataBuffer:nodeBuffer];
[self deallocateDataList:nodeName];
return status;
}
// ------------------------------------------------------------------
// addBufferToListOfUsers: fromBuffer: inSearchNode:
//
// Convert Buffer user records to collection of NSArray/NSDictionary/NSString.
// Takes the buffer items and creates an NSDictionary for each key
// and its values. Those values are placed into an NSArray.
// Then each record is added to the _MasterUserList NSArray.
// ------------------------------------------------------------------
- (void)addToListOfUsers: (unsigned long)returnCount fromBuffer: (tDataBufferPtr)nodeBuffer inSearchNode:(tDirNodeReference)nodeRefToSearch
{
int i = 0;
int j = 0;
int k = 0;
tAttributeValueListRef valueRef = 0;
tAttributeEntryPtr pAttrEntry = nil;
tAttributeValueEntryPtr pValueEntry = nil;
tAttributeListRef attrListRef = 0;
tRecordEntry *pRecEntry = nil;
NSMutableDictionary *userAttributes = nil;
NSMutableArray *userAttrValues = nil;
NSString *key = nil;
tDirStatus status = eDSNoErr;
for (i =1; i<= returnCount; i++)
{
status =dsGetRecordEntry( nodeRefToSearch, nodeBuffer, i, &attrListRef, &pRecEntry );
userAttributes = [[NSMutableDictionary alloc ] init];
// Iterate over the Attributes keys for the user.
for (j =1; j<=pRecEntry->fRecordAttributeCount; j++)
{
userAttrValues = [[NSMutableArray alloc] init];
status =dsGetAttributeEntry( nodeRefToSearch, nodeBuffer, attrListRef, j, &valueRef, &pAttrEntry );
// Iterate over the values for the current attribute key
for (k =1; k<=pAttrEntry->fAttributeValueCount; k++)
{
status =dsGetAttributeValue( nodeRefToSearch, nodeBuffer, k, valueRef, &pValueEntry );
if (status == eDSNoErr) {
// Next commented out line causes a one-time 14 byte leak, don't understand why.
//[userAttrValues addObject: [NSString stringWithUTF8String:pValueEntry->fAttributeValueData.fBufferData]];
NSString *valueStr = [[NSString alloc] initWithUTF8String:pValueEntry->fAttributeValueData.fBufferData];
[userAttrValues addObject:valueStr];
[valueStr release];
}
// Clean up memory
if (pValueEntry != nil)
{
status = dsDeallocAttributeValueEntry(_DirRef, pValueEntry);
pValueEntry = nil;
}
}
key = [[NSString alloc] initWithCString: pAttrEntry->fAttributeSignature.fBufferData];
[userAttributes setObject: userAttrValues forKey: key];
[key release];
[userAttrValues release];
// Clean up memory
if (pAttrEntry != nil)
{
status = dsDeallocAttributeEntry(_DirRef, pAttrEntry);
pAttrEntry = nil;
}
if (valueRef != 0)
{
status = dsCloseAttributeValueList(valueRef);
valueRef = 0;
}
}
[_MasterUserList addObject: userAttributes];
[userAttributes release];
// Clean up memory
if (pRecEntry != nil)
{
status = dsDeallocRecordEntry(_DirRef, pRecEntry);
pRecEntry = nil;
}
if (attrListRef != 0)
{
status = dsCloseAttributeList(attrListRef);
attrListRef = 0;
}
}
}
// ------------------------------------------------------------------
// fetchRecordListOnNode: matchingName:
//
// Peforms a search for the specified inUsername in the specified
// node reference (presumable a search node), and adds matching
// nodes to this object's master list of found records.
// See also -fetchRecordListOnSearchNodeMatchingName:
// ------------------------------------------------------------------
- (tDirStatus)fetchRecordListOnNode:(tDirNodeReference)nodeRefToSearch matchingName:(NSString*)inUsername
{
tContextData localcontext = 0;
tDataListPtr recName = nil;
tDataListPtr recType = nil;
tDataListPtr attrType = nil;
tDataBufferPtr nodeBuffer = nil;
tDirStatus status = eDSNoErr;
unsigned short blockCount = 1;
UInt32 returnCount = 0;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
unsigned long matchingUsers = 0;
recName = dsBuildListFromStrings(_DirRef, [inUsername cString], NULL);
recType = dsBuildListFromStrings(_DirRef, _SearchObjectType, NULL);
attrType = dsBuildListFromStrings(_DirRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, NULL);
[self allocateDataBuffer: &nodeBuffer withNumberOfBlocks: blockCount shouldReallocate: NO];
do
{
if (doVerbose)
{
printf("---> dsGetRecordList() .... ");
fflush(stdout);
}
// Stuff the record entries into nodeBuffer
status = dsGetRecordList(nodeRefToSearch, nodeBuffer, recName, eDSExact, recType, attrType, false, &returnCount, &localcontext);
if (doVerbose)
{
printf("Count: %u, Cont: %3s, \n", (uint32_t) returnCount,
localcontext == 0 ? "NO" : "YES");
[_dsStat printOutErrorMessage:"Status" withStatus:status];
}
if (status == eDSBufferTooSmall)
{
blockCount++;
}
else if (status == eDSNoErr && returnCount > 0)
{
[self addToListOfUsers: returnCount fromBuffer: nodeBuffer inSearchNode: nodeRefToSearch ];
}
[self allocateDataBuffer: &nodeBuffer withNumberOfBlocks: blockCount shouldReallocate: YES];
} while ( (status == eDSNoErr && localcontext != 0) || (status == eDSBufferTooSmall));
// Do Memory cleanup
if (localcontext != 0)
{
dsReleaseContinueData(nodeRefToSearch, localcontext);
localcontext = 0;
}
[self deallocateDataList:recType];
[self deallocateDataList:recName];
[self deallocateDataList:attrType];
[self deallocateDataBuffer:nodeBuffer];
[pool release];
// If status is not eDSNoErr, and we didn't get any users, raise an exception.
// If we did get users, then it is some non-fatal error. The normal
// print statements will output the status error, but we should not raise
// an exception (which aborts program execution).
// However, if we get a eDSServerTimeout error, then we should raise exception.
matchingUsers = [_MasterUserList count];
if (status != eDSNoErr && (matchingUsers <= 0 || status == eDSServerTimeout))
{
DSException *ex = nil;
ex = [DSException name:@"FetchRecordError" reason:@"Unable to retrieve any records via dsGetRecordList." status:status];
[ex raise];
}
printf("Call to dsGetRecordList returned count = %ld with ", matchingUsers);
[_dsStat printOutErrorMessage:"Status" withStatus:status];
if (matchingUsers <= 0)
{
printf("No matching users found.\n");
if (checkpw([inUsername cString], "") != CHECKPW_UNKNOWNUSER)
printf("**** checkpw() DISAGREES! ****\n");
}
return status;
}
// ------------------------------------------------------------------
// getAttibute: forRecordNumber
//
// Retrieve the attribute string from the recordNumber'th
// matching record from the recent search in the search path.
// ------------------------------------------------------------------
- (NSString*)getAttribute: (char*)attr forRecordNumber: (unsigned long)recordNumber
{
NSArray *recordValues = nil;
NSString *key = [[NSString alloc] initWithCString: attr];
recordValues = [[_MasterUserList objectAtIndex: recordNumber] objectForKey: key];
[key release];
if (recordValues != nil && [recordValues count] > 0)
{
return [recordValues objectAtIndex:0];
}
else
return nil;
}
// ------------------------------------------------------------------
// nodePathStrForSearchNodeRecordNumber:
//
// Retrieve the username string from the recordNumber'th
// matching record from the recent search in the search path.
// ------------------------------------------------------------------
- (NSString*)usernameForSearchNodeRecordNumber:(unsigned long)recordNumber
{
return [self getAttribute:kDSNAttrRecordName forRecordNumber:recordNumber];
}
// ------------------------------------------------------------------
// nodePathStrForSearchNodeRecordNumber:
//
// Retrieve the node path name string from the recordNumber'th
// matching record from the recent search in the search path.
// ------------------------------------------------------------------
- (NSString*)nodePathStrForSearchNodeRecordNumber:(unsigned long)recordNumber
{
return [self getAttribute:kDSNAttrMetaNodeLocation forRecordNumber:recordNumber];
}
// ============================================================================
// Public methods for accessing the Directory Service functions
// that this class provides.
// ------------------------------------------------------------------
// authenticateInNodePathStr: username: password:
//
// Takes the text string name of a node path and performs an
// authentication check on it for the specified username & passowrd.
// Similar to authOnNodePath: username: password:, except this one
// is optimized for short usernames only. It skips searching the
// node for the user record and just sends checks for authetication
// based on the username specified in the arguments.
// ------------------------------------------------------------------
- (tDirStatus)authenticateInNodePathStr:(NSString*)nodePathStr username:(NSString*)inUsername
password:(NSString*)inPassword
{
tDataListPtr nodePath = nil;
tDirNodeReference userNode = 0;
tDirStatus status = eDSNoErr;
nodePath = dsBuildFromPath(_DirRef, [nodePathStr cString], "/");
if (doVerbose)
{
printf("---> dsOpenDirNode() on node Named: %s ... ", [nodePathStr cString]);
fflush(stdout);
}
status = dsOpenDirNode(_DirRef, nodePath, &userNode);
if (doVerbose)
{
printf("\t");
[_dsStat printOutErrorMessage:"Status" withStatus:status];
}
[self deallocateDataList:nodePath];
if (status == eDSNoErr)
status = [self authenticateInNode:userNode username:inUsername password:inPassword];
dsCloseDirNode(userNode);
return status;
}
// ------------------------------------------------------------------
// authenticateInNode: username: password:
//
// Takes a DirectoryServices node path reference and performs an
// authentication check on it for the specified username & passowrd.
// ------------------------------------------------------------------
- (tDirStatus)authenticateInNode:(tDirNodeReference)userNode username:(NSString*)inUsername
password:(NSString*)inPassword
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
tDataBufferPtr step = NULL;
tDataBufferPtr stepResponse = NULL;
tDataNodePtr authMethod = NULL;
UInt32 length = 0;
UInt32 current = 0;
tDirStatus status = 0;
[self allocateDataBuffer:&step withNumberOfBlocks:4 shouldReallocate: NO];
[self allocateDataBuffer:&stepResponse withNumberOfBlocks:4 shouldReallocate: NO];
authMethod = dsDataNodeAllocateString(_DirRef, kDSStdAuthNodeNativeClearTextOK);
length = strlen( [inUsername UTF8String] );
memcpy( &(step->fBufferData[current]), &length, sizeof(length));
current += sizeof(length);
memcpy( &(step->fBufferData[current]), [inUsername UTF8String], length );
current +=length;
length = strlen( [inPassword UTF8String] );
memcpy( &(step->fBufferData[current]), &length, sizeof(length));
current += sizeof(length);
memcpy( &(step->fBufferData[current]), [inPassword UTF8String], length );
step->fBufferLength = current + length;
if(doVerbose)
{
printf("---> dsDoDirNodeAuth() ......................... ");
fflush(stdout);
}
status = dsDoDirNodeAuth(userNode, authMethod, 1, step, stepResponse, NULL);
if(doVerbose)
{
[_dsStat printOutErrorMessage:"Status" withStatus:status];
}
printf("Username: %s\nPassword: %s\n", [inUsername cString], [inPassword cString]);
if(status == eDSNoErr)
printf("Success");
else
[_dsStat printOutErrorMessage:"Error" withStatus:status];
// Clean up allocated memory
//dsCloseDirNode(userNode); // don't close since not opened here
[self deallocateDataNode:authMethod];
[self deallocateDataBuffer:step];
[self deallocateDataBuffer:stepResponse];
[pool release];
return (status);
}
// ------------------------------------------------------------------
// authUserOnLocalNode: password:
//
// Takes the specified username and password and performs an
// authentication check for them on the local NetInfo node.
// ------------------------------------------------------------------
- (tDirStatus)authUserOnLocalNode:(NSString*)inUsername password:(NSString*)inPassword
{
tDataBufferPtr localNodeBuffer = nil;
tDataListPtr localNodeName = nil;
tDirNodeReference localNodeRef = 0;
tDirStatus status = eDSNoErr;
u_long i = 0;
unsigned long matchingUsers = 0;
localNodeBuffer = [self retrieveLocalNode];
localNodeName = [self getNodeNameForBuffer:localNodeBuffer];
[self deallocateDataBuffer:localNodeBuffer];
localNodeRef = [self openDirNodeWithName:localNodeName];
[self deallocateDataList:localNodeName];
[self fetchRecordListOnNode:localNodeRef matchingName:inUsername];
matchingUsers = [_MasterUserList count];
for (i=0; i< matchingUsers; i++)
{
status = [self authenticateInNode:localNodeRef username:[self usernameForSearchNodeRecordNumber:i] password:inPassword];
printf("\n");
}
dsCloseDirNode(localNodeRef);
return status;
}
// ------------------------------------------------------------------
// authOnNodePath: username: password:
//
// Takes the text string name of a node path and performs an
// authentication check on it for the specified username & passowrd.
// Both long and short usernames can be used because it first
// searches the node for the user record. Then it extracts
// the short username and uses that to check authentication.
// ------------------------------------------------------------------
- (tDirStatus)authOnNodePath:(NSString*)nodePathStr username:(NSString*)inUsername password:(NSString*)inPassword
{
tDataListPtr nodePath = NULL;
tDirNodeReference userNode = 0;
tDirStatus status = 0;
int i = 0;
unsigned long matchingUsers = 0;
nodePath = dsBuildFromPath(_DirRef, [nodePathStr cString], "/");
if (doVerbose)
{
printf("---> dsOpenDirNode() on node Named: %s ... ", [nodePathStr cString]);
fflush(stdout);
}
status = dsOpenDirNode(_DirRef, nodePath, &userNode);
if (doVerbose)
{
printf("\t");
[_dsStat printOutErrorMessage:"Status" withStatus:status];
}
[self deallocateDataList:nodePath];
// if we have an eDSNoErr on open, then we can continue...
if( status == eDSNoErr )
{
[self fetchRecordListOnNode:userNode matchingName:inUsername];
matchingUsers = [_MasterUserList count];
for (i=0; i < matchingUsers; i++)
{
status = [self authenticateInNode:userNode username:[self usernameForSearchNodeRecordNumber:i] password:inPassword];
printf("\n");
}
dsCloseDirNode(userNode);
}
return status;
}
// ------------------------------------------------------------------
// authUserOnSearchPath: password:
//
// Finds all nodes in the search path that contain a user by the
// specified name. It then successively performs an authentication
// check on those nodes for the username and password specified.
// ------------------------------------------------------------------
- (tDirStatus)authUserOnSearchPath:(NSString*)inUsername password:(NSString*)inPassword
{
tDataBufferPtr searchNodeBuffer = nil;
tDataListPtr searchNodeName = nil;
tDirStatus status = eDSNoErr;
u_long i = 0;
NSString *nodePathStr = nil;
NSString *realUsername = nil;
int checkpwresult = 1;
char *cpwresultstr = nil;
NSAutoreleasePool *pool = nil;
unsigned long matchingUsers = 0;
NS_DURING
searchNodeBuffer = [self retrieveSearchPathNode];
searchNodeName = [self getNodeNameForBuffer:searchNodeBuffer];
[self deallocateDataBuffer:searchNodeBuffer];
searchNodeBuffer = nil;
_SearchNodeRef = [self openDirNodeWithName:searchNodeName];
[self deallocateDataList:searchNodeName];
searchNodeName = nil;
status = [self fetchRecordListOnNode:_SearchNodeRef matchingName:inUsername];
matchingUsers = [_MasterUserList count];
for (i=0 ; i < matchingUsers; i++)
{
pool = [[NSAutoreleasePool alloc] init];
nodePathStr = [self nodePathStrForSearchNodeRecordNumber:i];
realUsername = [self usernameForSearchNodeRecordNumber:i];
if ([self isMemberOfClass:[DSAuthenticate class]])
{
if (i == 0) //only need to do checkpw once since result will not change
{
checkpwresult = checkpw([realUsername cString], [inPassword cString]);
switch (checkpwresult) {
case CHECKPW_SUCCESS:
cpwresultstr = "Success";
break;
case CHECKPW_UNKNOWNUSER:
cpwresultstr = "Unknown User";
break;
case CHECKPW_BADPASSWORD:
cpwresultstr = "Bad Password";
break;
case CHECKPW_FAILURE:
cpwresultstr = "Failure";
break;
}
printf("\nCall to checkpw(): %s", cpwresultstr);
}
}
printf("\n\npath: %s\n", [nodePathStr cString]);
status = [self authenticateInNodePathStr:nodePathStr username:realUsername password:inPassword];
[pool release];
pool = nil;
}
printf("\n");
NS_HANDLER
[self deallocateDataBuffer:searchNodeBuffer];
[self deallocateDataList:searchNodeName];
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
return status;
}
// ------------------------------------------------------------------
// getListOfNodesWithUser:
//
// Searches the entire search path for a user named by the
// parameter. It returns an NSArray of NSStrings of the names
// of the nodes.
// ------------------------------------------------------------------
- (NSArray*)getListOfNodesWithUser:(NSString*)inUsername
{
NSMutableArray *nodePathStringList = [[NSMutableArray alloc] init];
tDataBufferPtr searchNodeBuffer = nil;
tDataListPtr searchNodeName = nil;
u_long i = 0;
unsigned long matchingUsers = 0;
searchNodeBuffer = [self retrieveSearchPathNode];
searchNodeName = [self getNodeNameForBuffer:searchNodeBuffer];
[self deallocateDataBuffer:searchNodeBuffer];
_SearchNodeRef = [self openDirNodeWithName:searchNodeName];
[self deallocateDataList:searchNodeName];
[self fetchRecordListOnNode:_SearchNodeRef matchingName:inUsername];
matchingUsers = [_MasterUserList count];
for (i=0; i < matchingUsers; i++)
[nodePathStringList addObject:[self nodePathStrForSearchNodeRecordNumber:i]];
return (NSArray*)[nodePathStringList autorelease];
}
@end

39
dirt/DSAuthenticateLM.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSAuthenticateNT
*/
#import <Foundation/Foundation.h>
#import "DSAuthenticate.h"
#define LM_AUTH @"lm"
@interface DSAuthenticateLM : DSAuthenticate
{
}
@end

123
dirt/DSAuthenticateLM.m Normal file
View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSAuthenticateLM
*/
#import "DSAuthenticateLM.h"
#import <openssl/rand.h>
#import "SMBAuth.h"
extern BOOL doVerbose;
@implementation DSAuthenticateLM
- (tDirStatus)authenticateInNode:(tDirNodeReference)userNode username:(NSString*)inUsername
password:(NSString*)inPassword
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
tDataBufferPtr step = NULL;
tDataBufferPtr stepResponse = NULL;
tDataNodePtr authMethod = NULL;
UInt32 length = 0;
UInt32 current = 0;
tDirStatus status = 0;
unsigned char hash[21] = {0};
unsigned char p24[24] = {0};
unsigned char challenge[8] = {0};
[self allocateDataBuffer:&step withNumberOfBlocks:1 shouldReallocate:NO];
[self allocateDataBuffer:&stepResponse withNumberOfBlocks:4 shouldReallocate:NO];
authMethod = dsDataNodeAllocateString(_DirRef, kDSStdAuthSMB_LM_Key);
// Prepare data derived from password to pass to dsDoDirNodeAuth()
RAND_bytes(challenge, 8);
if(doVerbose)
{
printf("---> challenge generated(): %s ............... ",challenge);
fflush(stdout);
}
CalculateSMBLANManagerHash([inPassword UTF8String], hash);
bzero( hash+16, 5);
if(doVerbose)
{
printf("---> hash generated(): %s ............... ",hash);
fflush(stdout);
}
CalculateP24( hash, challenge, p24 ); // pick a random challenge, can be anything.
if(doVerbose)
{
printf("---> p24 generated(): %s ............... ",p24);
fflush(stdout);
}
length = strlen( [inUsername UTF8String] );
memcpy( &(step->fBufferData[current]), &length, sizeof(length));
current += sizeof(length);
memcpy( &(step->fBufferData[current]), [inUsername UTF8String], length );
current +=length;
length = 8;
memcpy( &(step->fBufferData[current]), &length, sizeof(length));
current += sizeof(length);
memcpy( &(step->fBufferData[current]), challenge, length);
current +=length;
length = 24;
memcpy( &(step->fBufferData[current]), &length, sizeof(length));
current += sizeof(length);
memcpy( &(step->fBufferData[current]), p24, length);
step->fBufferLength = current + length;
if(doVerbose)
{
printf("---> dsDoDirNodeAuth() ......................... ");
fflush(stdout);
}
status = dsDoDirNodeAuth(userNode, authMethod, 1, step, stepResponse, NULL);
if(doVerbose)
{
[_dsStat printOutErrorMessage:"Status" withStatus:status];
}
printf("Username: %s\nPassword: %s\n", [inUsername cString], [inPassword cString]);
if(status == eDSNoErr)
printf("Good");
else
[_dsStat printOutErrorMessage:"Error" withStatus:status];
// Clean up allocated memory
//dsCloseDirNode(userNode); /// don't close since not opened here
[self deallocateDataNode:authMethod];
[self deallocateDataBuffer:step];
[self deallocateDataBuffer:stepResponse];
[pool release];
return (status);
}
@end

39
dirt/DSAuthenticateNT.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSAuthenticateNT
*/
#import <Foundation/Foundation.h>
#import "DSAuthenticate.h"
#define NT_AUTH @"nt"
@interface DSAuthenticateNT : DSAuthenticate
{
}
@end

137
dirt/DSAuthenticateNT.m Normal file
View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSAuthenticateNT
*/
#import "DSAuthenticateNT.h"
#import <openssl/rand.h>
#import "SMBAuth.h"
extern BOOL doVerbose;
void
print_as_hex( void *bin, int len )
{
int idx;
for ( idx = 0; idx < len; idx++ )
printf( "%.2X ", ((unsigned char *)bin)[idx] );
printf("\n");
}
@implementation DSAuthenticateNT
- (tDirStatus)authenticateInNode:(tDirNodeReference)userNode username:(NSString*)inUsername
password:(NSString*)inPassword
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
tDataBufferPtr step = NULL;
tDataBufferPtr stepResponse = NULL;
tDataNodePtr authMethod = NULL;
UInt32 length = 0;
UInt32 current = 0;
tDirStatus status = 0;
unsigned char hash[21] = {0};
unsigned char p24[24] = {0};
unsigned char challenge[8] = {0};
[self allocateDataBuffer:&step withNumberOfBlocks:1 shouldReallocate: NO];
[self allocateDataBuffer:&stepResponse withNumberOfBlocks:4 shouldReallocate: NO];
authMethod = dsDataNodeAllocateString(_DirRef, kDSStdAuthSMB_NT_Key);
// Prepare data derived from password to pass to dsDoDirNodeAuth()
RAND_bytes(challenge, 8);
if(doVerbose)
{
printf("---> challenge generated(): ");
print_as_hex( challenge, 8 );
fflush(stdout);
}
CalculateSMBNTHash([inPassword UTF8String], hash);
bzero( hash+16, 5);
if(doVerbose)
{
printf("---> hash generated(): ");
print_as_hex( hash, 16 );
fflush(stdout);
}
CalculateP24( hash, challenge, p24 ); // pick a random challenge, can be anything.
if(doVerbose)
{
printf("---> p24 generated(): ");
print_as_hex( p24, 24 );
fflush(stdout);
}
length = strlen( [inUsername UTF8String] );
memcpy( &(step->fBufferData[current]), &length, sizeof(length));
current += sizeof(length);
memcpy( &(step->fBufferData[current]), [inUsername UTF8String], length );
current +=length;
length = 8;
memcpy( &(step->fBufferData[current]), &length, sizeof(length));
current += sizeof(length);
memcpy( &(step->fBufferData[current]), challenge, length);
current +=length;
length = 24;
memcpy( &(step->fBufferData[current]), &length, sizeof(length));
current += sizeof(length);
memcpy( &(step->fBufferData[current]), p24, length);
step->fBufferLength = current + length;
if(doVerbose)
{
printf("---> dsDoDirNodeAuth() ......................... ");
fflush(stdout);
}
status = dsDoDirNodeAuth(userNode, authMethod, 1, step, stepResponse, NULL);
if(doVerbose)
{
[_dsStat printOutErrorMessage:"Status" withStatus:status];
}
printf("Username: %s\nPassword: %s\n", [inUsername cString], [inPassword cString]);
if(status == eDSNoErr)
printf("Good");
else
[_dsStat printOutErrorMessage:"Error" withStatus:status];
// Clean up allocated memory
//dsCloseDirNode(userNode); /// don't close since not opened here
[self deallocateDataNode:authMethod];
[self deallocateDataBuffer:step];
[self deallocateDataBuffer:stepResponse];
[pool release];
return (status);
}
@end

42
dirt/DSException.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSException
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirServicesTypes.h>
#import "DSStatus.h"
@interface DSException : NSException
{
DSStatus *_dsStat;
}
+ (DSException*) name:(NSString*)name reason:(NSString*)reason status:(tDirStatus)status;
- (tDirStatus) status;
- (char*) statusCString;
@end

72
dirt/DSException.m Normal file
View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSException
*/
#import "DSException.h"
@implementation DSException
+ (DSException*) name:(NSString*)inName reason:(NSString*)inReason status:(tDirStatus)inStatus
{
DSException *selfInstance = nil;
NSDictionary *statusDict = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt:inStatus] forKey:@"status"];
selfInstance = [[self alloc] initWithName:inName reason:inReason userInfo:statusDict];
return [selfInstance autorelease];
}
- (id)initWithName:(NSString *)inname reason:(NSString *)inreason userInfo:(NSDictionary *)inuserInfo
{
_dsStat = [[DSStatus sharedInstance] retain];
return [super initWithName:inname reason:inreason userInfo:inuserInfo];
}
- (void) dealloc
{
[_dsStat release];
[super dealloc];
}
- (tDirStatus) status
{
if ([self userInfo] != nil)
{
NSNumber *statusNumber = [[self userInfo] objectForKey:@"status"];
if (statusNumber != nil)
return [statusNumber intValue];
}
return eDSNoErr;
}
- (char*) statusCString
{
return [_dsStat cStringForStatus:[self status]];
}
@end

40
dirt/DSStatus.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSStatus
*/
#import <Foundation/Foundation.h>
@interface DSStatus : NSObject
{
NSDictionary *_errDict;
}
+(DSStatus*)sharedInstance;
-(char*) cStringForStatus:(int)dirStatus;
-(void) printOutErrorMessage:(const char*)messageTag withStatus:(int)dirStatus;
@end

71
dirt/DSStatus.m Normal file
View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSStatus
*/
#import "DSStatus.h"
#import <DirectoryService/DirServicesUtils.h>
@implementation DSStatus
-init
{
[super init];
return self;
}
-(void) dealloc
{
[super dealloc];
}
+(DSStatus*)sharedInstance
{
static DSStatus *_sharedInstance = nil;
if ([_sharedInstance self] == nil)
_sharedInstance = [[[self alloc] init] autorelease];
return _sharedInstance;
}
-(char*) cStringForStatus:(int)dirStatus
{
return(dsCopyDirStatusName(dirStatus));
}
-(void) printOutErrorMessage:(const char*)messageTag withStatus:(int)dirStatus
{
if (messageTag != nil)
{
char *statusString = dsCopyDirStatusName(dirStatus);
printf("%s : %s : (%d)\n", messageTag, statusString, dirStatus);
free(statusString);
statusString = nil;
fflush(stdout);
}
}
@end

198
dirt/SMBAuth.c Normal file
View File

@ -0,0 +1,198 @@
/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header SMBAuth
*/
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <openssl/md4.h>
#include <openssl/des.h>
#include "SMBAuth.h"
// utility functions prototypes
#ifdef __cplusplus
extern "C" {
#endif
u_int16_t ByteSwapInt16(u_int16_t value);
void CStringToUnicode(char *cstr, u_int16_t *unicode);
void MD4Encode(unsigned char *output, unsigned char *input, unsigned int len);
void strnupper(char *str, int maxlen);
void DESEncode(void *str, void *data);
void str_to_key(unsigned char *str, unsigned char key[8]);
#ifdef __cplusplus
}
#endif
#define kDESVersion1 1
// Utility functions
void CalculateP24(unsigned char *P21, unsigned char *C8, unsigned char *P24)
{
// setup P24
memcpy(P24, C8, 8);
memcpy(P24+8, C8, 8);
memcpy(P24+16, C8, 8);
DESEncode(P21, P24);
DESEncode(P21+7, P24+8);
DESEncode(P21+14, P24+16);
}
void CalculateSMBNTHash(const char *utf8Password, unsigned char outHash[16])
{
u_int16_t unicodeLen = 0;
u_int16_t unicodepwd[258] = {0};
char *password[128] = {0};
int passLen = 0;
//unsigned char P21[21] = {0};
if (utf8Password == NULL || outHash == NULL) return;
if (strlen(utf8Password) < 128)
passLen = strlen(utf8Password);
else
passLen = 128;
memmove(password, utf8Password, passLen);
unicodeLen = strlen((char *)password) * sizeof(u_int16_t);
CStringToUnicode((char *)password, unicodepwd);
MD4Encode(outHash, (unsigned char *)unicodepwd, unicodeLen);
}
void CalculateSMBLANManagerHash(const char *password, unsigned char outHash[16])
{
unsigned char S8[8] = {0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
int passLen = 0;
unsigned char P21[21] = {0};
unsigned char P14[14] = {0};
unsigned char *P16 = P21;
if (strlen(password) < 14)
passLen = strlen(password);
else
passLen = 14;
// setup P14
memmove(P14, password, passLen);
strnupper((char *)P14, 14);
// setup P16
memmove(P16, S8, 8);
memmove(P16+8, S8, 8);
DESEncode(P14, P16);
DESEncode(P14+7, P16+8);
memmove(outHash, P16, 16);
}
u_int16_t ByteSwapInt16(u_int16_t value)
{
u_int16_t mask = value;
mask <<= 8;
value >>= 8;
value |= mask;
return value;
}
void CStringToUnicode(char *cstr, u_int16_t *unicode)
{
int i;
u_int16_t val;
int len;
len = strlen(cstr);
for(i = 0; i < len; i++)
{
val = *cstr;
if (BYTE_ORDER == BIG_ENDIAN)
*unicode = ByteSwapInt16(val);
else
*unicode = val;
unicode++;
cstr++;
if (val == 0) break;
}
}
void MD4Encode(unsigned char *output, unsigned char *input, unsigned int len)
{
MD4_CTX context = {};
MD4_Init (&context);
MD4_Update (&context, (unsigned char *)input, len);
MD4_Final (output, &context);
}
void strnupper(char *str, int maxlen)
{
char *s = str;
while (*s && maxlen)
{
if (islower(*s))
*s = toupper(*s);
s++;
maxlen--;
}
}
void DESEncode(void *str, void *data)
{
des_key_schedule theKeyArray;
unsigned char key[8] = {};
des_cblock output;
str_to_key((unsigned char *)str, key);
des_set_key_unchecked((const_des_cblock *)key, theKeyArray);
des_ecb_encrypt((const_des_cblock *)data, &output, theKeyArray, kDESVersion1);
memcpy(data,output,8);
}
void str_to_key(unsigned char *str, unsigned char key[8])
{
int i;
key[0] = str[0]>>1;
key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
key[7] = str[6]&0x7F;
for (i=0;i<8;i++) {
key[i] = (key[i]<<1);
}
des_set_odd_parity((des_cblock *)&key); //des_cblock *key // typedef unsigned char des_cblock[8];
}

44
dirt/SMBAuth.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header SMBAuth
*/
#ifndef __SMBAUTH_H__
#define __SMBAUTH_H__ 1
// utility functions prototypes
#ifdef __cplusplus
extern "C" {
#endif
void CalculateSMBNTHash(const char *utf8Password, unsigned char outHash[16]);
void CalculateSMBLANManagerHash(const char *password, unsigned char outHash[16]);
void CalculateP24(unsigned char *P21, unsigned char *C8, unsigned char *P24);
void DESEncode(void *str, void *data);
#ifdef __cplusplus
}
#endif
#endif

64
dirt/dirt.1 Normal file
View File

@ -0,0 +1,64 @@
.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
.\"See Also:
.\"man mdoc.samples for a complete listing of options
.\"man mdoc for the short list of editing options
.\"/usr/share/misc/mdoc.template
.Dd Feb 21, 2003 \" DATE
.Dt dirt 1 \" Program name and manual section number
.Os MacOSX
.Sh NAME \" Section Header - required - don't modify
.Nm dirt
.\" The following lines are read in generating the apropos(man -k) database. Use only key
.\" words here as the database is built based on the words here and in the .ND line.
.\" Use .Nm macro to designate other names for the documented program.
.Nd A Directory Tool for testing Directory Services
.Sh SYNOPSIS \" Section Header - required - don't modify
.Nm
.Op Fl c \" [options]
.Op Fl g \" [options]
.Op Fl s \" [options]
.Op Fl l | Fl m Ar path | Fl n \" [options]
.Op Fl q Ar query_iterations Op Fl d Ar seconds \" [options]
.Fl u Ar username
.Op Fl p Ar password
.Sh DESCRIPTION \" Section Header - required - don't modify
The dirt tool is a command line utility for testing Directory Services. Common usages are to do simple authentication tests on various nodes (including search node) as well as repetitive stress testing.
.Pp
The options are as follows:
.Pp
.Nm options:
.Bl -tag -width -indent \" Differs from above in -compact tag removed
.It Fl l
Search Local node only
.It Fl c
Search the Contacts search path (default is to use the Authentication path)
.It Fl m Ar path
Search on node named path
.It Fl q Ar n
Perform the specified query operation n times. (specify 0 to loop forever)
.It Fl d Ar n
Sleep n seconds between each query iteration. Default is 0.
.It Fl g
Search for groups instead of users.
.It Fl a Ar auth_method
Use specified authentication method. Available methods:
.Dl nt --> SMB-NT
.It Fl s
Grep the DS headers for final status code.
.El \" Ends the list
.\" The following are optional section headers. Remove the comment tag to use.
.\" .Sh RETURN VALUES \"Sections 2 and 3
.\" .Sh ENVIRONMENT \"Sections 1, 6, 7, and 8
.\" .Sh FILES
.\" .Sh EXAMPLES
.\" .Ev PAGER
.\" .Sh DIAGNOSTICS \"Sections 1, 6, 7, and 8
.\" .Sh ERRORS \"Sections 2 and 3
.Sh SEE ALSO
.\" List links in ascending order by section, alphabetically within a section.
.\" Please do not reference files that do not exist without filing a bug report
.Xr DirectoryService 8
.Xr dscl 1
.Xr DirectoryServiceAttributes 7
.\" .Sh BUGS
.\" .Sh HISTORY

414
dirt/main.m Normal file
View File

@ -0,0 +1,414 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSAuthenticate
* Tool for testing authentication against DirectoryService API.
* DIRT: the DIRectory Tool.
*/
#import <Foundation/Foundation.h>
#import "DSAuthenticate.h"
#import "DSAuthenticateLM.h"
#import "DSAuthenticateNT.h"
#import "DSException.h"
#import "DSStatus.h"
#import "dstools_version.h"
#import <unistd.h>
#import <termios.h>
#import <sysexits.h>
BOOL doVerbose = NO;
static BOOL sigIntRaised = NO;
void catch_int(int sig_num);
void usage(void);
//-----------------------------------------------------------------------------
// intcatch
//
// Helper function for read_passphrase
//-----------------------------------------------------------------------------
volatile int intr;
void
intcatch(int dontcare)
{
intr = 1;
}
//-----------------------------------------------------------------------------
// read_passphrase
//
// Returns: malloc'd C-str
// Provides a secure prompt for inputting passwords
/*
* Reads a passphrase from /dev/tty with echo turned off. Returns the
* passphrase (allocated with xmalloc), being very careful to ensure that
* no other userland buffer is storing the password.
*/
//-----------------------------------------------------------------------------
char *
read_passphrase(const char *prompt, int from_stdin)
{
char buf[1024], *p, ch;
struct termios tio, saved_tio;
sigset_t oset, nset;
struct sigaction sa, osa;
int input, output, echo = 0;
if (from_stdin) {
input = STDIN_FILENO;
output = STDERR_FILENO;
} else
input = output = open("/dev/tty", O_RDWR);
if (input == -1)
fprintf(stderr, "You have no controlling tty. Cannot read passphrase.\n");
/* block signals, get terminal modes and turn off echo */
sigemptyset(&nset);
sigaddset(&nset, SIGTSTP);
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = intcatch;
(void) sigaction(SIGINT, &sa, &osa);
intr = 0;
if (tcgetattr(input, &saved_tio) == 0 && (saved_tio.c_lflag & ECHO)) {
echo = 1;
tio = saved_tio;
tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
(void) tcsetattr(input, TCSANOW, &tio);
}
fflush(stdout);
(void)write(output, prompt, strlen(prompt));
for (p = buf; read(input, &ch, 1) == 1 && ch != '\n';) {
if (intr)
break;
if (p < buf + sizeof(buf) - 1)
*p++ = ch;
}
*p = '\0';
if (!intr)
(void)write(output, "\n", 1);
/* restore terminal modes and allow signals */
if (echo)
tcsetattr(input, TCSANOW, &saved_tio);
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
(void) sigaction(SIGINT, &osa, NULL);
if (intr) {
kill(getpid(), SIGINT);
sigemptyset(&nset);
/* XXX tty has not neccessarily drained by now? */
sigsuspend(&nset);
}
if (!from_stdin)
(void)close(input);
p = (char *)malloc(strlen(buf)+1);
strcpy(p, buf);
memset(buf, 0, sizeof(buf));
return (p);
}
int main(int argc, char *argv[])
{
tDirStatus status = eDSNoErr;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
DSAuthenticate *dsauth = nil;
NSString *username = nil;
NSString *password = nil;
NSString *sNodeToSearch = nil;
NSString *authMethod = nil;
BOOL listNodesOnly = NO;
BOOL searchLocalOnly = NO;
BOOL useContactPath = NO;
BOOL groupSearch = NO; // Thus by default let's perform a user search.
BOOL reportStatusCodes = NO;
int queryIterations = 1;
long delayInSeconds = 0;
int ch = -1;
char *localtime = nil;
time_t nowtime;
unsigned int i = 0;
NSAutoreleasePool *loopPool = nil;
DSException *dirtException = nil;
DSStatus *dsStat = [[DSStatus sharedInstance] retain];
if ( argc == 2 && strcmp(argv[1], "-appleversion") == 0 )
dsToolAppleVersionExit( argv[0] );
while ((ch = getopt(argc, argv, "u:p:nclvgxm:q:d:a:h?")) != -1)
{
switch (ch)
{
case 'u':
username = [[NSString alloc] initWithCString:optarg];
break;
case 'p':
password = [[NSString alloc] initWithUTF8String:optarg];
break;
case 'n':
// Only list the nodes where the username is found
listNodesOnly = YES;
break;
case 'l':
// Only search the localnode
searchLocalOnly = YES;
break;
case 'g':
// Search for a group name, instead of a user.
groupSearch = YES;
break;
case 'm':
// Only search the specified node name
sNodeToSearch = [[NSString alloc] initWithCString:optarg];
break;
case 'q':
queryIterations = atoi(optarg);
// if iterations parameter < 0, then loop forever by never incrementing the loop counter
if ((int)queryIterations < 0) {
fprintf(stderr, "The number of iterations must be a non-negative integer.\n");
exit(-1);
}
break;
case 'd':
delayInSeconds = atol(optarg);
if ((int)queryIterations < 0) {
fprintf(stderr, "The delay (seconds) must be a non-negative integer.\n");
exit(-2);
}
break;
case 'c':
useContactPath = YES;
break;
case 'v':
doVerbose = YES;
break;
case 'x':
reportStatusCodes = YES;
break;
case 'a':
authMethod = [[NSString alloc] initWithCString:optarg];
break;
case '?':
case 'h':
default:
usage();
}
}
if (queryIterations != 1)
{
signal(SIGINT, catch_int);
signal(SIGTERM, catch_int);
}
// If a username is specified without a password and a password is needed we prompt for it.
if (username != nil && password == nil && !listNodesOnly) {
password = [[NSString alloc] initWithUTF8String:read_passphrase("User password:",1)];
NSLog( @"password is : %@", password );
}
if (username != nil && (password != nil || listNodesOnly))
{
NS_DURING
if (!authMethod)
dsauth = [[DSAuthenticate alloc] init];
else if ([authMethod isEqualToString:NT_AUTH])
dsauth = [[DSAuthenticateNT alloc] init];
else if ([authMethod isEqualToString:LM_AUTH])
dsauth = [[DSAuthenticateLM alloc] init];
else {
fprintf(stderr, "Error: the authentication method '%s' is not supported by the dirt tool.\n", [authMethod UTF8String]);
exit(EX_USAGE);
}
for (i=0; (queryIterations == 0 ? TRUE : i < queryIterations) && (sigIntRaised == NO); i++ )
{
NS_DURING
loopPool = [[NSAutoreleasePool alloc] init];
if (queryIterations != 1)
{
nowtime = time(NULL);
localtime = ctime(&nowtime);
localtime[strlen(localtime)-1] = 0;
printf("%d:\n%s ---------------- \n", i, localtime);
}
// Open DirectoryService by instantiating the dsauth object.
if (useContactPath == YES)
[dsauth useContactSearchPath];
if (groupSearch == YES)
[dsauth searchForGroups];
if (searchLocalOnly == YES)
status = [dsauth authUserOnLocalNode:username password:password];
else if (sNodeToSearch != nil)
status = [dsauth authOnNodePath:sNodeToSearch username:username password:password];
else if (listNodesOnly == YES)
{
int iList;
NSArray *nodeList = [dsauth getListOfNodesWithUser:username];
[nodeList retain];
printf("%s %s was found in:\n", groupSearch ? "Group" : "User",
[username UTF8String]);
int iListLimit = [nodeList count];
for (iList = 0; iList < iListLimit; iList++)
{
printf("%s\n", [[nodeList objectAtIndex:iList] UTF8String]);
}
[nodeList release];
}
else
status = [dsauth authUserOnSearchPath:username password:password];
[loopPool release];
loopPool = nil;
if (queryIterations != 1)
{
nowtime = time(NULL);
localtime = ctime(&nowtime);
localtime[strlen(localtime)-1] = 0;
char *statusString = [dsStat cStringForStatus:status];
printf("%s ---------------- status: %s (%d)\n", localtime, statusString, status);
free(statusString);
statusString = nil;
if (reportStatusCodes) fprintf(stderr, "%d\n",status);
}
fflush(stdout);
if (delayInSeconds > 0 && (i+1 < queryIterations || queryIterations == 0))
sleep(delayInSeconds);
if ((queryIterations > 1 && i+1 < queryIterations) || queryIterations == 0)
[dsauth reset];
NS_HANDLER
if (queryIterations == 1)
{
[localException retain];
[loopPool release];
[[localException autorelease] raise];
}
else
{
dirtException = (DSException*)localException;
printf("%s -- DS status: %s (%d)\n", [[dirtException reason] UTF8String],
[dirtException statusCString], [dirtException status]);
// If this is a eDSServerTimeout or eDSCannotAccessSession error, then probably DS shut down.
// We attempt to open a new connection to the DS server:
if ([dirtException status] == eDSServerTimeout || [dirtException status] == eDSCannotAccessSession)
{
printf("RESTARTING Directory Services.\n");
fflush(stdout);
[dsauth release];
dsauth = [[DSAuthenticate alloc] init];
if (reportStatusCodes) fprintf(stderr, "%d\n", [dirtException status]);
}
dirtException = nil;
}
NS_ENDHANDLER
} // End for loop
NS_HANDLER
if ([localException isKindOfClass:[DSException class]])
{
dirtException = (DSException*)localException;
fprintf(stderr, "%s -- DS status: %s (%d)\n", [[dirtException reason] UTF8String],
[dirtException statusCString], [dirtException status]);
status = [dirtException status];
}
else
{
fprintf(stderr, "Catching unknown exception: <%s> %s\n", [[localException name] UTF8String], [[localException reason] UTF8String]);
fprintf(stderr, "Attempting to clean up.\n");
}
NS_ENDHANDLER
// Clean up, close Dir Server
if (dsauth != nil) [dsauth release];
}
else
usage();
if (username != nil)
[username release];
if (password != nil)
[password release];
if (sNodeToSearch != nil)
[sNodeToSearch release];
[pool release];
if (doVerbose)
{
char *statusString = [dsStat cStringForStatus: status];
printf("exiting cleanly, status: %s (%d)\n", statusString, status);
free(statusString);
statusString = nil;
}
[dsStat release];
return status;
}
void catch_int(int sig_num)
{
static BOOL calledOnce = NO;
if (calledOnce)
exit(3);
sigIntRaised = YES;
fprintf(stderr, "\n\n-------------------- Cleaning up, please wait. --------------------\n");
fprintf(stderr, " If you wish to exit immediately, issue CTRL-C or signal again.\n\n");
fflush(stderr);
calledOnce = YES;
}
void usage(void) {
printf("DIRT: The DIRectory Tool for testing authentication against the\n" );
printf(" DirectoryServices API.\n");
printf("Version %s\n\n", TOOLS_VERSION);
printf("Usage: dirt [-c] [-g] [-l | -m path | -n] [-q query_iterations [-d seconds]]\n"
" [-a auth_method] -u username [-p password]\n\n");
printf(" -l\t\tQuery Local Node only\n");
printf(" -c\t\tQuery the Contacts Search Policy\n\t\t(default is to use the Authentication Search Policy)\n");
printf(" -m path\tQuery on Node named by given path\n");
printf(" -q n\t\tPerform the specified query operation n times.\n\t\t(specify 0 to loop forever)\n");
printf(" -d n\t\tSleep n seconds between each query iteration. Default is 0.\n");
printf(" -n\t\tOnly list Nodes in Search Policy where user (or group) is found\n\t\t(password not required)\n");
printf(" -g\t\tQuery for groups instead of users.\n");
printf(" -a auth_method\tUse specified authentication method. Available methods:\n\t\t\tnt --> SMB-NT\n");
printf("\n");
exit(0);
}

98
dscacheutil/dscacheutil.1 Normal file
View File

@ -0,0 +1,98 @@
.Dd Jan 14, 2007
.Dt dscacheutil 1
.Os Darwin
.Sh NAME
.Nm dscacheutil
.Nd gather information, statistics and initiate queries to the Directory Service cache.
.Sh SYNOPSIS
.Nm
.Fl h
.Nm
.Fl q Ar category Op Fl a Ar key Ar value
.Nm
.Fl cachedump Op Fl buckets
.Op Fl entries Op Ar category
.Nm
.Fl configuration
.Nm
.Fl flushcache
.Nm
.Fl statistics
.Pp
.Sh DESCRIPTION
.Nm
does various operations against the Directory Service cache including gathering statistics, initiating lookups, inspection, cache flush, etc. This tool replaces most of the functionality of the lookupd tool previously available in the OS.
.Pp
.Sh FLAGS
A list of flags and their descriptions:
.Bl -tag -width -ident
.It Fl h
Lists the options for calling
.Nm
.It Fl q Ar category
Initiate a query using standard calls. These calls will either return results from the cache or go fetch live data and place them in the cache. By default if no specific query is requested via
.Fl a
then all results within that category will be returned.
.It Fl a Ar key Ar value
Optional flag to
.Fl q
for a specific key with a value.
.It Fl cachedump
Dumps an overview of the cache by default. Additional flags will provide more detailed information.
.It Fl buckets
Used in conjunction with
.Fl cachedump
to also print hash bucket usage of the current cache.
.It Fl entries Op Ar category
Used in conjunction with
.Fl cachedump
to dump detailed information about cache entries. An optional category can be supplied to only see types of interest. Dumping 'host' entries can only be done by administrative users.
.It Fl configuration
Prints current configuration information, such as the search policy from Directory Service and cache parameters.
.It Fl flushcache
Flushes the entire cache. This should only be used in extreme cases. Validation information is used within the cache along with other techniques to ensure the OS has valid information available to it.
.It Fl statistics
Prints statistics from the cache including an overview and detailed call statistics. Some calls are not cached but are derived from other calls internally. Cache hits and cache misses may not always be equal to external calls. For example getaddrinfo is actually a combination of gethostbyname with other calls internally to the cache to maximize cache hit rate.
.El
.Pp
Available categories and associated keys:
.Bl -tag -width "xxxxxxxxxx"
.It Ar group
name or gid
.It Ar host
name or ip_address (used for both IPv6 and IPv4)
.It Ar mount
name
.It Ar protocol
name or number
.It Ar rpc
name or number
.It Ar service
name or port
.It Ar user
name or uid
.El
.Pp
.Sh EXAMPLES
.Pp
.Bl -tag -width -indent
.It Lookup a user:
.Dl % dscacheutil -q user -a name jdoe
.Dl name: jdoe
.Dl password: ********
.Dl uid: 501
.Dl gid: 501
.Dl dir: /Users/jdoe
.Dl shell: /bin/csh
.Dl gecos: John Doe
.It Lookup all users:
.Dl % dscacheutil -q user
.It Dump cache overview:
.Dl % dscacheutil -cachedump
.It Dump cache details with user entries:
.Dl % dscacheutil -cachedump -entries user
.El
.Pp
.Sh SEE ALSO
.Xr DirectoryService 8 ,
.Xr dsmemberutil 1

788
dscacheutil/dscacheutil.m Normal file
View File

@ -0,0 +1,788 @@
/*
* Copyright (c) 2007 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#import <OpenDirectory/NSOpenDirectory.h>
#import <Foundation/Foundation.h>
#import <DSlibinfoMIG.h>
#import <netdb.h>
#import <unistd.h>
#import <pwd.h>
#import <grp.h>
#import <fstab.h>
#import <arpa/inet.h>
#import <sysexits.h>
#import <membership.h>
char *gProgName = NULL;
id getCacheState( NSString *inKey )
{
NSPropertyListFormat format = NSPropertyListXMLFormat_v1_0;
ODNode *odNode = [ODNode nodeWithSession: [ODSession defaultSession] name: @"/Cache" error: nil];
NSDictionary *details = [odNode nodeDetailsForKeys: [NSArray arrayWithObject: inKey] error: nil];
NSString *detailsString = [[details objectForKey: inKey] lastObject];
id cacheInfo = nil;
if ( detailsString != nil )
{
NSData *tempData = [detailsString dataUsingEncoding: NSUTF8StringEncoding];
cacheInfo = [NSPropertyListSerialization propertyListFromData: tempData
mutabilityOption: NSPropertyListMutableContainersAndLeaves
format: &format
errorDescription: nil];
// change dates to strings
if ( [cacheInfo isKindOfClass:[NSDictionary class]] )
{
for ( NSMutableDictionary *entry in [cacheInfo objectForKey: @"Entries"] )
{
id bestBefore = [entry objectForKey: @"Best Before"];
id lastAccess = [entry objectForKey: @"Last Access"];
if ( bestBefore != nil )
[entry setObject: [bestBefore descriptionWithCalendarFormat: @"%m/%d/%y %H:%M:%S" timeZone: nil locale: nil] forKey: @"Best Before"];
if ( lastAccess != nil )
[entry setObject: [lastAccess descriptionWithCalendarFormat: @"%m/%d/%y %H:%M:%S" timeZone: nil locale: nil] forKey: @"Last Access"];
}
}
}
else
{
fprintf( stderr, "Unable to get details from the cache node\n" );
}
return cacheInfo;
}
void print_stringlist( const char *inTitle, char **inList )
{
if ( inList != NULL && (*inList) != NULL )
{
printf( "%s", inTitle );
while ( (*inList) != NULL )
{
printf( "%s ", (*inList) );
inList++;
}
printf( "\n" );
}
}
void print_passwd( struct passwd *entry )
{
if ( entry != NULL )
{
if ( entry->pw_name != NULL )
printf( "name: %s\n", entry->pw_name );
if ( entry->pw_passwd != NULL )
printf( "password: %s\n", entry->pw_passwd );
printf( "uid: %d\n", entry->pw_uid );
printf( "gid: %d\n", entry->pw_gid );
if ( entry->pw_dir != NULL )
printf( "dir: %s\n", entry->pw_dir );
if ( entry->pw_shell != NULL )
printf( "shell: %s\n", entry->pw_shell );
if ( entry->pw_gecos != NULL )
printf( "gecos: %s\n", entry->pw_gecos );
printf( "\n" );
}
}
void print_group( struct group *entry )
{
if ( entry != NULL )
{
if ( entry->gr_name != NULL )
printf( "name: %s\n", entry->gr_name );
if ( entry->gr_passwd != NULL )
printf( "password: %s\n", entry->gr_passwd );
printf( "gid: %d\n", entry->gr_gid );
print_stringlist( "users: ", entry->gr_mem );
printf( "\n" );
}
}
void print_service( struct servent *entry )
{
if ( entry != NULL )
{
if ( entry->s_name != NULL )
printf( "name: %s\n", entry->s_name );
print_stringlist( "aliases: ", entry->s_aliases );
if ( entry->s_proto != NULL )
printf( "protocol: %s\n", entry->s_proto );
printf( "port: %d\n", ntohs(entry->s_port) );
printf( "\n" );
}
}
void print_rpc( struct rpcent *entry )
{
if ( entry != NULL )
{
if ( entry->r_name != NULL )
printf( "name: %s\n", entry->r_name );
print_stringlist( "aliases: ", entry->r_aliases );
printf( "number: %d\n", entry->r_number );
printf( "\n" );
}
}
void print_proto( struct protoent *entry )
{
if ( entry != NULL )
{
if ( entry->p_name != NULL )
printf( "name: %s\n", entry->p_name );
print_stringlist( "aliases: ", entry->p_aliases );
printf( "number: %d\n", entry->p_proto );
printf( "\n" );
}
}
void print_mount( struct fstab *entry )
{
if ( entry != NULL )
{
if ( entry->fs_spec != NULL )
printf( "name: %s\n", entry->fs_spec );
if ( entry->fs_file != NULL )
printf( "file: %s\n", entry->fs_file );
if ( entry->fs_vfstype != NULL )
printf( "vfstype: %s\n", entry->fs_vfstype );
if ( entry->fs_mntops != NULL )
printf( "options: %s\n", entry->fs_mntops );
if ( entry->fs_type != NULL )
printf( "type: %s\n", entry->fs_type );
if ( entry->fs_vfstype != NULL )
printf( "vfstype: %s\n", entry->fs_vfstype );
printf( "frequency: %d\n", entry->fs_freq );
printf( "pass: %d\n", entry->fs_passno );
printf( "\n" );
}
}
void print_hostent( struct hostent *entry )
{
if ( entry != NULL )
{
if ( entry->h_name != NULL )
printf( "name: %s\n", entry->h_name );
print_stringlist( "alias: ", entry->h_aliases );
char ipStr[INET6_ADDRSTRLEN];
char **addrPtr;
char *addressName = (entry->h_addrtype == AF_INET ? "ip_address" : "ipv6_address");
for ( addrPtr = entry->h_addr_list; (*addrPtr) != NULL; addrPtr++ ) {
if ( inet_ntop(entry->h_addrtype, (*addrPtr), ipStr, sizeof(ipStr)) )
printf( "%s: %s\n", addressName, ipStr );
}
printf( "\n" );
}
}
int query( char *inQueryCategory, char *inQueryKey, char *inQueryValue )
{
if ( strcasecmp(inQueryCategory, "host") == 0 )
{
if ( inQueryKey == NULL )
{
struct hostent *entry;
sethostent( 1 );
while ( (entry = gethostent()) != NULL )
print_hostent( entry );
endhostent();
return 0;
}
else if ( inQueryValue != NULL )
{
if ( strcasecmp(inQueryKey, "name") == 0 )
{
print_hostent( gethostbyname2(inQueryValue, AF_INET6) );
print_hostent( gethostbyname2(inQueryValue, AF_INET) );
}
else if ( strcasecmp(inQueryKey, "ip_address") == 0 )
{
unsigned char buffer[16];
uint32_t tempFamily = AF_UNSPEC;
if( inet_pton(AF_INET6, inQueryValue, buffer) == 1 )
tempFamily = AF_INET6;
if( tempFamily == AF_UNSPEC && inet_pton(AF_INET, inQueryValue, buffer) == 1 )
tempFamily = AF_INET;
if ( tempFamily != AF_UNSPEC )
print_hostent( gethostbyaddr( buffer, sizeof(buffer), tempFamily) );
else
fprintf( stderr, "Invalid address provided\n" );
}
}
else
{
fprintf( stderr, "query failed!\n" );
}
}
else if ( strcasecmp(inQueryCategory, "user") == 0 )
{
if ( inQueryKey == NULL )
{
struct passwd *entry;
setpwent();
while ( (entry = getpwent()) != NULL )
print_passwd( entry );
endpwent();
}
else if ( inQueryValue != NULL )
{
if ( strcasecmp(inQueryKey, "name") == 0 )
print_passwd( getpwnam(inQueryValue) );
else if ( strcasecmp(inQueryKey, "uid") == 0 )
print_passwd( getpwuid(atoi(inQueryValue)) );
}
else
{
fprintf( stderr, "query failed!\n" );
}
}
else if ( strcasecmp(inQueryCategory, "group") == 0 )
{
if ( inQueryKey == NULL )
{
struct group *entry;
setgrent();
while ( (entry = getgrent()) != NULL )
print_group( entry );
endgrent();
}
else if ( inQueryValue != NULL )
{
if ( strcasecmp(inQueryKey, "name") == 0 )
print_group( getgrnam(inQueryValue) );
else if ( strcasecmp(inQueryKey, "gid") == 0 )
print_group( getgrgid(atoi(inQueryValue)) );
}
else
{
fprintf( stderr, "query failed!\n" );
}
}
else if ( strcasecmp(inQueryCategory, "service") == 0 )
{
if ( inQueryKey == NULL )
{
struct servent *entry;
setservent( 1 );
while ( (entry = getservent()) != NULL )
print_service( entry );
endservent();
}
else if ( inQueryValue != NULL )
{
if ( strcasecmp(inQueryKey, "name") == 0 )
print_service( getservbyname(inQueryValue, NULL) );
else if ( strcasecmp(inQueryKey, "port") == 0 )
print_service( getservbyport(htons(atoi(inQueryValue)), NULL) );
}
else
{
fprintf( stderr, "query failed!\n" );
}
}
else if ( strcasecmp(inQueryCategory, "rpc") == 0 )
{
if ( inQueryKey == NULL )
{
struct rpcent *entry;
setrpcent( 1 );
while ( (entry = getrpcent()) != NULL )
print_rpc( entry );
endrpcent();
}
else if ( inQueryValue != NULL )
{
if ( strcasecmp(inQueryKey, "name") == 0 )
print_rpc( getrpcbyname(inQueryValue) );
else if ( strcasecmp(inQueryKey, "number") == 0 )
print_rpc( getrpcbynumber( atoi(inQueryValue)) );
}
else
{
fprintf( stderr, "query failed!\n" );
}
}
else if ( strcasecmp(inQueryCategory, "protocol") == 0 )
{
if ( inQueryKey == NULL )
{
struct protoent *entry;
setprotoent( 1 );
while ( (entry = getprotoent()) != NULL )
print_proto( entry );
endprotoent();
}
else if ( inQueryValue != NULL )
{
if ( strcasecmp(inQueryKey, "name") == 0 )
print_proto( getprotobyname(inQueryValue) );
else if ( strcasecmp(inQueryKey, "number") == 0 )
print_proto( getprotobynumber( atoi(inQueryValue)) );
}
else
{
fprintf( stderr, "query failed!\n" );
}
}
else if ( strcasecmp(inQueryCategory, "mount") == 0 )
{
if ( inQueryKey == NULL )
{
struct fstab *entry;
setfsent();
while ( (entry = getfsent()) != NULL )
print_mount( entry );
endfsent();
}
else if ( inQueryValue != NULL )
{
if ( strcasecmp(inQueryKey, "name") == 0 )
print_mount( getfsspec(inQueryValue) );
}
else
{
fprintf( stderr, "query failed!\n" );
}
}
return 0;
}
int flushcache( void )
{
char reply[16384] = { 0, };
mach_msg_type_number_t replyCnt = 0;
vm_offset_t ooreply = 0;
mach_msg_type_number_t ooreplyCnt = 0;
int32_t procno = 0;
security_token_t userToken;
mach_port_t serverPort;
if ( bootstrap_look_up(bootstrap_port, kDSStdMachDSLookupPortName, &serverPort) == KERN_SUCCESS )
{
if( libinfoDSmig_GetProcedureNumber(serverPort, "_flushcache", &procno, &userToken) == KERN_SUCCESS )
{
libinfoDSmig_Query( serverPort, procno, "", 0, reply, &replyCnt, &ooreply, &ooreplyCnt, &userToken );
return 0;
}
}
fprintf( stderr, "Flushcache failed, unable to talk to daemon\n" );
return EIO;
}
void printDictFormatted( const char *inTitle, const char *inIndent, NSDictionary *inDictionary )
{
NSArray *allKeys = [[inDictionary allKeys] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)];
// determine the max key length
int maxLen = 0;
for ( NSString *key in allKeys )
{
int tempLen = strlen( [key UTF8String] );
if ( tempLen > maxLen )
maxLen = tempLen;
}
// now print them all out
printf( "%s%s\n", inIndent, inTitle );
for ( NSString *key in allKeys )
{
const char *keyStr = [key UTF8String];
id value = [inDictionary objectForKey: key];
int iPadLen = maxLen - strlen( keyStr );
int ii;
char padStr[maxLen + 1];
if ( [value isKindOfClass: [NSArray class]] || [value isKindOfClass: [NSDictionary class]] )
continue;
memset( padStr, ' ', iPadLen );
padStr[iPadLen] = '\0';
printf( "%s %s%s - %s\n", inIndent, keyStr, padStr, ([value isKindOfClass:[NSString class]] ? [value UTF8String] : [[value stringValue] UTF8String]) );
}
printf( "\n" );
}
void printFormattedCacheEntry( char *formatString, NSDictionary *inEntry )
{
// first print the high level info, then below it the keys
NSString *theType = [inEntry objectForKey: @"Type"];
NSString *bestBefore = [inEntry objectForKey: @"Best Before"];
NSString *lastAccess = [inEntry objectForKey: @"Last Access"];
NSString *hits = [inEntry objectForKey: @"Hits"];
NSString *refs = [inEntry objectForKey: @"Reference Count"];
NSString *ttl = [inEntry objectForKey: @"TTL"];
NSNumber *negative = [inEntry objectForKey: @"Negative Entry"];
NSString *node = [inEntry valueForKeyPath: @"Validation Information.Name"];
printf( formatString, [theType UTF8String], [bestBefore UTF8String], [lastAccess UTF8String], [hits UTF8String],
[refs UTF8String], [ttl UTF8String], ([negative boolValue] ? "YES" : ""), (node ? [node UTF8String] : "") );
for (NSString *key in [inEntry objectForKey: @"Keys"])
{
printf( " %20s: %s\n", "Key", [key UTF8String] );
}
printf( "\n" );
}
int cacheDump( char *inCategory, BOOL inBuckets, BOOL inEntries, BOOL isAdmin )
{
NSMutableDictionary *cacheInfo = getCacheState( (inEntries ? @"dsAttrTypeNative:LibinfoCacheDetails" : @"dsAttrTypeNative:LibinfoCacheOverview") );
NSArray *cacheEntries = [cacheInfo objectForKey: @"Entries"];
NSArray *bucketInfo = [cacheInfo objectForKey: @"Bucket Info"];
NSDictionary *entrySummary = [cacheInfo objectForKey: @"Counts By Type"];
[cacheInfo removeObjectsForKeys: [NSArray arrayWithObjects: @"Bucket Info", @"Entries", @"Default TTL", @"Hash Slots", @"Max Bucket Depth",
@"Policy Flags", @"Cache Cap", @"Counts By Type", nil]];
if ( cacheInfo != nil )
{
printDictFormatted( "DirectoryService Cache Overview:", "", cacheInfo );
printDictFormatted( "Entry count by category:", " ", entrySummary );
if ( inBuckets == YES && [bucketInfo count] != 0 )
{
printf( "Bucket Use Information:\n\n" );
printf( " Bucket Depth Bucket Depth Bucket Depth Bucket Depth\n" );
printf( " ------ ----- ------ ----- ------ ----- ------ -----\n" );
int iCount = 0;
for ( NSDictionary *bucket in bucketInfo )
{
printf( " %6d %5d", [[bucket objectForKey: @"Bucket"] intValue], [[bucket objectForKey: @"Depth"] intValue] );
if ( ++iCount == 4 )
{
printf( "\n" );
iCount = 0;
}
}
if ( iCount < 4 )
printf( "\n\n" );
else
printf( "\n" );
}
if ( inEntries == YES && [cacheEntries count] != 0 )
{
NSString *theType = (inCategory != NULL ? [NSString stringWithUTF8String: inCategory] : nil);
char *formatString = " %10s %18s %18s %8s %6s %8s %5s %s\n";
printf( "Cache entries (ordered as stored in the cache):\n\n" );
printf( formatString, "Category", "Best Before", "Last Access", "Hits", "Refs", "TTL", "Neg", "DS Node" );
printf( formatString, "----------", "------------------", "------------------", "--------", "------", "--------", "-----", "---------" );
for (NSDictionary *entry in cacheEntries)
{
if ( theType != nil && [theType caseInsensitiveCompare: [entry objectForKey: @"Type"]] != NSOrderedSame )
continue;
// skip host entries if not admin
if ( [[entry objectForKey: @"Type"] caseInsensitiveCompare: @"Host"] == NSOrderedSame && isAdmin == NO )
continue;
printFormattedCacheEntry( formatString, entry );
}
}
}
return 0;
}
int dumpStatistics( void )
{
NSArray *cacheInfo = getCacheState( @"dsAttrTypeNative:Statistics" );
if ( [cacheInfo count] > 0 )
{
NSMutableDictionary *globalStats = [cacheInfo objectAtIndex: 0];
[globalStats removeObjectForKey: @"Category"];
printDictFormatted( "Overall Statistics:", "", globalStats );
}
if ( [cacheInfo count] > 1 )
{
printf( "Statistics by procedure:\n\n" );
printf( " Procedure Cache Hits Cache Misses External Calls\n" );
printf( " ------------------ ---------- ------------ --------------\n" );
for ( NSMutableDictionary *stats in [[cacheInfo objectAtIndex: 1] objectForKey: @"subValues"] )
{
NSString *total = [stats objectForKey: @"Total Calls"];
if ( [total intValue] != 0 )
{
NSString *category = [stats objectForKey: @"Category"];
NSString *misses = [stats objectForKey: @"Cache Misses"];
NSString *hits = [stats objectForKey: @"Cache Hits"];
printf( " %18s %10s %12s %14s\n", [category UTF8String], [hits UTF8String], [misses UTF8String], [total UTF8String] );
}
}
}
printf( "\n" );
return 0;
}
int dumpConfiguration( void )
{
// here we just dump the search policy and some minor details about the cache
NSError *error = nil;
ODNode *odNode = [ODNode nodeWithSession: [ODSession defaultSession] type: kODNodeTypeAuthentication error: &error];
if ( odNode != nil )
{
NSArray *searchPolicy = [odNode subnodeNamesAndReturnError: &error];
if ( searchPolicy != nil )
{
printf( "DirectoryService Cache search policy:\n" );
for ( NSString *value in searchPolicy )
printf( " %s\n", [value UTF8String] );
printf( "\n" );
}
else
{
fprintf( stderr, "Unable to open Search node to get search policy - %s\n", [[error description] UTF8String] );
}
}
else
{
fprintf( stderr, "Unable to open Search node to get search policy - %s\n", [[error description] UTF8String] );
}
NSMutableDictionary *cacheInfo = getCacheState( @"dsAttrTypeNative:LibinfoCacheOverview");
if ( cacheInfo != nil )
{
[cacheInfo removeObjectsForKeys: [NSArray arrayWithObjects: @"Buckets Used", @"Cache Size", @"Max Bucket Depth", @"Counts By Type", nil]];
printDictFormatted( "Settings:", "", cacheInfo );
}
else
{
fprintf( stderr, "Unable to get cache configuration information\n" );
}
return 0;
}
void usage( void )
{
printf( "Usage: dscacheutil -h\n"
" dscacheutil -q category [-a key value]\n"
" dscacheutil -cachedump [-buckets] [-entries [category]]\n"
" dscacheutil -configuration\n"
" dscacheutil -flushcache\n"
" dscacheutil -statistics\n" );
}
int main( int argc, char *argv[] )
{
int ch;
int ii;
BOOL bQuery = NO;
BOOL bCacheDump = NO;
BOOL bEntries = NO;
BOOL bBuckets = NO;
char *pQueryCategory = NULL;
char *pQueryKey = NULL;
char *pQueryValue = NULL;
char *pCategory = NULL;
// first get our program name
char *slash = strrchr( argv[0], '/' );
if ( slash != NULL )
gProgName = ++slash;
else
gProgName = argv[0];
while ( (ch = getopt(argc, argv, "dDq:a:hs:c:f:b:e:")) != -1 )
{
switch (ch)
{
// these are lookupd options we don't support
case 'd':
case 'D':
if ( strcmp(gProgName, "lookupd") == 0 )
{
printf( "Lookupd no longer exists in this version of the OS. Only a limited number of\n"
"legacy options are available. Please use dscacheutil as the lookupd tool\n"
"may go away in the future.\n\n" );
}
usage();
return EX_USAGE;
case 'e':
if ( strcmp(optarg, "ntries") != 0 )
{
usage();
return EX_USAGE;
}
if ( argv[optind] != NULL && argv[optind][0] != '-' )
{
pCategory = argv[optind];
optind++;
}
bEntries = YES;
break;
case 'b':
if ( strcmp(optarg, "uckets") != 0 )
{
usage();
return EX_USAGE;
}
bBuckets = YES;
break;
case 'c':
if ( strcmp(optarg, "achedump") == 0 )
{
bCacheDump = YES;
continue;
}
else if ( strcmp(optarg, "onfiguration") == 0 )
return dumpConfiguration();
usage();
return EX_USAGE;
case 'f':
if ( strcmp(optarg, "lushcache") != 0 )
{
usage();
return EX_USAGE;
}
return flushcache();
case 'q':
bQuery = YES;
pQueryCategory = optarg;
break;
case 'a':
pQueryKey = optarg;
if ( argv[optind] == NULL || argv[optind][0] == '-' )
{
usage();
return EX_USAGE;
}
pQueryValue = argv[optind];
optind++;
break;
case 's':
if ( strcmp(optarg, "tatistics") != 0 )
{
usage();
return EX_USAGE;
}
return dumpStatistics();
case 'h':
usage();
return 0;
case '?':
return EX_USAGE;
default:
break;
}
}
if ( bQuery == YES )
return query( pQueryCategory, pQueryKey, pQueryValue );
else if ( bCacheDump == YES ) {
int isAdmin = 0;
// require user to be part of admin group to view host lookups
if ( (pCategory == NULL || strcasecmp(pCategory, "host") == 0) && geteuid() != 0 ) {
uuid_t userUU;
mbr_uid_to_uuid( getuid(), userUU );
if ( mbr_check_membership_by_id(userUU, 80, &isAdmin) == 0 && isAdmin == 0 && pCategory != NULL ) {
// TODO: we could prompt user for username/password of an admin user, but not really necessary
printf( "Viewing host entries requires administrator privileges.\n" );
return EX_NOPERM;
}
}
return cacheDump( pCategory, bBuckets, bEntries, isAdmin );
}
usage();
return EX_USAGE;
}

1
dscacheutil/lookupd.1 Normal file
View File

@ -0,0 +1 @@
.so man1/dscacheutil.1

50
dscl/DSCLCommandHistory.h Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSCLCommandHistory
*/
#import <Foundation/Foundation.h>
#define HISTORY_CAPACITY 50
@interface DSCLCommandHistory : NSObject
{
NSString *mCommandList[HISTORY_CAPACITY];
unsigned int mLastItem;
unsigned int mCurrentItem;
BOOL mIsClean;
}
- (void)addCommand:(NSString*)inCommand;
- (void)addTemporaryCommand:(NSString*)inCommand;
- (NSString*)previousCommand;
- (NSString*)nextCommand;
- (void)resetToLast;
- (BOOL)isClean;
@end

136
dscl/DSCLCommandHistory.m Normal file
View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header DSCLCommandHistory
*/
#import "DSCLCommandHistory.h"
@interface DSCLCommandHistory (DSCLCommandHistoryPrivate)
- (unsigned int)increment:(unsigned int*)i;
- (unsigned int)decrement:(unsigned int*)i;
- (unsigned int)incrementCurrent;
- (unsigned int)decrementCurrent;
@end
@implementation DSCLCommandHistory
- init
{
unsigned int i;
[super init];
mCurrentItem = 0;
mLastItem = 0;
mIsClean = YES;
for (i=0; i < HISTORY_CAPACITY; i++)
mCommandList[i] = nil;
return self;
}
- (void) dealloc
{
unsigned int i;
for (i=0; i < HISTORY_CAPACITY; i++)
[mCommandList[i] release]; // It's ok to send a superfluous message to a nil pointer
[super dealloc];
}
- (void)addCommand:(NSString*)inCommand
{
[mCommandList[mLastItem] release];
mCommandList[mLastItem] = [inCommand retain];
[self increment:&mLastItem];
mCurrentItem = mLastItem;
}
- (void)addTemporaryCommand:(NSString*)inCommand
{
[mCommandList[mLastItem] release];
mCommandList[mLastItem] = [inCommand retain];
}
- (NSString*)previousCommand
{
[self decrementCurrent];
return mCommandList[mCurrentItem];
}
- (NSString*)nextCommand
{
[self incrementCurrent];
return mCommandList[mCurrentItem];
}
- (void)resetToLast
{
mCurrentItem = mLastItem;
}
- (BOOL)isClean
{
return mCurrentItem == mLastItem;
}
@end
@implementation DSCLCommandHistory (DSCLCommandHistoryPrivate)
- (unsigned int)increment:(unsigned int*)i
{
unsigned int oldValue = *i;
if (*i == HISTORY_CAPACITY-1)
*i = 0;
else
(*i)++;
return oldValue;
}
- (unsigned int)decrement:(unsigned int*)i
{
unsigned int oldValue = *i;
if (*i == 0)
*i = HISTORY_CAPACITY - 1;
else
(*i)--;
return oldValue;
}
- (unsigned int)incrementCurrent
{
if (mCurrentItem != mLastItem)
return [self increment:&mCurrentItem];
else
return mCurrentItem;
}
- (unsigned int)decrementCurrent
{
unsigned int oldValue = [self decrement:&mCurrentItem];
if (mLastItem == mCurrentItem || mCommandList[mCurrentItem] == nil)
[self increment:&mCurrentItem];
return oldValue;
}
@end

87
dscl/NSStringEscPath.h Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header NSStringEscPath
*/
#import <Foundation/Foundation.h>
/*!
* @category NSString(NSStringEscPath)
* A category on NSString that provides
* on extra method for handling paths.
*/
@interface NSString (NSStringEscPath)
/*!
@method escapablePathFromArray:
@abstract Takes an array and turns it into an escaped path NSString
@discussion Returns and escaped string that can be re-parsed if necessary
*/
+ (NSString *)escapablePathFromArray:(NSArray *)inArray;
/*!
* @method unescapedPathComponents
* @abstract Like pathComponents, but will honor escaped slashes.
* @discussion Performs the same operation as pathComponents
* but it will honor escaped slashes for allowing the use
* of forward slashes in a name.
*
* Example: @"/path/to/file/namewith\/slash"
* will be split into this array:
*
* (@"/", @"path", @"to", @"file", @"namewith/slash")
* instead of the way pathComponents would do it:
*
* (@"/", @"path", @"to", @"file", @"namewith\", @"slash")
*
* @result Array of NSStrings of the path components.
*/
- (NSArray *)unescapedPathComponents;
/*!
@method unescapedString
@abstract This gets the string in a standard form for use by removing escape characters
@discussion Unescapes all the components and returns a clean string for normal use
*/
- (NSString *)unescapedString;
/*!
@method escapedString
@abstract Escapes the string for use by routines
@discussion Escapes the string
*/
- (NSString *)escapedString;
/*!
@method shortcut for stringByReplacingPercentEscapesUsingEncoding:
@abstract shortcut for calling stringByReplacingPercentEscapesUsingEncoding, for legacy calls
@discussion shortcut for calling stringByReplacingPercentEscapesUsingEncoding, for legacy calls
*/
- (NSString *)urlEncoded;
@end

105
dscl/NSStringEscPath.m Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header NSStringEscPath
*/
#import "NSStringEscPath.h"
@implementation NSString (NSStringEscPath)
+ (NSString *)escapablePathFromArray:(NSArray *)inArray
{
NSString *returnValue = nil;
if( [inArray count] )
{
NSEnumerator *pathEnum = [inArray objectEnumerator];
NSString *value = nil;
// preflight with first value
returnValue = [[pathEnum nextObject] escapedString];
while( value = [pathEnum nextObject] ) {
returnValue = [returnValue stringByAppendingString: @"/"];
returnValue = [returnValue stringByAppendingString: [value escapedString]];
}
}
return returnValue;
}
- (NSArray *)unescapedPathComponents
{
NSMutableArray *newComponents = [NSMutableArray array];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableString *workingString = [NSMutableString stringWithString: self];
// unescape everything so we have good components that we can pass around without worrying
[workingString replaceOccurrencesOfString: @"\\/" withString:@"%2f" options:NSLiteralSearch range:NSMakeRange(0,[workingString length])];
[workingString replaceOccurrencesOfString: @"\\\\" withString:@"%5c" options:NSLiteralSearch range:NSMakeRange(0,[workingString length])];
[workingString replaceOccurrencesOfString: @"\\" withString:@"" options:NSLiteralSearch range:NSMakeRange(0,[workingString length])];
NSArray *components = [workingString pathComponents];
NSEnumerator *compEnum = [components objectEnumerator];
NSString *component;
while( component = [compEnum nextObject] )
{
[newComponents addObject: [component stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
}
[pool release];
return newComponents;
}
- (NSString *)unescapedString
{
NSMutableString *workingString = [[self mutableCopy] autorelease];
[workingString replaceOccurrencesOfString: @"\\/" withString:@"%2f" options:NSLiteralSearch range:NSMakeRange(0,[workingString length])];
[workingString replaceOccurrencesOfString: @"\\\\" withString:@"%5c" options:NSLiteralSearch range:NSMakeRange(0,[workingString length])];
[workingString replaceOccurrencesOfString: @"\\" withString:@"" options:NSLiteralSearch range:NSMakeRange(0,[workingString length])];
return [workingString stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
}
- (NSString *)escapedString
{
NSMutableString *workingString = [[self mutableCopy] autorelease];
[workingString replaceOccurrencesOfString: @"\\" withString:@"\\\\" options:NSLiteralSearch range:NSMakeRange(0,[workingString length])];
[workingString replaceOccurrencesOfString: @"/" withString: @"\\/" options:NSLiteralSearch range:NSMakeRange(0,[workingString length])];
[workingString replaceOccurrencesOfString: @" " withString: @"\\ " options:NSLiteralSearch range:NSMakeRange(0,[workingString length])];
return workingString;
}
- (NSString *)urlEncoded
{
return [self stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
@end

53
dscl/PathDirService.h Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathDirService
*/
#import <Foundation/Foundation.h>
#import "PathItem.h"
@class DSoDirectory;
@interface PathDirService : PathItem
{
DSoDirectory *_dir;
NSMutableDictionary *_attribs;
}
// Open a connection to the local machine.
- initWithLocal;
// Open a connection to the local machine to the local only DS daemon
- initWithLocalPath:(NSString*)filePath;
// Open a conection to a remote machine using DS Proxy.
- initWithHost:(NSString*)hostName user:(NSString*)user password:(NSString*)password;
- (NSArray*) getPluginList;
// ATM - PlugInManager needs access to directory
-(DSoDirectory*) directory;
@end

281
dscl/PathDirService.m Normal file
View File

@ -0,0 +1,281 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathDirService
*/
#import <DirectoryService/DirServicesTypes.h>
#import "PathDirService.h"
#import "DSoDirectory.h"
#import "DSoNode.h"
#import "PathNode.h"
#import "PathNodeConfig.h"
#import "PathNodeSearch.h"
#import "DSoRecord.h"
#import "DSoNodeConfig.h"
#import "DSoException.h"
#import "DSoDirectoryPriv.h"
#define kHostnameKey @"hostname"
#define kUserKey @"user"
static NSDictionary *gSearchPaths;
@implementation PathDirService
+ (void)initialize
{
gSearchPaths = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithLong:eDSSearchNodeName],
@"Search",
[NSNumber numberWithLong:eDSContactsSearchNodeName],
@"Contact",
nil];
}
// ----------------------------------------------------------------------------
// Initialization / teardown
#pragma mark ******** Initialization / teardown ********
- init
{
[super init];
_attribs = [[NSMutableDictionary alloc] init];
return self;
}
- initWithLocal
{
[self init];
_dir = [[DSoDirectory alloc] initWithLocal];
[_attribs setObject:@"localhost" forKey:kHostnameKey];
return self;
}
- initWithLocalPath:(NSString*)filePath
{
[self init];
_dir = [[DSoDirectory alloc] initWithLocalPath:filePath];
[_attribs setObject:@"localonly" forKey:kHostnameKey];
return self;
}
- initWithHost:(NSString*)hostName user:(NSString*)user password:(NSString*)password
{
[self init];
_dir = [[DSoDirectory alloc] initWithHost:hostName user:user password:password];
[_attribs setObject:hostName forKey:kHostnameKey];
[_attribs setObject:user forKey:kUserKey];
return self;
}
- (void)dealloc
{
[_dir release];
[_attribs release];
[super dealloc];
}
-(DSoDirectory*) directory
{
// ATM - PlugInManager needs access to directory instance
return _dir;
}
// ----------------------------------------------------------------------------
// PathItemProtocol implementations
#pragma mark ******** PathItemProtocol implementations ********
- (NSString*)name
{
return @"";
}
- (tDirStatus) read:(NSArray*)inKeys
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *key = nil;
NSString *value = nil;
NSEnumerator *keyEnum;
if (inKeys != nil && [inKeys count] > 0)
{
keyEnum = [inKeys objectEnumerator];
}
else
{
keyEnum = [_attribs keyEnumerator];
}
while (key = [keyEnum nextObject])
{
value = [_attribs objectForKey:key];
printf("%s: %s\n", [key UTF8String], [value UTF8String]);
}
[pool release];
return eDSNoErr;
}
- (NSArray*) getPluginList
{
NSArray* nodeNames = [_dir findNodeNames];
NSMutableSet* firstComponents = [NSMutableSet set];
NSEnumerator* nodeNameEnum = [nodeNames objectEnumerator];
NSString* nodeName = nil;
while ((nodeName = (NSString*)[nodeNameEnum nextObject]) != nil)
{
NSArray* pathComponents = [nodeName pathComponents];
if ([pathComponents count] > 1)
{
[firstComponents addObject:[pathComponents objectAtIndex:1]];
}
}
return [firstComponents allObjects]; // Already autoreleased.
}
- (NSArray*) getList
{
return [[self getPluginList] arrayByAddingObjectsFromArray:[gSearchPaths allKeys]];
}
- (tDirStatus) list:(NSString*)inPath key:(NSString*)inKey
{
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
DSoNodeConfig *configNode = [_dir configNode];
id keyEnum;
id key;
NSArray *plugins = [[self getPluginList] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
NSString *pluginName = nil;
int i = 0;
int cntLimit = 0;
cntLimit = [plugins count];
for (i = 0; i < cntLimit; i++)
{
pluginName = [plugins objectAtIndex:i];
if ([configNode pluginEnabled:pluginName])
printf("%s\n", [pluginName UTF8String]);
}
printf("\n");
keyEnum = [gSearchPaths keyEnumerator];
while(key = [keyEnum nextObject])
{
printf("%s\n", [key UTF8String]);
}
[p release];
return eDSNoErr;
}
- (PathItem*) cd:(NSString*)dest
{
PathItem *p = nil;
NSString *s = nil;
DSoNode *n = nil;
id pathVal = nil;
if (pathVal = [gSearchPaths objectForKey:dest])
{
// They typed a search path name.
long val = [pathVal longValue];
if (val == eDSSearchNodeName)
{
n = [_dir searchNode];
}
else
{
n = [_dir findNode:nil matchType:val];
}
if (n != nil)
{
s = [[NSString alloc] initWithFormat:@"/%@",dest];
p = [[PathNodeSearch alloc] initWithNode:n path:s type:val];
[(PathNode *)p setEnableSubNodes:NO];
[s release];
}
}
else if ([dest caseInsensitiveCompare:@"config"] == NSOrderedSame)
{
p = [[PathNodeConfig alloc] initWithNode:[_dir configNode] path:@"/Config"];
[(PathNodeConfig*)p setEnableSubNodes:NO];
}
else if ([dest caseInsensitiveCompare:@"configure"] == NSOrderedSame)
{
p = [[PathNodeConfig alloc] initWithNode:[_dir configNode] path:@"/Configure"];
[(PathNodeConfig*)p setEnableSubNodes:NO];
}
else if ([dest caseInsensitiveCompare:@"cache"] == NSOrderedSame)
{
NS_DURING
n = [_dir findNode:@"/Cache"];
NS_HANDLER
if (!DS_EXCEPTION_STATUS_IS(eNotHandledByThisNode))
[localException raise];
NS_ENDHANDLER
p = [[PathNode alloc] initWithNode:n path:@"/Cache"];
}
else if ([[_dir configNode] pluginEnabled:dest])
{
// If they are traversing to the NetInfo, append "/root" to its name.
if ([dest isEqualToString:@"NetInfo"])
{
s = [[NSString alloc] initWithFormat:@"/%@/root",dest];
}
else
{
s = [[NSString alloc] initWithFormat:@"/%@",dest];
}
NS_DURING
n = [_dir findNode:s];
NS_HANDLER
if (!DS_EXCEPTION_STATUS_IS(eNotHandledByThisNode))
[localException raise];
NS_ENDHANDLER
if (n == nil)
{
//We just have a node prefix.
p = [[PathNode alloc] initWithDir:_dir path:s];
}
else
{
p = [[PathNode alloc] initWithNode:n path:s];
}
[s release];
}
else
{
// Invalid destination
p = nil;
}
return [p autorelease];
}
@end

59
dscl/PathItem.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathItem
*/
#import <Foundation/Foundation.h>
#import <DSObjCWrappers/DSoNode.h>
#import "PathItemProtocol.h"
#define DS_EXCEPTION_STATUS_IS(S) ([localException isKindOfClass:[DSoException class]] && [(DSoException*)localException status] == S)
extern BOOL gRawMode;
extern BOOL gURLEncode;
/* printValue()
* Print an attribute value, but url encoded if appropriate
*/
void printValue(NSString *inValue, BOOL hasSpaces);
NSString* stripDSPrefixOffValue(NSString* inValue);
void printAttribute(NSString *key, NSArray *values, NSString *prefixString);
void printPlist(NSString *plistPath, id currentElement);
NSArray* prefixedAttributeKeysWithNode(DSoNode* inNode, NSArray* inKeys);
@interface PathItem : NSObject <PathItemProtocol>
{
}
/*
* Strip the Prefix off of a DS constant.
* Many DS contants have a prefix followed by a colon followed
* by a unique string for that particular constant. This is a simple
* utility function grab just the post-colon string.
*/
- (NSString*)stripDSPrefixOffValue:(NSString*)inValue;
@end

595
dscl/PathItem.m Normal file
View File

@ -0,0 +1,595 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathItem
*/
#import "DSoDirectory.h"
#import "PathItem.h"
#import "NSStringEscPath.h"
BOOL gPlistMode = NO;
@implementation PathItem
// ----------------------------------------------------------------------------
// Initialization / teardown
#pragma mark ******** Initialization / teardown ********
- init
{
[super init];
return self;
}
- (NSString*)stripDSPrefixOffValue:(NSString*)inValue
{
NSRange r = [inValue rangeOfString:@":" options:NSBackwardsSearch];
if (!gRawMode && r.length > 0 && [inValue hasPrefix:@"ds"]
&& ![inValue hasPrefix:@kDSNativeAttrTypePrefix]
&& ![inValue hasPrefix:@kDSNativeRecordTypePrefix])
{
// inValue definitely (with high probability) has a prefix
return [inValue substringFromIndex:r.location+1];
}
else
{
// it doesn't look like a known prefix or we are
// in raw mode, leave it alone
return inValue;
}
}
- (NSString*)description
{
return [[super description] stringByAppendingFormat:@"(%@)",[self name]];
}
// ----------------------------------------------------------------------------
// PathItemProtocol implementations
// It is expected that these will all be implemented as needed
#pragma mark ******** PathItemProtocol implementations ********
- (tDirStatus) appendKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return eDSNoErr;
}
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword authOnly:(BOOL)inAuthOnly
{
return eDSAuthFailed;
}
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword
{
return [self authenticateName:inUsername withPassword:inPassword authOnly:NO];
}
- (tDirStatus) setPassword:(NSArray*)inPassword
{
return eDSAuthFailed;
}
- (NSString*) name
{
return nil;
}
- (PathItem*) cd:(NSString*)dest
{
return nil;
}
- (tDirStatus) createKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return eDSNoErr;
}
- (tDirStatus) deleteItem
{
return eDSNoErr;
}
- (tDirStatus) deleteKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return eDSNoErr;
}
- (tDirStatus) list:(NSString*)inPath key:(NSString*)inKey
{
return eDSNoErr;
}
- (NSDictionary*) getDictionary:(NSArray*)inKeys
{
return nil;
}
- (NSArray*) getList
{
return nil;
}
- (NSArray*) getListWithKeys:(NSArray*)inKeys
{
return nil;
}
- (NSArray*) getPossibleCompletionsFor:(NSString*)inPrefix
{
NSMutableArray* possibleCompletions = nil;
NSArray* currentList = [self getList];
if (currentList != nil)
{
inPrefix = [inPrefix lowercaseString];
possibleCompletions = [NSMutableArray array];
NSEnumerator* listEnum = [currentList objectEnumerator];
NSString* currentItem = nil;
while (currentItem = (NSString*)[listEnum nextObject])
{
if ([[currentItem lowercaseString] hasPrefix:inPrefix])
[possibleCompletions addObject:currentItem];
}
}
return possibleCompletions;
}
- (tDirStatus) mergeKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return eDSNoErr;
}
- (NSString*)nodeName
{
return @"No Node";
}
- (void) printDictionary:(NSDictionary*)inDict withRequestedKeys:(NSArray*)inKeys
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id key = nil;
id keys = nil;
id values = nil;
unsigned long cnt = 0;
unsigned long i = 0;
if (gPlistMode)
{
NSData* data = (NSData*)CFPropertyListCreateXMLData(NULL, inDict);
char* plistStr = NULL;
if (data != nil)
{
plistStr = (char*)calloc(sizeof(char), [data length] + 1);
}
if (plistStr != NULL)
{
strlcpy(plistStr, (char*)[data bytes], [data length]);
printf("%s\n", plistStr);
free(plistStr);
plistStr = NULL;
}
[data release];
data = nil;
}
else
{
keys = [[inDict allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
cnt = [keys count];
for(i = 0; i < cnt; i++)
{
key = [keys objectAtIndex:i];
values = [inDict objectForKey:key];
printAttribute(key, values, nil);
}
if ([inKeys count] > 0)
{
NSEnumerator *keyEnum = nil;
NSString *key = nil;
NSString *attrib = nil;
NSString *attrib2 = nil;
unsigned long cntLimit = 0;
unsigned long i = 0;
NSMutableSet *missingAttributes = [NSMutableSet set];
cntLimit = [inKeys count];
for (i = 0; i < cntLimit; i++)
{
key = [inKeys objectAtIndex:i];
if ([key isEqualToString:@kDSAttributesStandardAll] || [key isEqualToString:@kDSAttributesNativeAll])
{
// don't print an error message about it
continue;
}
if (!([key hasPrefix:@kDSStdAttrTypePrefix] || [key hasPrefix:@kDSNativeAttrTypePrefix]))
{
attrib = [@kDSStdAttrTypePrefix stringByAppendingString:key];
attrib2 = [@kDSNativeAttrTypePrefix stringByAppendingString:key];
if([inDict objectForKey:attrib] == nil && [inDict objectForKey:attrib2] == nil)
[missingAttributes addObject:key];
}
else
{
if([inDict objectForKey:key] == nil)
[missingAttributes addObject:key];
}
}
keyEnum = [missingAttributes objectEnumerator];
while ((key = (NSString*)[keyEnum nextObject]) != nil)
{
fprintf(stderr, "No such key: %s\n", [key UTF8String]);
}
}
}
[pool release];
}
- (tDirStatus) read:(NSArray*)inKeys
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *attribs = nil;
NS_DURING
attribs = [self getDictionary:inKeys];
[self printDictionary:attribs withRequestedKeys:inKeys];
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
[pool release];
return eDSNoErr;
}
- (tDirStatus) readAll:(NSArray*)inKeys
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *list = [self getListWithKeys:inKeys];
NSEnumerator *listEnum = [list objectEnumerator];
NSDictionary *attribs;
NS_DURING
if (gPlistMode)
{
[self printDictionary:(NSDictionary*)list withRequestedKeys:nil];
}
else
{
attribs = (NSDictionary*)[listEnum nextObject];
while (attribs != nil)
{
[self printDictionary:attribs withRequestedKeys:nil];
attribs = (NSDictionary*)[listEnum nextObject];
if (attribs != nil)
{
printf("-\n");
}
}
}
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
[pool release];
return eDSNoErr;
}
- (tDirStatus) read:(NSString*)inPath keys:(NSArray*)inKeys
{
tDirStatus status = eDSNoErr;
if ( ([inPath isEqualToString:@"."]) ||([inPath isEqualToString:@"/"]) )
{
status = [self read:inKeys];
}
else
{
PathItem* destPathItem = [self cd:inPath];
status = (tDirStatus)[destPathItem read:inKeys];
}
return status;
}
- (tDirStatus) read:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *attribs = nil;
NSArray *values = nil;
NSString *value = nil;
NSDictionary *plist = nil;
NSArray *pathElements = nil;
NSEnumerator *pathEnum = nil;
NSString *currentPathElement = nil;
id currentElement = nil;
NSPropertyListFormat format = NSPropertyListXMLFormat_v1_0;
NS_DURING
attribs = [self getDictionary:[NSArray arrayWithObject:inKey]];
if([attribs count] == 0)
{
printf("Invalid key.\n");
NS_VALUERETURN(eDSEmptyAttribute,tDirStatus);
}
NSString *attrib;
if (!([inKey hasPrefix:@kDSStdAttrTypePrefix] || [inKey hasPrefix:@kDSNativeAttrTypePrefix]))
{
attrib = [@kDSStdAttrTypePrefix stringByAppendingString:inKey];
if([attribs objectForKey:attrib] != nil)
inKey = attrib;
attrib = [@kDSNativeAttrTypePrefix stringByAppendingString:inKey];
if([attribs objectForKey:attrib] != nil)
inKey = attrib;
}
values = [attribs objectForKey:inKey];
if([values count] < 1)
{
printf("There is no value for attribute %s\n", [inKey UTF8String]);
NS_VALUERETURN(eDSEmptyAttribute,tDirStatus);
}
else if(index >= [values count])
{
printf("Value index out of range\n");
NS_VALUERETURN(eDSIndexOutOfRange,tDirStatus);
}
else
{
value = [values objectAtIndex:index];
}
plist = [NSPropertyListSerialization propertyListFromData:[value dataUsingEncoding:NSUTF8StringEncoding]
mutabilityOption:NSPropertyListImmutable format:&format errorDescription:nil];
pathElements = [inPlistPath componentsSeparatedByString:@":"];
pathEnum = [pathElements objectEnumerator];
currentElement = plist;
while (currentElement != nil && ((currentPathElement = (NSString*)[pathEnum nextObject]) != nil))
{
if ([currentElement isKindOfClass:[NSDictionary class]])
{
currentElement = [currentElement objectForKey:currentPathElement];
}
else if([currentElement isKindOfClass:[NSArray class]])
{
NSString* intString = [[NSString alloc] initWithFormat:@"%d",[currentPathElement intValue]];
if([currentPathElement intValue] >= [currentElement count] || ![currentPathElement isEqualToString:intString])
{
break; // index out of range
}
else
{
currentElement = [currentElement objectAtIndex:[currentPathElement intValue]];
}
[intString release];
}
else
{
break; // not a valid path
}
}
if (currentPathElement == nil && currentElement != nil)
{
// found something
if ([currentElement isKindOfClass:[NSString class]])
{
printAttribute(inPlistPath, [NSArray arrayWithObject:currentElement], nil);
}
else if ([currentElement isKindOfClass:[NSArray class]] || [currentElement isKindOfClass:[NSDictionary class]])
{
printPlist(inPlistPath, currentElement);
}
else if([currentElement isKindOfClass:[NSNumber class]])
{
printf("%s: %s\n", [inPlistPath UTF8String], [[currentElement stringValue] UTF8String]);
}
else if([currentElement isKindOfClass:[NSDate class]])
{
printf("%s: %s\n", [inPlistPath UTF8String], [[currentElement description] UTF8String]);
}
else if([currentElement isKindOfClass:[NSData class]])
{
NSString *dataString = [[NSString alloc] initWithData:currentElement encoding:NSUTF8StringEncoding];
printf("%s: %s", [inPlistPath UTF8String], [dataString UTF8String]);
[dataString release];
}
else
{
printf("Currently, the class %s is not supported.\n", [[currentElement className] UTF8String]);
}
}
else
{
// bogus path
printf("No such plist path: %s\n", [inPlistPath UTF8String]);
NS_VALUERETURN(eDSUnknownMatchType, tDirStatus);
}
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
[pool release];
return eDSNoErr;
}
- (tDirStatus) read:(NSString*)inKey plistPath:(NSString*)inPlistPath
{
return [self read:inKey atIndex:0 plistPath:inPlistPath];
}
- (tDirStatus) create:(NSString*)inKey plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
printf("You can only use createpl on a record.\n");
return eDSNoErr;
}
- (tDirStatus) delete:(NSString*)inKey plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
printf("You can only use deletepl on a record.\n");
return eDSNoErr;
}
- (tDirStatus) create:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
printf("You can only use createpli on a record.\n");
return eDSNoErr;
}
- (tDirStatus) delete:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
printf("You can only use deletepli on a record.\n");
return eDSNoErr;
}
- (tDirStatus) searchForKey:(NSString*)inKey withValue:(NSString*)inValue matchType:(NSString*)inType
{
printf("You can only search a node or record type path.\n");
return eDSNoErr;
}
- (tDirStatus) changeKey:(NSString*)inKey oldAndNewValues:(NSArray*)inValues
{
return eDSNoErr;
}
- (tDirStatus) changeKey:(NSString*)inKey indexAndNewValue:(NSArray*)inValues
{
return eDSNoErr;
}
@end
NSArray* prefixedAttributeKeysWithNode(DSoNode* inNode, NSArray* inKeys)
{
NSString *attrib = nil;
unsigned long cntLimit = 0;
id key = nil;
NSMutableArray *niceKeys = nil;
unsigned long i = 0;
if ( inKeys == nil )
{
return nil;
}
//here we need to make the keys "nice"
cntLimit = [inKeys count];
niceKeys = [NSMutableArray arrayWithCapacity:cntLimit];
for (i = 0; i < cntLimit; i++)
{
key = [inKeys objectAtIndex:i];
if ([key hasPrefix:@kDSStdAttrTypePrefix] || [key hasPrefix:@kDSNativeAttrTypePrefix]
|| [key isEqualToString:@kDSAttributesStandardAll] || [key isEqualToString:@kDSAttributesNativeAll])
{
attrib = key;
}
else
{
attrib = [@kDSStdAttrTypePrefix stringByAppendingString:key];
if (![[[inNode directory] standardAttributeTypes] containsObject:attrib])
attrib = [@kDSNativeAttrTypePrefix stringByAppendingString:key];
}
[niceKeys addObject:attrib];
}
return niceKeys;
}
void printValue(NSString *inValue, BOOL hasSpaces)
{
if (gURLEncode)
inValue = [inValue urlEncoded];
if (!hasSpaces)
printf(" %s", [inValue UTF8String]);
else
printf("\n %s", [inValue UTF8String]);
}
NSString* stripDSPrefixOffValue(NSString* inValue)
{
NSRange r = [inValue rangeOfString:@":" options:NSBackwardsSearch];
if (!gRawMode && r.length > 0 && [inValue hasPrefix:@"ds"]
&& ![inValue hasPrefix:@kDSNativeAttrTypePrefix]
&& ![inValue hasPrefix:@kDSNativeRecordTypePrefix])
{
// inValue definitely (with high probability) has a prefix
return [inValue substringFromIndex:r.location+1];
}
else
{
// it doesn't look like a known prefix or we are
// in raw mode, leave it alone
return inValue;
}
}
void printAttribute(NSString *key, NSArray *values, NSString *prefixString)
{
BOOL hasSpaces;
int j;
NSString *value = nil;
key = stripDSPrefixOffValue(key);
if(prefixString)
printf("%s", [prefixString UTF8String]);
printf("%s:", [key UTF8String]);
unsigned long cntLimit = [values count];
hasSpaces = NO;
for(j = 0; !hasSpaces && j < cntLimit; j++)
{
hasSpaces = [[values objectAtIndex:j] rangeOfString:@" "].location != NSNotFound;
}
for (j = 0; j < cntLimit; j++)
{
value = [values objectAtIndex:j];
printValue(value, hasSpaces);
}
printf("\n");
}
void printPlist(NSString *plistPath, id currentElement)
{
printf("%s: \n", [plistPath UTF8String]);
NSData *data = [NSPropertyListSerialization dataFromPropertyList:currentElement format:NSPropertyListXMLFormat_v1_0 errorDescription:nil];
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
printf("%s", [dataString UTF8String]);
[dataString release];
}

98
dscl/PathItemProtocol.h Normal file
View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathItemProtocol
*/
#import <DirectoryService/DirectoryService.h>
@class PathItem;
@protocol PathItemProtocol
// Return the name (for interactive display purposes)
// of this path location.
- (NSString*) name;
- (tDirStatus) appendKey:(NSString*)inKey withValues:(NSArray*)inValues;
// verify or authenticate a user to the node for or containing the current path item.
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword authOnly:(BOOL)inAuthOnly;
// Authenticate a user to the node for or containing the current path item.
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword;
- (tDirStatus) setPassword:(NSArray*)inPassword;
// Change directory into path derived from this path.
// ie. a sub-node, or a record type within a node
// or a record within a record type.
- (PathItem*) cd:(NSString*)dest;
- (tDirStatus) createKey:(NSString*)inKey withValues:(NSArray*)inValues;
- (tDirStatus) create:(NSString*)inKey plistPath:(NSString*)inPlistPath values:(NSArray*)inValues;
- (tDirStatus) create:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath values:(NSArray*)inValues;
// Delete the record held by this PathItem.
- (tDirStatus) deleteItem;
- (tDirStatus) deleteKey:(NSString*)inKey withValues:(NSArray*)inValues;
- (tDirStatus) delete:(NSString*)inKey plistPath:(NSString*)inPlistPath values:(NSArray*)inValues;
- (tDirStatus) delete:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath values:(NSArray*)inValues;
// List the contents of the current path
- (NSDictionary*) getDictionary:(NSArray*)inKeys;
- (NSArray*) getList;
- (NSArray*) getListWithKeys:(NSArray*)inKeys;
- (tDirStatus) list:(NSString*)inPath key:(NSString*)inKey;
- (NSArray*) getPossibleCompletionsFor:(NSString*)inPrefix;
- (tDirStatus) mergeKey:(NSString*)inKey withValues:(NSArray*)inValues;
- (tDirStatus) changeKey:(NSString*)inKey oldAndNewValues:(NSArray*)inValues;
- (tDirStatus) changeKey:(NSString*)inKey indexAndNewValue:(NSArray*)inValues;
// Return the name of the node for or containing the current PathItem.
- (NSString*)nodeName;
// Perform a read operation on the current path location.
// ie. for a record, this will display all its attributes.
- (tDirStatus) read:(NSArray*)inKeys;
// Perform a read all operation on the current path location.
// ie. for a record type, this will display all the attributes for all records of that type.
- (tDirStatus) readAll:(NSArray*)inKeys;
- (tDirStatus) read:(NSString*)inPath keys:(NSArray*)inKeys;
- (tDirStatus) read:(NSString*)inKey plistPath:(NSString*)inPlistPath;
- (tDirStatus) read:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath;
// Search for records with a matching key & value pair.
- (tDirStatus) searchForKey:(NSString*)inKey withValue:(NSString*)inValue matchType:(NSString*)inType;
- (void) printDictionary:(NSDictionary*)inDict withRequestedKeys:(NSArray*)inKeys;
@end

106
dscl/PathManager.h Normal file
View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathManager
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirServicesTypes.h>
@interface PathManager : NSObject
{
NSMutableArray *_stack;
NSMutableArray *_stackBackup;
NSMutableArray *_pushdPopdStack;
}
// Open a connection to the local machine.
- initWithLocal;
// Open a conection to a remote machine using DS Proxy.
- initWithHost:(NSString*)hostName user:(NSString*)user password:(NSString*)password;
// Open only a specific node via the local DS service
- initWithNodeEnum:(int)inNodeEnum;
- initWithNodeName:(NSString*)inNodeName;
- initWithNodeName:(NSString*)inNodeName user:(NSString*)inUsername password:(NSString*)inPassword;
// Open the local node via the local DS service (a specialized case of initWithNodeName)
- initWithLocalNode;
- initWithLocalNodeAuthUser:(NSString*)inUsername password:(NSString*)inPassword;
//open the slim version of the DS daemon with only the local node at the file path specified
- initWithLocalPath:(NSString*)filePath;
- (tDirStatus)authenticateUser:(NSString*)inUsername password:(NSString*)inPassword authOnly:(BOOL)inAuthOnly;
- (tDirStatus) setPasswordForUser:(NSString*)inRecordPath withParams:(NSArray*)inParams;
- (void)list:(NSString*)inPath key:(NSString*)inKey;
- (void)cd:(NSString*)dest;
- (void)pushd:(NSString*)dest;
- (void)popd;
- (NSString*)cwd;
- (NSArray*)getCurrentList:(NSString*)inPath;
- (NSArray*)getPossibleCompletionsFor:(NSString*)inPathAndPrefix;
- (tDirStatus)read:(NSString*)inPath keys:(NSArray*)inKeys;
- (tDirStatus)readAll:(NSString*)inPath keys:(NSArray*)inKeys;
- (tDirStatus)read:(NSString*)inPath key:(NSString*)inKey plistPath:(NSString*)inPlistPath;
- (tDirStatus)read:(NSString*)inPath key:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath;
- (tDirStatus)create:(NSString*)inPath key:(NSString*)inKey plistPath:(NSString*)inPlistPath values:(NSArray*)inValues;
- (tDirStatus)create:(NSString*)inPath key:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath values:(NSArray*)inValues;
- (tDirStatus)delete:(NSString*)inPath key:(NSString*)inKey plistPath:(NSString*)inPlistPath values:(NSArray*)inValues;
- (tDirStatus)delete:(NSString*)inPath key:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath values:(NSArray*)inValues;
- (void)diff:(NSString*)inPath1 otherPath:(NSString*)inPath2 keys:(NSArray*)inKeys;
- (tDirStatus)createRecord:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues;
- (tDirStatus)appendToRecord:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues;
- (tDirStatus)mergeToRecord:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues;
- (tDirStatus)deleteInRecord:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues;
- (tDirStatus)deleteRecord:(NSString*)inRecordPath;
- (tDirStatus)changeInRecord:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues;
- (tDirStatus)changeInRecordByIndex:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues;
- (void)searchInPath:(NSString*)inPath forKey:(NSString*)inKey withValue:(NSString*)inValue matchType:(NSString*)inType;
// -----------------------
// Utilities:
// Create a trivial path (a single component, no path delimiter)
// And then cd into that path.
- (tDirStatus)createAndCd:(NSString*)inPath;
// Backup the path stack.
- (void)backupStack;
// Restore the path stack from the backup.
- (void)restoreStack;
- (void)printPushdPopdStack;
// -----------------------
// ATM - PlugInManager needs direct access to the stack
-(NSArray*) stack;
@end

927
dscl/PathManager.m Normal file
View File

@ -0,0 +1,927 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathManager
*/
#import "PathManager.h"
#import "PathDirService.h"
#import "PathNode.h"
#import "PathNodeConfig.h"
#import "PathNodeSearch.h"
#import "DSoDirectory.h"
#import "DSoNode.h"
#import "DSoException.h"
#import "NSStringEscPath.h"
BOOL gRawMode = NO;
@implementation PathManager
// ----------------------------------------------------------------------------
// Initialization / teardown
#pragma mark ******** Initialization / teardown ********
- init
{
[super init];
_stack = [[NSMutableArray alloc] init];
_pushdPopdStack = [[NSMutableArray alloc] init];
_stackBackup = nil;
return self;
}
// Open a connection to the local machine.
- initWithLocal
{
id dirBase;
[self init];
dirBase = [[PathDirService alloc] initWithLocal];
[_stack addObject:dirBase];
[dirBase release];
return self;
}
// Open a conection to a slimmed version of DS daemon that likely ONLY has a local node in it.
- initWithLocalPath:(NSString*)filePath
{
id dirBase;
[self init];
dirBase = [[PathDirService alloc] initWithLocalPath:filePath];
[_stack addObject:dirBase];
[dirBase release];
return self;
}
// Open a conection to a remote machine using DS Proxy.
- initWithHost:(NSString*)hostName user:(NSString*)user password:(NSString*)password
{
id dirBase;
[self init];
dirBase = [[PathDirService alloc] initWithHost:hostName user:user password:password];
[_stack addObject:dirBase];
[dirBase release];
return self;
}
- initWithNodeEnum:(int)inNodeEnum
{
DSoDirectory *dir = nil;
DSoNode *node = nil;
PathNode *dirBase = nil;
[self init];
NS_DURING
dir = [[DSoDirectory alloc] initWithLocal];
node = [dir findNodeViaEnum:inNodeEnum];
dirBase = [[PathNode alloc] initWithNode:node path:@"/"];
[dir release];
NS_HANDLER
[dir release];
[self release];
if ([localException isKindOfClass:[DSoException class]])
{
[dirBase release];
dirBase = nil;
}
else
[localException raise];
NS_ENDHANDLER
if (dirBase)
{
[dirBase setEnableSubNodes:NO];
[_stack addObject:dirBase];
[dirBase release];
return self;
}
else
return nil;
}
- initWithNodeName:(NSString*)inNodeName
{
DSoDirectory *dir = nil;
DSoNode *node = nil;
PathNode *dirBase = nil;
[self init];
NS_DURING
dir = [[DSoDirectory alloc] initWithLocal];
node = [dir findNode:inNodeName];
if ([inNodeName isEqualToString:@"/Search"]
|| [inNodeName isEqualToString:@"/Search/Contacts"]) {
dirBase = [[PathNodeSearch alloc] initWithNode:node path:@"/"];
} else if ([inNodeName isEqualToString:@"/Configure"]) {
dirBase = [[PathNodeConfig alloc] initWithNode:node path:@"/"];
} else {
dirBase = [[PathNode alloc] initWithNode:node path:@"/"];
}
[dir release];
NS_HANDLER
[dir release];
[self release];
if ([localException isKindOfClass:[DSoException class]])
{
[dirBase release];
dirBase = nil;
}
else
[localException raise];
NS_ENDHANDLER
if (dirBase)
{
[dirBase setEnableSubNodes:NO];
[_stack addObject:dirBase];
[dirBase release];
return self;
}
else
return nil;
}
- initWithNodeName:(NSString*)inNodeName user:(NSString*)inUsername password:(NSString*)inPassword
{
PathNode *node = nil;
tDirStatus status = eDSNoErr;
if ([self initWithNodeName:inNodeName] == nil)
return nil;
node = [_stack objectAtIndex:0];
status = [node authenticateName:inUsername withPassword:inPassword];
if (status != eDSNoErr)
{
[_stack release];
[_stackBackup release];
return nil;
}
return self;
}
- initWithLocalNode
{
DSoDirectory *dir = nil;
DSoNode *localNode = nil;
PathNode *dirBase = nil;
[self init];
dir = [[DSoDirectory alloc] initWithLocal];
localNode = [dir localNode];
dirBase = [[PathNode alloc] initWithNode:localNode path:@"/"];
[dirBase setEnableSubNodes:NO];
[_stack addObject:dirBase];
[dirBase release];
[dir release];
return self;
}
- initWithLocalNodeAuthUser:(NSString*)inUsername password:(NSString*)inPassword
{
PathNode *node = nil;
tDirStatus status = eDSNoErr;
[self initWithLocalNode];
node = [_stack objectAtIndex:0];
status = [node authenticateName:inUsername withPassword:inPassword];
if (status != eDSNoErr)
{
[_stack release];
[_stackBackup release];
return nil;
}
return self;
}
- (void)dealloc
{
[_stack release];
[_pushdPopdStack release];
[_stackBackup release]; // just in case.
[super dealloc];
}
// ----------------------------------------------------------------------------
// Command actions
#pragma mark ******** Command Actions ********
- (tDirStatus)authenticateUser:(NSString*)inUsername password:(NSString*)inPassword authOnly:(BOOL)inAuthOnly
{
tDirStatus authStatus = eDSNoErr;
authStatus = [(PathNode*)[_stack lastObject] authenticateName:inUsername withPassword:inPassword authOnly:inAuthOnly];
if (authStatus != eDSNoErr)
{
printf("Authentication for node %s failed. (%d, %s)\n", [[[_stack lastObject] nodeName] UTF8String],
authStatus, [[DSoStatus sharedInstance] cStringForStatus:authStatus]);
}
return authStatus;
}
- (void)list:(NSString*)inPath key:(NSString*)inKey
{
if (inPath == nil)
{
[(PathItem*)[_stack lastObject] list:inPath key:inKey];
}
else
{
[self backupStack];
[self cd:inPath];
[(PathItem*)[_stack lastObject] list:inPath key:inKey];
[self restoreStack];
}
}
- (tDirStatus)createRecord:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
if (inRecordPath == nil || [inRecordPath isEqualToString:@"."] )
{
status = [[_stack lastObject] createKey:inKey withValues:inValues];
}
else
{
[self backupStack];
status = [self createAndCd:inRecordPath];
if (status == eDSNoErr && inKey != nil)
status = [[_stack lastObject] createKey:inKey withValues:inValues];
[self restoreStack];
}
return status;
}
- (tDirStatus)appendToRecord:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
if (inRecordPath == nil || [inRecordPath isEqualToString:@"."] )
{
status = [[_stack lastObject] appendKey:inKey withValues:inValues];
}
else
{
[self backupStack];
[self cd:inRecordPath];
status = [[_stack lastObject] appendKey:inKey withValues:inValues];
[self restoreStack];
}
return status;
}
- (tDirStatus)deleteInRecord:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
if (inRecordPath == nil || [inRecordPath isEqualToString:@"."] )
{
status = [[_stack lastObject] deleteKey:inKey withValues:inValues];
}
else
{
[self backupStack];
[self cd:inRecordPath];
status = [[_stack lastObject] deleteKey:inKey withValues:inValues];
[self restoreStack];
}
return status;
}
- (tDirStatus)deleteRecord:(NSString*)inRecordPath
{
tDirStatus status = eDSNoErr;
if (inRecordPath == nil || [inRecordPath isEqualToString:@"."] )
{
status = [[_stack lastObject] deleteItem];
if (status == eDSNoErr)
{
[_stack removeLastObject];
}
}
else
{
[self backupStack];
[self cd:inRecordPath];
status = [[_stack lastObject] deleteItem];
[self restoreStack];
}
return status;
}
- (tDirStatus)mergeToRecord:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
if (inRecordPath == nil || [inRecordPath isEqualToString:@"."] )
{
status = [[_stack lastObject] mergeKey:inKey withValues:inValues];
}
else
{
[self backupStack];
[self cd:inRecordPath];
status = [[_stack lastObject] mergeKey:inKey withValues:inValues];
[self restoreStack];
}
return status;
}
- (tDirStatus)changeInRecord:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
if (inRecordPath == nil || [inRecordPath isEqualToString:@"."] )
{
status = [[_stack lastObject] changeKey:inKey oldAndNewValues:inValues];
}
else
{
[self backupStack];
[self cd:inRecordPath];
status = [[_stack lastObject] changeKey:inKey oldAndNewValues:inValues];
[self restoreStack];
}
return status;
}
- (tDirStatus)changeInRecordByIndex:(NSString*)inRecordPath key:(NSString*)inKey values:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
if (inRecordPath == nil || [inRecordPath isEqualToString:@"."] )
{
status = [[_stack lastObject] changeKey:inKey indexAndNewValue:inValues];
}
else
{
[self backupStack];
[self cd:inRecordPath];
status = [[_stack lastObject] changeKey:inKey indexAndNewValue:inValues];
[self restoreStack];
}
return status;
}
- (tDirStatus)read:(NSString*)inPath keys:(NSArray*)inKeys
{
tDirStatus status = eDSNoErr;
if (inPath == nil)
{
status = (tDirStatus)[[_stack lastObject] read:inKeys];
}
else
{
[self backupStack];
// Mount records can look like a path, but need to be treated as a
// single entity. Mount records look like: "machine:/path/to/somewhere".
// Need to handle both: "machine:/path/to/somewhere" and
// "/LDAPv3/127.0.0.1/machine:/path/to/somewhere".
NSRange colon = [inPath rangeOfString:@":"];
if (colon.location == NSNotFound)
{
// Regular path (not a mount record).
[self cd:[inPath stringByDeletingLastPathComponent]];
status = (tDirStatus)[[_stack lastObject] read:[inPath lastPathComponent] keys:inKeys];
}
else
{
// Mount record. Split the DS path from the mount record itself.
NSString* mountRecString;
// Find the first slash that preceeds the colon - that will be the
// end of the DS path.
colon.length = colon.location;
colon.location = 0;
NSRange dsPathEnd = [inPath rangeOfString:@"/" options:NSBackwardsSearch range:colon];
if (dsPathEnd.location == NSNotFound)
{
// No DS path preceeding the mount record.
mountRecString = inPath;
}
else
{
// Split the DS path from the mount record.
NSString* dsPath = [inPath substringToIndex:dsPathEnd.location];
mountRecString = [inPath substringFromIndex:dsPathEnd.location + 1];
[self cd:dsPath];
}
status = (tDirStatus)[[_stack lastObject] read:mountRecString keys:inKeys];
}
[self restoreStack];
}
return status;
}
- (tDirStatus)readAll:(NSString*)inPath keys:(NSArray*)inKeys
{
tDirStatus status = eDSNoErr;
if (inPath == nil)
{
status = [[_stack lastObject] readAll:inKeys];
}
else
{
[self backupStack];
[self cd:inPath];
status = [[_stack lastObject] readAll:inKeys];
[self restoreStack];
}
return status;
}
- (tDirStatus)read:(NSString*)inPath key:(NSString*)inKey plistPath:(NSString*)inPlistPath
{
tDirStatus status = eDSNoErr;
if (inPath != nil)
{
[self backupStack];
[self cd:inPath];
status = (tDirStatus)[[_stack lastObject] read:inKey plistPath:inPlistPath];
[self restoreStack];
}
return status;
}
- (tDirStatus)read:(NSString*)inPath key:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath
{
tDirStatus status = eDSNoErr;
if (inPath != nil)
{
[self backupStack];
[self cd:inPath];
status = (tDirStatus)[[_stack lastObject] read:inKey atIndex:index plistPath:inPlistPath];
[self restoreStack];
}
return status;
}
- (tDirStatus)create:(NSString*)inPath key:(NSString*)inKey plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
if (inPath != nil)
{
[self backupStack];
[self cd:inPath];
status = (tDirStatus)[[_stack lastObject] create:inKey plistPath:inPlistPath values:inValues];
[self restoreStack];
}
return status;
}
- (tDirStatus)create:(NSString*)inPath key:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
if (inPath != nil)
{
[self backupStack];
[self cd:inPath];
status = (tDirStatus)[[_stack lastObject] create:inKey atIndex:index plistPath:inPlistPath values:inValues];
[self restoreStack];
}
return status;
}
- (tDirStatus)delete:(NSString*)inPath key:(NSString*)inKey plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
if(inPath != nil)
{
[self backupStack];
[self cd:inPath];
status = (tDirStatus)[[_stack lastObject] delete:inKey plistPath:inPlistPath values:inValues];
[self restoreStack];
}
return status;
}
- (tDirStatus)delete:(NSString*)inPath key:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
if(inPath != nil)
{
[self backupStack];
[self cd:inPath];
status = (tDirStatus)[[_stack lastObject] delete:inKey atIndex:index plistPath:inPlistPath values:inValues];
[self restoreStack];
}
return status;
}
- (void)diff:(NSString*)inPath1 otherPath:(NSString*)inPath2 keys:(NSArray*)inKeys
{
NSDictionary* dict1 = nil;
NSDictionary* dict2 = nil;
if (inPath1 != nil && inPath2 != nil)
{
// should always be true but just in case
[self backupStack];
[self cd:inPath1];
dict1 = [[_stack lastObject] getDictionary:inKeys];
[self restoreStack];
[self backupStack];
[self cd:inPath2];
dict2 = [[_stack lastObject] getDictionary:inKeys];
[self restoreStack];
// Get the union of the keys from both dictionaries and then sort them in to an array
NSArray *keys = [dict1 allKeys];
NSMutableSet *keysSet = [[NSMutableSet alloc] initWithArray:keys];
keys = [dict2 allKeys];
[keysSet addObjectsFromArray:keys];
keys = [keysSet allObjects];
[keys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
NSEnumerator *enumerator = [keys objectEnumerator];
id key;
while(key = [enumerator nextObject])
{
id object1;
id object2;
object1 = [dict1 objectForKey:key];
object2 = [dict2 objectForKey:key];
if(![object2 isEqual:object1])
{
if(object1 != nil)
{
printAttribute(key, object1, @"- ");
}
if(object2 != nil)
{
printAttribute(key, object2, @"+ ");
}
}
}
[keysSet release];
}
}
- (tDirStatus) setPasswordForUser:(NSString*)inRecordPath withParams:(NSArray*)inParams
{
tDirStatus status = eDSNoErr;
if ([inRecordPath isEqualToString:@"."])
{
status = [[_stack lastObject] setPassword:inParams];
}
else
{
[self backupStack];
[self cd:inRecordPath];
status = [[_stack lastObject] setPassword:inParams];
[self restoreStack];
}
return status;
}
- (tDirStatus)createAndCd:(NSString*)inPath
{
NSArray *pathComponents = [inPath unescapedPathComponents];
NSString *pathComp = nil;
unsigned int i = 0;
tDirStatus status = eDSNoErr;
int cntLimit = 0;
if ([[pathComponents objectAtIndex:0] isEqualToString:@"/"])
i = 1;
cntLimit = [pathComponents count];
for(; i < cntLimit; i++)
{
pathComp = [pathComponents objectAtIndex:i];
status = [[_stack lastObject] createKey:pathComp withValues:nil];
if (status == eDSRecordAlreadyExists)
status = eDSNoErr;
else if (status != eDSNoErr)
break;
[self cd: [pathComp escapedString]];
}
return status;
}
- (void)cd:(NSString*)dest
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
PathItem *p = nil;
NSArray *pathElements = nil;
NSMutableArray *newPath = [[NSMutableArray alloc] initWithArray:_stack];
NSString *s = nil;
int i = 0;
int start = 0;
BOOL failure = NO;
pathElements = [dest unescapedPathComponents];
if ( [pathElements count] )
{
// If the first element is empty, then we have specified an absolute path.
// So strip the new stack down to the base element.
if ([[pathElements objectAtIndex:0] isEqualToString:@"/"])
{
if ( [_stack count] > 1)
{
NSRange r = NSMakeRange(1,[_stack count] - 1);
[newPath removeObjectsInRange:r];
}
start = 1;
}
else
{
start = 0;
}
// Now iterate through the elements and successively 'cd' into each one.
NS_DURING
int cntLimit = [pathElements count];
for (i = start; i < cntLimit && !failure; i++)
{
s = [pathElements objectAtIndex:i];
// If it is "..", then go up a path by removing the item from the stack.
if ([s isEqualToString:@".."])
{
// If they have already reached the top, then don't go any farther.
if ([newPath count] > 1)
[newPath removeLastObject];
}
// If it is empty or they have specifed the extraneous "root" after "/NetInfo", then just skip this element.
else if ([s length] == 0 || [s isEqualToString:@"."] ||
([s isEqualToString:@"root"] && [[[newPath lastObject] name] isEqualToString:@"NetInfo/root"]) )
{
continue;
}
// Otherwise, add the next item down.
else
{
// don't do anything to s, PathItem takes unescaped strings only
p = [(PathItem*)[newPath lastObject] cd:s];
if (p != nil)
[newPath addObject:p];
else
failure = YES;
}
}
NS_HANDLER
// If there was an exception (such as too many "cd .." causing the newPath
// Array to empty, then fail the whole command.
failure = YES;
NS_ENDHANDLER
if (!failure)
{
// Success! replace the _stack variable with our new, updated copy.
[_stack release];
_stack = newPath;
}
else
{
// Failure, release the copy, pool, and raise error.
[newPath release];
[pool release];
[NSException raise:@"DSCL" format:@"Invalid Path"];
}
}
[pool release];
}
- (void)pushd:(NSString*)dest
{
if (dest == nil)
{
NSMutableArray *swapStack = nil;
if ([_pushdPopdStack count] == 0)
[NSException raise:@"DSCL" format:@"no other directory"];
// No new destination was specified. Swap the current path and the top path:
swapStack = [[_pushdPopdStack lastObject] retain];
[_pushdPopdStack removeLastObject];
[_pushdPopdStack addObject:_stack];
[_stack release];
_stack = swapStack;
}
else
{
[_pushdPopdStack addObject:_stack];
NS_DURING
[self cd:dest];
NS_HANDLER
[_pushdPopdStack removeLastObject];
[localException raise];
NS_ENDHANDLER
}
[self printPushdPopdStack];
}
- (void)popd
{
if ([_pushdPopdStack count] == 0)
[NSException raise:@"DSCL" format:@"Directory stack empty."];
[_stack release];
_stack = [[_pushdPopdStack lastObject] retain];
[_pushdPopdStack removeLastObject];
[self printPushdPopdStack];
}
- (NSString*)cwd
{
NSString *outCwd = nil;
NSEnumerator *stackEnum = [_stack objectEnumerator];
NSMutableArray *pathArray = [NSMutableArray array];
PathItem *pathItem;
// loop over all of them and add names
while( pathItem = [stackEnum nextObject] )
{
[pathArray addObject:[pathItem name]];
}
if( [pathArray count] == 0 ) {
outCwd = @"/";
} else {
outCwd = [NSString escapablePathFromArray: pathArray];
}
return outCwd;
}
- (NSArray*)getCurrentList:(NSString*)inPath
{
NSArray *retValue = nil;
NSArray *inPathComponents = [inPath unescapedPathComponents];
// First drop the last item on the inPath...
// (Later we may pick it back up and pass it to the getList methods)
if ([inPathComponents count] > 1)
inPath = [NSString escapablePathFromArray: [inPathComponents subarrayWithRange: NSMakeRange(0, [inPathComponents count] - 1)]];
else
inPath = nil;
if (inPath == nil)
{
retValue = [[_stack lastObject] getList];
}
else
{
[self backupStack];
[self cd:[inPath escapedString]];
retValue = [[_stack lastObject] getList];
[self restoreStack];
}
return retValue;
}
- (NSArray*)getPossibleCompletionsFor:(NSString*)inPathAndPrefix
{
NSArray *retValue = nil;
NSArray *pathComponents = [inPathAndPrefix unescapedPathComponents];
NSString *prefix = [[pathComponents lastObject] lowercaseString];
unsigned int pathCount = [pathComponents count];
if (pathCount > 1)
{
NSArray *tempArray = [pathComponents subarrayWithRange: NSMakeRange(0, pathCount - 1)];
[self backupStack];
[self cd: [NSString escapablePathFromArray: tempArray]];
retValue = [[_stack lastObject] getPossibleCompletionsFor: prefix];
[self restoreStack];
}
else if( prefix )
{
retValue = [[_stack lastObject] getPossibleCompletionsFor: prefix];
}
return retValue;
}
- (void)searchInPath:(NSString*)inPath forKey:(NSString*)inKey withValue:(NSString*)inValue matchType:(NSString*)inType
{
BOOL isCurrentDir = [inPath isEqualToString:@"."];
if (!isCurrentDir)
{
[self backupStack];
[self cd:inPath];
}
[[_stack lastObject] searchForKey:inKey withValue:inValue matchType:inType];
if (!isCurrentDir)
[self restoreStack];
}
// ----------------------------------------------------------------------------
// Utility methods
#pragma mark ******** Utility methods ********
- (void)backupStack
{
_stackBackup = [[NSMutableArray alloc] initWithArray:_stack];
}
- (void)restoreStack
{
if (_stackBackup != nil)
{
[_stack release];
_stack = _stackBackup;
_stackBackup = nil;
}
}
- (void)printPushdPopdStack
{
int i = 0;
int j = 0;
int cnt = 0;
printf("%s ", [[[self cwd] unescapedString] UTF8String]);
cnt = [_pushdPopdStack count];
for (i=cnt-1; i >= 0 ; i--)
{
NSArray *pathStack = [_pushdPopdStack objectAtIndex:i];
int cntLimit = [pathStack count];
if (cntLimit == 1)
printf("/");
else
{
for (j=1; j < cntLimit; j++)
{
NSString *pathItemName = [[pathStack objectAtIndex:j] name];
printf("/%s",[pathItemName UTF8String]);
}
}
printf(" ");
}
printf("\n");
}
-(NSArray*) stack
{
// ATM - give PlugInManager access to the stack
return _stack;
}
@end

67
dscl/PathNode.h Normal file
View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathNode
*/
#import <Foundation/Foundation.h>
#import <DirectoryService/DirServicesTypes.h>
#import "PathItem.h"
@class DSoDirectory,DSoNode;
@interface PathNode : PathItem
{
NSString *_pathName;
DSoDirectory *_dir;
DSoNode *_node;
BOOL _enableSubNodes;
}
// Initialize with a Directory object, and a pathname of the node (or node prefix)
- initWithDir:(DSoDirectory*)inDir path:(NSString*)inPath;
// Initialize with a Node object and its intended pathname.
- initWithNode:(DSoNode*)inNode path:(NSString*)inPath;
// Get a list of the sub-node, i.e. at list of nodes
// whose names begin with the name of this node.
- (NSArray*)getSubnodeList;
// Get a list of Record types that this node contains.
- (NSArray*)getRecordList;
// Create a new sub-node path object derived from this node object.
- (PathItem*)cdNode:(NSString*)dest;
// Create a new record type path object derived from this node object.
- (PathItem*)cdRecordType:(NSString*)dest;
- (BOOL)enableSubNodes;
- (void)setEnableSubNodes:(BOOL)value;
// ATM - PlugInManager needs access to node
-(DSoNode*) node;
@end

528
dscl/PathNode.m Normal file
View File

@ -0,0 +1,528 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathNode
*/
#import "PathNode.h"
#import "PathRecordType.h"
#import "DSoDirectory.h"
#import "DSoNode.h"
#import "DSoException.h"
#import <DirectoryService/DirServicesConst.h>
static NSString *kNSStdRecordTypePrefix = @"dsRecTypeStandard:";
static NSString *kNSNativeRecordTypePrefix = @"dsRecTypeNative:";
static NSString *kNSStdAttrTypePrefix = @"dsAttrTypeStandard:";
static NSString *kNSNativeAttrTypePrefix = @"dsAttrTypeNative:";
@interface PathNode (PathNodePrivate)
// Print the search results from the searchForKey:withValue:matchType: routine.
- (void)printSearch:(NSString*)inKey Results:(NSArray*)inResults;
@end
@implementation PathNode
// ----------------------------------------------------------------------------
// Initialization / teardown
#pragma mark ******** Initialization / teardown ********
- init
{
[super init];
_pathName = nil;
_dir = nil;
_node = nil;
_enableSubNodes = YES;
return self;
}
- initWithDir:(DSoDirectory*)inDir path:(NSString*)inPath
{
[self init];
_pathName = inPath;
[_pathName retain];
_dir = inDir;
return self;
}
- initWithNode:(DSoNode*)inNode path:(NSString*)inPath
{
[self init];
_pathName = inPath;
[_pathName retain];
_node = [inNode retain];
_dir = [_node directory];
return self;
}
- (void)dealloc
{
[_pathName release];
[_node release];
[super dealloc];
}
// ----------------------------------------------------------------------------
// PathItemProtocol implementations
#pragma mark ******** PathItemProtocol implementations ********
- (NSString*)name
{
NSAutoreleasePool *pool;
NSString *name = nil;
if ([_pathName isEqualToString:@"/NetInfo/root"])
return @"NetInfo/root";
else
{
pool = [[NSAutoreleasePool alloc] init];
name = [[[_pathName componentsSeparatedByString:@"/"] lastObject] retain];
[pool release];
return [name autorelease];
}
}
- (NSArray*)getList
{
NSArray *recordList = [self getRecordList];
NSArray *subnodeList = nil;
if (_enableSubNodes)
subnodeList = [self getSubnodeList];
if (recordList != nil && !gRawMode && [recordList count] > 0)
{
NSMutableArray *newList = [NSMutableArray arrayWithCapacity:[recordList count]];
unsigned int i = 0;
unsigned int cntLimit = [recordList count];
for (i = 0; i < cntLimit; i++)
[newList addObject:[self stripDSPrefixOffValue:[recordList objectAtIndex:i]]];
recordList = newList;
}
if (recordList != nil && subnodeList != nil
&& [recordList count] > 0 && [subnodeList count] > 0)
return [subnodeList arrayByAddingObjectsFromArray:recordList];
else if (recordList != nil && [recordList count] > 0)
return recordList;
else if (subnodeList != nil && [subnodeList count] > 0)
return subnodeList;
else
return nil;
}
- (tDirStatus)list:(NSString*)inPath key:(NSString*)inKey
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *recordList = [self getRecordList];
NSString *recType = nil;
unsigned long i = 0;
unsigned long sCount = 0;
unsigned long rCount = 0;
[super list:inPath key:(NSString*)inKey];
if (_enableSubNodes)
{
NSArray *subnodeList = [self getSubnodeList];
sCount = [subnodeList count];
for (i = 0; i < sCount; i++)
{
printf("%s\n", [[subnodeList objectAtIndex:i] UTF8String]);
}
}
rCount = [recordList count];
if (sCount && rCount)
printf ("\n");
for (i = 0; i < rCount ; i++)
{
recType = [self stripDSPrefixOffValue:[recordList objectAtIndex:i]];
printf("%s\n", [recType UTF8String]);
}
[pool release];
return eDSNoErr;
}
- (PathItem*) cd:(NSString*)dest
{
PathItem *nextItem = nil;
// The following checks are in order of fastest check.
// If the dest empty, abort.
if (dest == nil || [dest length] == 0)
{
return nil;
}
// If the destination hase a fully qualified record type, then use it;
// else look for existing standard, then native types.
else if ([dest hasPrefix:kNSStdRecordTypePrefix] || [dest hasPrefix:kNSNativeRecordTypePrefix])
{
nextItem = [[PathRecordType alloc] initWithNode:_node recordType:dest];
}
// try using it as the name of a child of this node, but only if
// configured to do so.
else if (_enableSubNodes)
{
NSString *fullPathName = [NSString stringWithFormat:@"%@/%@",_pathName,dest];
DSoNode *n;
NS_DURING
n = [_dir findNode:fullPathName matchType:eDSExact useFirst:NO]; // more efficient for non-existant names
nextItem = [[PathNode alloc] initWithNode:n path:fullPathName];
NS_HANDLER
if (!DS_EXCEPTION_STATUS_IS(eDSUnknownNodeName) &&
!DS_EXCEPTION_STATUS_IS(eDSNodeNotFound))
{ // Some unexpected exception
[localException raise];
}
NS_ENDHANDLER
}
// Try looking for a standard or native type by the name of the destination.
if (nextItem == nil) // I would have used else here, but the Exception handlers were causing problems.
{
NSString *stdDest = [kNSStdRecordTypePrefix stringByAppendingString:dest];
NSString *nativeDest = [kNSNativeRecordTypePrefix stringByAppendingString:dest];
NS_DURING
if ([_node hasRecordsOfType:[stdDest UTF8String]])
nextItem = [[PathRecordType alloc] initWithNode:_node recordType:stdDest];
else if ([_node hasRecordsOfType:[nativeDest UTF8String]])
nextItem = [[PathRecordType alloc] initWithNode:_node recordType:nativeDest];
NS_HANDLER
NS_ENDHANDLER
}
// Check with case-insensitive
if (nextItem == nil) {
NSString *stdDest = [kNSStdRecordTypePrefix stringByAppendingString:dest];
NSString *nativeDest = [kNSNativeRecordTypePrefix stringByAppendingString:dest];
NS_DURING
NSArray *recTypes = [_node getAttribute:kDSNAttrRecordType];
for (NSString *string in recTypes) {
if (([string caseInsensitiveCompare:stdDest] == NSOrderedSame) ||
([string caseInsensitiveCompare:nativeDest] == NSOrderedSame)) {
nextItem = [[PathRecordType alloc] initWithNode:_node recordType:string];
break;
}
}
NS_HANDLER
NS_ENDHANDLER
}
// if all else fails try to open the name as is
if (nextItem == nil && _enableSubNodes)
{
NSString *fullPathName = [NSString stringWithFormat:@"%@/%@",_pathName,dest];
DSoNode *n;
NS_DURING
n = [_dir findNode:fullPathName matchType:eDSExact useFirst:YES]; // just open the name as provided
nextItem = [[PathNode alloc] initWithNode:n path:fullPathName];
NS_HANDLER
if (!DS_EXCEPTION_STATUS_IS(eDSUnknownNodeName) &&
!DS_EXCEPTION_STATUS_IS(eDSNodeNotFound))
{ // Some unexpected exception
[localException raise];
}
NS_ENDHANDLER
}
return [nextItem autorelease];
}
- (NSDictionary *) getDictionary:(NSArray *)inKeys
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *attribs = nil;
id key = nil;
NSString *attrib = nil;
unsigned long i = 0;
NS_DURING
if (inKeys == nil || [inKeys count] == 0)
{
attribs = [_node getAllAttributes];
}
else
{
NSMutableDictionary* mutableAttribs = [NSMutableDictionary dictionary];
unsigned long cntLimit = 0;
attribs = [_node getAllAttributes];
cntLimit = [inKeys count];
for (i = 0; i < cntLimit; i++)
{
key = [inKeys objectAtIndex:i];
if ([key hasPrefix:@kDSStdAttrTypePrefix] || [key hasPrefix:@kDSNativeAttrTypePrefix])
{
attrib = key;
if([attribs objectForKey:attrib] != nil)
[mutableAttribs setObject:[attribs objectForKey:attrib] forKey:attrib];
}
else if ([key isEqualToString:@kDSAttributesStandardAll])
{
for (NSString *attribKey in [attribs allKeys]) {
if ([attribKey hasPrefix:@kDSStdAttrTypePrefix]) {
[mutableAttribs setObject:[attribs objectForKey:attribKey] forKey:attribKey];
}
}
}
else if ([key isEqualToString:@kDSAttributesNativeAll])
{
for (NSString *attribKey in [attribs allKeys]) {
if ([attribKey hasPrefix:@kDSNativeAttrTypePrefix]) {
[mutableAttribs setObject:[attribs objectForKey:attribKey] forKey:attribKey];
}
}
}
else
{
attrib = [@kDSStdAttrTypePrefix stringByAppendingString:key];
if([attribs objectForKey:attrib] != nil)
[mutableAttribs setObject:[attribs objectForKey:attrib] forKey:attrib];
attrib = [@kDSNativeAttrTypePrefix stringByAppendingString:key];
if([attribs objectForKey:attrib] != nil)
[mutableAttribs setObject:[attribs objectForKey:attrib] forKey:attrib];
}
}
attribs = (NSDictionary *)mutableAttribs;
}
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
[attribs retain];
[pool release];
return [attribs autorelease];
}
- (tDirStatus) searchForKey:(NSString*)inKey withValue:(NSString*)inValue matchType:(NSString*)inType
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *searchResults = nil;
NSArray *recordTypes = [_node findRecordTypes];
NSMutableArray *attribList = [NSMutableArray arrayWithObjects:
@kDSNAttrRecordName,
kDSOAttrRecordType, nil];
NSString *key = nil;
tDirPatternMatch type = eDSExact;
NS_DURING
if ([inKey hasPrefix:kNSStdAttrTypePrefix] || [inKey hasPrefix:kNSNativeAttrTypePrefix])
{
key = inKey;
}
else
{
key = [kNSStdAttrTypePrefix stringByAppendingString:inKey];
if (![[[_node directory] standardAttributeTypes] containsObject:key])
key = [kNSNativeAttrTypePrefix stringByAppendingString:inKey];
}
[attribList addObject:key];
searchResults = [_node findRecordsOfTypes:recordTypes withAttribute:[key UTF8String]
value:inValue matchType:type retrieveAttributes:attribList];
[self printSearch:key Results:searchResults];
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
[pool release];
return eDSNoErr;
}
// ----------------------------------------------------------------------------
// Utility functions
#pragma mark ******** Utility functions ********
- (PathItem*)cdNode:(NSString*)dest
{
DSoNode *n = [_dir findNode:dest];
PathNode *p = nil;
if (n == nil)
{
//We just have a node prefix.
p = [[PathNode alloc] initWithDir:_dir path:dest];
}
else
{
p = [[PathNode alloc] initWithNode:n path:dest];
}
return [p autorelease];
}
- (PathItem*)cdRecordType:(NSString*)destType
{
PathRecordType *p = [[PathRecordType alloc] initWithNode:_node recordType:destType];
return [p autorelease];
}
- (NSArray*)getSubnodeList
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *findResults = nil;
NSArray *findResults2 = nil;
NSArray *nameComponents = nil;
NSArray *list = nil;
NSMutableSet *set = [NSMutableSet set];
NSString *name = nil;
unsigned long i = 0;
unsigned long count = 0;
int currentComponentCount = 0;
int iCompCount = 0;
NS_DURING
findResults = [_dir findNodeNames:_pathName matchType:eDSStartsWith];
NS_HANDLER
if (!DS_EXCEPTION_STATUS_IS(eDSUnknownNodeName)
&& !DS_EXCEPTION_STATUS_IS(eDSNodeNotFound))
{
// Clean up memory from the autorelease pool & the pool itself
// before sending the exception on up.
// This also means we have to transfer the localException from our local
// pool to the containing pool, else it is lost.
[localException retain];
[pool release];
[[localException autorelease] raise];
}
NS_ENDHANDLER
NS_DURING
if (_node != nil)
{
findResults2 = [_node getAttribute:kDSNAttrSubNodes];
if (findResults2 != nil)
findResults = [findResults arrayByAddingObjectsFromArray:findResults2];
}
NS_HANDLER
// ignore exceptions here
NS_ENDHANDLER
count = [findResults count];
// examine results to find only immediate child nodes.
// We do this by comparing the number of components in the node names
// using "/" as the component divider.
currentComponentCount = [[_pathName componentsSeparatedByString:@"/"] count];
for (i = 0; i < count; i++)
{
name = [findResults objectAtIndex:i];
nameComponents = [name componentsSeparatedByString:@"/"];
iCompCount = [nameComponents count];
if (iCompCount == currentComponentCount + 1)
[set addObject:[nameComponents lastObject]];
}
list = [[set allObjects] retain];
[pool release];
return [list autorelease];
}
- (NSArray*)getRecordList
{
if (_node != nil)
return [_node findRecordTypes];
else
return [NSArray array];
}
// ----------------------------------------------------------------------------
// Accessor functions
#pragma mark ******** Accessor functions ********
- (BOOL)enableSubNodes
{
return _enableSubNodes;
}
- (void)setEnableSubNodes:(BOOL)value
{
_enableSubNodes = value;
}
- (NSString*)nodeName
{
return [_node getName];
}
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword authOnly:(BOOL)inAuthOnly
{
return [_node authenticateName:inUsername withPassword:inPassword authOnly:inAuthOnly];
}
-(DSoNode*) node
{
// ATM - PlugInManager needs access to node instance
return _node;
}
@end
// ----------------------------------------------------------------------------
// Private functions
#pragma mark ******** Private functions ********
@implementation PathNode (PathNodePrivate)
/* Used by searchForKey:withValue:matchType: */
- (void)printSearch:(NSString*)inKey Results:(NSArray*)inResults
{
NSEnumerator *resultEnumerator = [inResults objectEnumerator];
NSString *kNSAttrRecordName = @kDSNAttrRecordName;
NSDictionary *d = nil;
while(d = [resultEnumerator nextObject])
{
printf("%s/%s\t\t%s = %s\n",[[self stripDSPrefixOffValue:[d objectForKey:kDSOAttrRecordType]] UTF8String],
[[[d objectForKey:kNSAttrRecordName] objectAtIndex:0] UTF8String],[[self stripDSPrefixOffValue:inKey] UTF8String],[[[d objectForKey:inKey] description] UTF8String]);
}
}
@end

38
dscl/PathNodeConfig.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathNodeConfig
*/
#import <Foundation/Foundation.h>
#import "PathNode.h"
@interface PathNodeConfig : PathNode
{
AuthorizationExternalForm _authExternalForm;
BOOL _haveRights;
}
@end

166
dscl/PathNodeConfig.m Normal file
View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathNodeConfig
*/
#import <DirectoryService/DirectoryService.h>
#import <DSObjCWrappers/DSObjCWrappers.h>
#import <opendirectory/odutils.h>
#import "PathNodeConfig.h"
#import "PathRecordTypeConfig.h"
@interface PathNodeConfig (Private)
- (void) _destroyRights;
@end
@implementation PathNodeConfig (Private)
- (void)_destroyRights
{
// free _authExternalForm
if (_haveRights) {
[_node customCall:eODCustomCallConfigureDestroyAuthRef
withAuthorization:&_authExternalForm];
}
}
@end
@implementation PathNodeConfig
- (id)init
{
[super init];
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- (id)initWithDir:(DSoDirectory*)inDir path:(NSString*)inPath
{
[super initWithDir:inDir path:inPath];
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- (id)initWithNode:(DSoNode*)inNode path:(NSString*)inPath
{
[super initWithNode:inNode path:inPath];
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- (void)dealloc
{
[self _destroyRights];
[super dealloc];
}
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword authOnly:(BOOL)inAuthOnly
{
NSAutoreleasePool* pool = [NSAutoreleasePool new];
DSoSearchNode* searchNode = [[_node directory] searchNode];
DSoUser* user = nil;
tDirStatus status = eDSAuthFailed;
NSMutableData* outputData = nil;
NS_DURING
user = [searchNode findUser:inUsername];
if (user != nil) {
status = [[user node] authenticateName:inUsername withPassword:inPassword authOnly:YES];
if (status == eDSNoErr && inAuthOnly == NO) {
outputData = [NSMutableData dataWithLength:sizeof(AuthorizationExternalForm)];
status = [_node customCall:eODCustomCallConfigureGetAuthRef
sendItems:[NSArray arrayWithObjects:inUsername,inPassword,nil]
outputData:outputData];
if (status == eDSNoErr && [outputData length] >= sizeof( AuthorizationExternalForm ) )
{
[outputData getBytes:&_authExternalForm length:sizeof( AuthorizationExternalForm )];
_haveRights = YES;
}
}
}
NS_HANDLER
NS_ENDHANDLER
[pool release];
return status;
}
- (PathItem*) cd:(NSString*)dest
{
PathRecordTypeConfig *nextItem = nil;
// The following checks are in order of fastest check.
// If the dest empty, abort.
if (dest == nil || [dest length] == 0)
{
return nil;
}
// If the destination has a fully qualified record type, then use it;
// else look for existing standard, then native types.
else if ([dest hasPrefix:@"dsConfigType"] || [dest hasPrefix:@kDSStdRecordTypePrefix])
{
nextItem = [[PathRecordTypeConfig alloc] initWithNode:_node recordType:dest];
}
// Try looking for a standard or native type by the name of the destination.
else
{
NSArray *recordTypeList = [self getRecordList];
NSString *cfgDest = [NSString stringWithFormat:@"dsConfigType::%@",dest];
NSString *stdDest = [@kDSStdRecordTypePrefix stringByAppendingString:dest];
if ([recordTypeList containsObject:stdDest])
dest = stdDest;
else if ([recordTypeList containsObject:cfgDest])
dest = cfgDest;
else
dest = nil;
if (dest != nil)
{
// The destination is either a fully qualified record type, or an existing type,
// the next item is a record type node.
nextItem = [[PathRecordTypeConfig alloc] initWithNode:_node recordType:dest];
}
else
{
return nil;
}
}
[nextItem setAuthExternalForm:&_authExternalForm];
return [nextItem autorelease];
}
@end

52
dscl/PathNodeSearch.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathNodeConfig
*/
#import <Foundation/Foundation.h>
#import <Security/Security.h>
#import "PathNode.h"
#import "PathRecord.h"
@class DSoNodeConfig;
@interface PathNodeSearch : PathNode
{
AuthorizationExternalForm _authExternalForm;
BOOL _haveRights;
DSoNodeConfig* _configNode;
tDirPatternMatch _type;
}
- initWithNode:(DSoNode*)inNode path:(NSString*)inPath type:(tDirPatternMatch)val;
- (tDirStatus) modify:(tAttrCAM)inAction withKey:(NSString*)inKey withValues:(NSArray*)inValues;
- (tDirStatus)setSearchPolicy:(NSString*)newPolicy;
- (tDirStatus)setCustomSearchPath:(NSArray*)nodeList;
- (BOOL)nodeNameIsValid:(NSString*)nodeName;
@end

400
dscl/PathNodeSearch.m Normal file
View File

@ -0,0 +1,400 @@
/*
* Copyright (c) 2003-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathNodeConfig
*/
#import <DirectoryService/DirectoryService.h>
#import <DSObjCWrappers/DSObjCWrappers.h>
#import <opendirectory/odutils.h>
#import <DirectoryService/DirServicesConstPriv.h>
#import "PathNodeSearch.h"
@interface PathNodeSearch (Private)
- (DSoNodeConfig*)configNode;
- (void) _destroyRights;
@end
@implementation PathNodeSearch (Private)
- (DSoNodeConfig*)configNode
{
if (_configNode == nil) {
_configNode = [[[_node directory] findNodeViaEnum:eDSConfigNodeName] retain];
}
return _configNode;
}
- (void)_destroyRights
{
// free _authExternalForm
if (_haveRights) {
[[self configNode] customCall:eODCustomCallConfigureDestroyAuthRef
withAuthorization:&_authExternalForm];
}
}
@end
@implementation PathNodeSearch
- init
{
[super init];
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- initWithDir:(DSoDirectory*)inDir path:(NSString*)inPath
{
[super initWithDir:inDir path:inPath];
if ( [inPath isEqualTo: @"/Search"] == YES ) {
_type = eDSSearchNodeName;
}
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- initWithNode:(DSoNode*)inNode path:(NSString*)inPath
{
[super initWithNode:inNode path:inPath];
if ( [[inNode getName] isEqualTo: @"/Search"] == YES || [inPath isEqualTo: @"/Search"] == YES ) {
_type = eDSSearchNodeName;
}
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- initWithNode:(DSoNode*)inNode path:(NSString*)inPath type:(tDirPatternMatch)val
{
[super initWithNode:inNode path:inPath];
if ( [[inNode getName] isEqualTo: @"/Search"] == YES || [inPath isEqualTo: @"/Search"] ) {
_type = eDSSearchNodeName;
}
else {
_type = val;
}
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- (void)dealloc
{
[self _destroyRights];
[_configNode release];
_configNode = nil;
[super dealloc];
}
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword authOnly:(BOOL)inAuthOnly
{
NSAutoreleasePool* pool = [NSAutoreleasePool new];
DSoUser* user = nil;
tDirStatus status = eDSAuthFailed;
NSMutableData* outputData = nil;
NS_DURING
user = [_node findUser:inUsername];
if (user != nil) {
status = [[user node] authenticateName:inUsername withPassword:inPassword authOnly:YES];
if (status == eDSNoErr && inAuthOnly == NO) {
outputData = [NSMutableData dataWithLength:sizeof(AuthorizationExternalForm)];
status = [[self configNode] customCall:eODCustomCallConfigureGetAuthRef
sendItems:[NSArray arrayWithObjects:inUsername,inPassword,nil]
outputData:outputData];
if (status == eDSNoErr && [outputData length] >= sizeof( AuthorizationExternalForm ) )
{
[outputData getBytes:&_authExternalForm length:sizeof( AuthorizationExternalForm )];
_haveRights = YES;
}
}
}
NS_HANDLER
NS_ENDHANDLER
[pool release];
return status;
}
- (tDirStatus) createKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return [self modify:ATTR_CREATE withKey:inKey withValues:inValues];
}
- (tDirStatus) deleteItem
{
return eDSReadOnly;
}
- (tDirStatus) deleteKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return [self modify:ATTR_DELETE withKey:inKey withValues:inValues];
}
- (tDirStatus) appendKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return [self modify:ATTR_APPEND withKey:inKey withValues:inValues];
}
- (tDirStatus) mergeKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return [self modify:ATTR_MERGE withKey:inKey withValues:inValues];
}
- (tDirStatus) changeKey:(NSString*)inKey oldAndNewValues:(NSArray*)inValues
{
return [self modify:ATTR_CHANGE withKey:inKey withValues:inValues];
}
- (tDirStatus) changeKey:(NSString*)inKey indexAndNewValue:(NSArray*)inValues
{
return [self modify:ATTR_CHANGE_INDEX withKey:inKey withValues:inValues];
}
// ----------------------------------------------------------------------------
// Utility methods
#pragma mark ******** Utility methods ********
- (tDirStatus) modify:(tAttrCAM)inAction withKey:(NSString*)inKey withValues:(NSArray*)inValues
{
tDirStatus nError = eDSReadOnly;
tDirStatus firstError = eDSNoErr;
NSUInteger index = NSNotFound;
NSEnumerator *objEnum = nil;
NSString *oldValue = nil;
NSString *newValue = nil;
NSArray *oldValues = nil;
NSMutableArray *newValues = nil;
BOOL changeSearchPath;
if ([inKey isEqualToString:@kDS1AttrSearchPolicy]
|| [[@kDSStdAttrTypePrefix stringByAppendingString:inKey] isEqualToString:@kDS1AttrSearchPolicy])
{
changeSearchPath = NO;
}
else if ([inKey isEqualToString:@kDSNAttrCSPSearchPath]
|| [[@kDSStdAttrTypePrefix stringByAppendingString:inKey] isEqualToString:@kDSNAttrCSPSearchPath])
{
changeSearchPath = YES;
}
else
{
return eDSReadOnly;
}
NS_DURING
switch (inAction)
{
case ATTR_CREATE:
if (!changeSearchPath && [inValues count] == 1) {
nError = [self setSearchPolicy:[inValues lastObject]];
} else if (changeSearchPath) {
if ([inValues count] >= 1
&& [[_node getAttributeFirstValue:kDSNAttrCSPSearchPath]
isEqual:[inValues objectAtIndex:0]]) {
objEnum = [inValues objectEnumerator];
while (newValue = [objEnum nextObject]) {
if (![self nodeNameIsValid:newValue]) {
nError = eDSNodeNotFound;
break;
}
}
if (nError != eDSNodeNotFound) {
nError = [self setCustomSearchPath:inValues];
}
}
}
break;
case ATTR_APPEND:
case ATTR_MERGE:
if (changeSearchPath) {
objEnum = [inValues objectEnumerator];
newValues = [[[_node getAttribute:kDSNAttrCSPSearchPath] mutableCopy] autorelease];
while (newValue = [objEnum nextObject]) {
if (![newValues containsObject:newValue]) {
if ([self nodeNameIsValid:newValue]) {
[newValues addObject:newValue];
} else {
nError = eDSNodeNotFound;
break;
}
}
}
if (nError != eDSNodeNotFound) {
nError = [self setCustomSearchPath:newValues];
}
}
break;
case ATTR_DELETE:
if (changeSearchPath && [inValues count] > 0) {
oldValues = [_node getAttribute:kDSNAttrCSPSearchPath];
newValues = [[oldValues mutableCopy] autorelease];
[newValues removeObjectsInArray:inValues];
nError = [self setCustomSearchPath:newValues];
}
break;
case ATTR_CHANGE:
if (!changeSearchPath) {
oldValue = [_node getAttributeFirstValue:kDS1AttrSearchPolicy];
if ([[inValues objectAtIndex:0] isEqual:oldValue]
|| [[@kDSStdAttrTypePrefix stringByAppendingString:[inValues objectAtIndex:0]] isEqual:oldValue]) {
nError = [self setSearchPolicy:[inValues objectAtIndex:1]];
} else {
nError = eDSAttributeValueNotFound;
}
} else {
oldValues = [_node getAttribute:kDSNAttrCSPSearchPath];
newValues = [[oldValues mutableCopy] autorelease];
index = [oldValues indexOfObject:[inValues objectAtIndex:0]];
newValue = [inValues objectAtIndex:1];
if (index == 0) {
nError = eDSReadOnly;
} else if (index == NSNotFound) {
nError = eDSAttributeValueNotFound;
} else if ([self nodeNameIsValid:newValue]) {
[newValues replaceObjectAtIndex:index
withObject:newValue];
nError = [self setCustomSearchPath:newValues];
} else {
nError = eDSNodeNotFound;
}
}
break;
case ATTR_CHANGE_INDEX:
index = [[inValues objectAtIndex:0] intValue];
if (!changeSearchPath && index == 0) {
nError = [self setSearchPolicy:[inValues objectAtIndex:1]];
} else if (changeSearchPath && index != 0) {
oldValues = [_node getAttribute:kDSNAttrCSPSearchPath];
newValues = [[oldValues mutableCopy] autorelease];
newValue = [inValues objectAtIndex:1];
if (index >= [newValues count]) {
nError = eDSIndexOutOfRange;
} else if ([self nodeNameIsValid:newValue]) {
[newValues replaceObjectAtIndex:index withObject:newValue];
nError = [self setCustomSearchPath:newValues];
} else {
nError = eDSNodeNotFound;
}
}
break;
}
NS_HANDLER
if ([localException isKindOfClass:[DSoException class]])
{
nError = [(DSoException*)localException status];
firstError = nError;
//printf("standard createKey status was: %d\n", nError);
}
else
[localException raise];
NS_ENDHANDLER
return nError;
}
- (tDirStatus)setSearchPolicy:(NSString*)newPolicy
{
tDirStatus status = eDSReadOnly;
int aCommand = 0;
if (![newPolicy hasPrefix:@kDSStdAttrTypePrefix]) {
newPolicy = [@kDSStdAttrTypePrefix stringByAppendingString:newPolicy];
}
if ([newPolicy isEqualToString:@kDSNAttrNSPSearchPath])
{
aCommand = eODCustomCallSearchSetPolicyAutomatic;
}
else if ([newPolicy isEqualToString:@kDSNAttrLSPSearchPath])
{
aCommand = eODCustomCallSearchSetPolicyLocalOnly;
}
else if ([newPolicy isEqualToString:@kDSNAttrCSPSearchPath])
{
aCommand = eODCustomCallSearchSetPolicyCustom;
}
if (aCommand != 0)
{
status = [_node customCall:aCommand withAuthorization:&_authExternalForm];
}
return status;
}
- (tDirStatus)setCustomSearchPath:(NSArray*)nodeList
{
NSMutableArray* newNodeList = [[nodeList mutableCopy] autorelease];
// operating system was added in 10.6 and that's all we are looking for
id sysVersion = [[self configNode] getAttribute: kDS1AttrOperatingSystemVersion];
if ( [sysVersion count] == 0 || _type == eDSSearchNodeName ) {
for ( id path in [_node getAttribute:kDSNAttrLSPSearchPath] ) {
[newNodeList removeObject: path];
}
}
return [_node customCall: eODCustomCallSearchSetCustomNodeList
sendPropertyList: newNodeList
withAuthorization: &_authExternalForm];
}
- (BOOL)nodeNameIsValid:(NSString*)nodeName
{
UInt32 ulCount = 0;
BOOL result = NO;
tDirStatus nError = eDSReadOnly;
DSoBuffer *bufNodeList = nil;
DSoDataList *dlPattern = nil;
NS_DURING
//do we even care if this node is registered?
//we certainly do not care if it is not reachable at this time since search node takes care of
//node reachability ie. achieving and maintaining reachability
bufNodeList = [[DSoBuffer alloc] initWithDir:[_node directory] bufferSize:strlen([nodeName UTF8String]) + 128];
dlPattern = [[DSoDataList alloc] initWithDir:[_node directory] separator:'/' pattern:nodeName];
do {
nError = dsFindDirNodes([[_node directory] dsDirRef], [bufNodeList dsDataBuffer], [dlPattern dsDataList], eDSExact, &ulCount, NULL) ;
if (nError == eDSBufferTooSmall) {
[bufNodeList grow: [bufNodeList getBufferSize] *2];
}
} while (nError == eDSBufferTooSmall);
[dlPattern release];
[bufNodeList release];
if ( ( nError == eDSNoErr ) && ( ulCount > 0 ) )
result = YES;
NS_HANDLER
NS_ENDHANDLER
return result;
}
@end

57
dscl/PathRecord.h Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathRecord
*/
#import <Foundation/Foundation.h>
#import "PathItem.h"
@class DSoRecord;
@interface PathRecord : PathItem
{
DSoRecord *_record;
}
typedef enum {
ATTR_CREATE,
ATTR_APPEND,
ATTR_MERGE,
ATTR_DELETE,
ATTR_CHANGE,
ATTR_CHANGE_INDEX
} tAttrCAM;
// Initialize with a DS record object.
- initWithRecord:(DSoRecord*)inRec;
// Do the work of the create, append, and merge actions.
// They are virtually the same, with just a minor difference in calls.
- (tDirStatus) modify:(tAttrCAM)inAction withKey:(NSString*)inKey withValues:(NSArray*)inValues;
// ATM - give PlugInManager access to record object
-(DSoRecord*) record;
@end

633
dscl/PathRecord.m Normal file
View File

@ -0,0 +1,633 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathRecord
*/
#import <unistd.h>
#import <DirectoryService/DirServicesConst.h>
#import "PathRecord.h"
#import "DSoDirectory.h"
#import "DSoNode.h"
#import "DSoRecord.h"
#import "DSoUser.h"
#import "DSoException.h"
@implementation PathRecord
// ----------------------------------------------------------------------------
// Initialization / teardown
#pragma mark ******** Initialization / teardown ********
- init
{
[super init];
_record = nil;
return self;
}
- initWithRecord:(DSoRecord*)inRec
{
[self init];
_record = [inRec retain];
return self;
}
- (void)dealloc
{
[_record release];
[super dealloc];
}
// ----------------------------------------------------------------------------
// PathItemProtocol implementations
#pragma mark ******** PathItemProtocol implementations ********
- (tDirStatus) appendKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return [self modify:ATTR_APPEND withKey:inKey withValues:inValues];
}
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword authOnly:(BOOL)inAuthOnly
{
tDirStatus status = eDSNoErr;
status = [[_record node] authenticateName:inUsername withPassword:inPassword authOnly:inAuthOnly];
if (status == eDSNoErr && inAuthOnly == NO)
{
// Since we are now authenticated, we need to re-open this record.
DSoRecord *newRec = nil;
newRec = [[_record node] findRecord:[_record getName] ofType:[_record getType]];
[_record release];
_record = [newRec retain];
}
return status;
}
- (NSString*) name
{
return [_record getName];
}
- (tDirStatus) list:(NSString*)inPath key:(NSString*)inKey
{
return eDSNoErr;
}
- (PathItem*) cd:(NSString*)dest
{
return nil;
}
- (tDirStatus) createKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return [self modify:ATTR_CREATE withKey:inKey withValues:inValues];
}
- (tDirStatus) deleteItem
{
tDirStatus nError = eDSNoErr;
NS_DURING
[_record removeRecord];
NS_HANDLER
if ([localException isKindOfClass:[DSoException class]])
nError = [(DSoException*)localException status];
else
[localException raise];
NS_ENDHANDLER
return nError;
}
- (tDirStatus) delete:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *attribs = nil;
NSMutableArray *values = nil;
NSString *value = nil;
NSMutableDictionary *plist = nil;
NSArray *pathElements = nil;
NSEnumerator *pathEnum = nil;
NSString *currentPathElement = nil;
NSString *previousPathElement = nil;
id currentElement = nil;
id previousElement = nil;
NSPropertyListFormat format = NSPropertyListXMLFormat_v1_0;
BOOL changed = NO;
tDirStatus status = eDSNoErr;
NS_DURING
attribs = [self getDictionary:[NSArray arrayWithObject:inKey]];
if([attribs count] == 0)
{
printf("Invalid key.\n");
NS_VALUERETURN(eDSEmptyAttribute,tDirStatus);
}
NSString *attrib;
if (!([inKey hasPrefix:@kDSStdAttrTypePrefix] || [inKey hasPrefix:@kDSNativeAttrTypePrefix]))
{
attrib = [@kDSStdAttrTypePrefix stringByAppendingString:inKey];
if([attribs objectForKey:attrib] != nil)
inKey = attrib;
attrib = [@kDSNativeAttrTypePrefix stringByAppendingString:inKey];
if([attribs objectForKey:attrib] != nil)
inKey = attrib;
}
values = [[[attribs objectForKey:inKey] mutableCopy] autorelease];
if([values count] < 1)
{
printf("There is no value for attribute %s\n", [inKey UTF8String]);
NS_VALUERETURN(eDSEmptyAttribute,tDirStatus);
}
else if(index >= [values count])
{
printf("Value index out of range\n");
NS_VALUERETURN(eDSIndexOutOfRange,tDirStatus);
}
else
{
value = [values objectAtIndex:index];
}
plist = [NSPropertyListSerialization propertyListFromData:[value dataUsingEncoding:NSUTF8StringEncoding]
mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:nil];
pathElements = [inPlistPath componentsSeparatedByString:@":"];
pathEnum = [pathElements objectEnumerator];
currentElement = plist;
while (currentElement != nil && ((currentPathElement = (NSString*)[pathEnum nextObject]) != nil))
{
previousPathElement = currentPathElement;
previousElement = currentElement;
if ([currentElement isKindOfClass:[NSDictionary class]])
{
currentElement = [currentElement objectForKey:currentPathElement];
}
else if([currentElement isKindOfClass:[NSArray class]])
{
NSString* intString = [[NSString alloc] initWithFormat:@"%d",[currentPathElement intValue]];
if([currentPathElement intValue] >= [currentElement count] || ![currentPathElement isEqualToString:intString])
{
break; // index out of range
}
else
{
currentElement = [currentElement objectAtIndex:[currentPathElement intValue]];
}
[intString release];
}
else
{
break; // not a valid path
}
}
inValues = [inValues sortedArrayUsingSelector:@selector(compare:)];
int c;
for(c = [inValues count] - 1; c >= 0; c--)
{
if (currentPathElement == nil && currentElement != nil)
{
// found something
if([currentElement isKindOfClass:[NSDictionary class]])
{
[currentElement removeObjectForKey:[inValues objectAtIndex:c]];
changed = YES;
}
else if([currentElement isKindOfClass:[NSArray class]])
{
NSString* intString = [[NSString alloc] initWithFormat:@"%d",[[inValues objectAtIndex:c] intValue]];
if(![[inValues objectAtIndex:c] isEqualToString:intString])
{
printf("Invalid index %s\n", [[inValues objectAtIndex:c] UTF8String]);
}
else if([[inValues objectAtIndex:c] intValue] >= [currentElement count])
{
printf("Index out of range\n");
}
else
{
[currentElement removeObjectAtIndex:[[inValues objectAtIndex:c] intValue]];
changed = YES;
}
[intString release];
}
}
else
{
// bogus path
printf("No such plist path: %s\n", [inPlistPath UTF8String]);
NS_VALUERETURN(eDSUnknownMatchType, tDirStatus);
}
}
if([inValues count] == 0)
{
if(previousPathElement && previousElement)
{
if([previousElement isKindOfClass:[NSDictionary class]])
{
[previousElement removeObjectForKey:previousPathElement];
changed = YES;
}
else if([previousElement isKindOfClass:[NSArray class]])
{
NSString* intString = [[NSString alloc] initWithFormat:@"%d",[previousPathElement intValue]];
if(![previousPathElement isEqualToString:intString])
{
printf("Invalid index %s\n", [previousPathElement UTF8String]);
}
else if([previousPathElement intValue] >= [previousElement count])
{
printf("Index out of range\n");
}
else
{
[previousElement removeObjectAtIndex:[previousPathElement intValue]];
changed = YES;
}
}
}
}
if(changed)
{
NSData *data = [NSPropertyListSerialization dataFromPropertyList:plist format:format errorDescription:nil];
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[values replaceObjectAtIndex:index withObject:dataString];
[dataString release];
status = [self modify:ATTR_CREATE withKey:inKey withValues:values];
}
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
[pool release];
return status;
}
- (tDirStatus) delete:(NSString*)inKey plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
return [self delete:inKey atIndex:0 plistPath:inPlistPath values:inValues];
}
- (tDirStatus) create:(NSString*)inKey atIndex:(int)index plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *attribs = nil;
NSMutableArray *values = nil;
NSString *value = nil;
NSMutableDictionary *plist = nil;
NSArray *pathElements = nil;
NSEnumerator *pathEnum = nil;
NSString *currentPathElement = nil;
NSString *previousPathElement = nil;
id currentElement = nil;
id previousElement = nil;
NSPropertyListFormat format = NSPropertyListXMLFormat_v1_0;
BOOL changed = NO;
tDirStatus status = eDSNoErr;
NS_DURING
attribs = [self getDictionary:[NSArray arrayWithObject:inKey]];
if([attribs count] == 0)
{
printf("Invalid key.\n");
}
NSString *attrib;
if (!([inKey hasPrefix:@kDSStdAttrTypePrefix] || [inKey hasPrefix:@kDSNativeAttrTypePrefix]))
{
attrib = [@kDSStdAttrTypePrefix stringByAppendingString:inKey];
if([attribs objectForKey:attrib] != nil)
inKey = attrib;
attrib = [@kDSNativeAttrTypePrefix stringByAppendingString:inKey];
if([attribs objectForKey:attrib] != nil)
inKey = attrib;
}
values = [[[attribs objectForKey:inKey] mutableCopy] autorelease];
if([values count] < 1)
{
printf("There is no value for attribute %s\n", [inKey UTF8String]);
NS_VALUERETURN(eDSEmptyAttribute,tDirStatus);
}
else if(index >= [values count])
{
printf("Value index out of range\n");
NS_VALUERETURN(eDSIndexOutOfRange,tDirStatus);
}
else
{
value = [values objectAtIndex:index];
}
plist = [NSPropertyListSerialization propertyListFromData:[value dataUsingEncoding:NSUTF8StringEncoding]
mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:nil];
pathElements = [inPlistPath componentsSeparatedByString:@":"];
pathEnum = [pathElements objectEnumerator];
currentElement = plist;
while (currentElement != nil && ((currentPathElement = (NSString*)[pathEnum nextObject]) != nil))
{
previousPathElement = currentPathElement;
previousElement = currentElement;
if ([currentElement isKindOfClass:[NSDictionary class]])
{
currentElement = [currentElement objectForKey:currentPathElement];
}
else if([currentElement isKindOfClass:[NSArray class]])
{
NSString* intString = [[NSString alloc] initWithFormat:@"%d",[currentPathElement intValue]];
if([currentPathElement intValue] > [currentElement count] || ![currentPathElement isEqualToString:intString])
{
currentPathElement = nil;
currentElement = nil;
printf("Index out of range\n");
break; // index out of range
}
else if([currentPathElement intValue] == [currentElement count])
{
currentElement = nil;
break;
}
else
{
currentElement = [currentElement objectAtIndex:[currentPathElement intValue]];
}
[intString release];
}
else
{
currentPathElement = [pathEnum nextObject];
if (currentPathElement != nil)
{
break; // not a valid path
}
}
}
id container = nil;
id key = nil;
if((currentPathElement == nil && currentElement != nil) ||
(currentPathElement != nil && previousElement != nil && [pathEnum nextObject] == nil))
{
container = previousElement;
key = previousPathElement;
}
else
{
container = nil;
key = nil;
printf("No such plist path: %s\n", [inPlistPath UTF8String]);
NS_VALUERETURN(eDSUnknownMatchType, tDirStatus);
}
if([container isKindOfClass:[NSArray class]])
{
// Adding to an array
printf("Changing an array\n");
if([inValues count] == 1)
{
//[container removeAllObjects];
//[container addObject:[inValues objectAtIndex:0]];
if([key intValue] < [container count])
[container replaceObjectAtIndex:[key intValue] withObject:[inValues objectAtIndex:0]];
else
[container addObject:[inValues objectAtIndex:0]];
}
else
{
if([key intValue] < [container count])
[container replaceObjectAtIndex:[key intValue] withObject:inValues];
else
[container addObject:inValues];
}
changed = YES;
}
else if([container isKindOfClass:[NSDictionary class]])
{
// Adding to a dictionary
printf("Changing a dictionary\n");
if([inValues count] == 1)
{
[container setObject:[inValues objectAtIndex:0] forKey:key];
}
else
{
[container setObject:inValues forKey:key];
}
changed = YES;
}
else
{
printf("No such plist path: %s\n", [inPlistPath UTF8String]);
NS_VALUERETURN(eDSUnknownMatchType, tDirStatus);
}
if(changed)
{
NSData *data = [NSPropertyListSerialization dataFromPropertyList:plist format:format errorDescription:nil];
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[values replaceObjectAtIndex:index withObject:dataString];
[dataString release];
status = [self modify:ATTR_CREATE withKey:inKey withValues:values];
}
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
[pool release];
return status;
}
- (tDirStatus) create:(NSString*)inKey plistPath:(NSString*)inPlistPath values:(NSArray*)inValues
{
return [self create:inKey atIndex:0 plistPath:inPlistPath values:inValues];
}
- (tDirStatus) deleteKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return [self modify:ATTR_DELETE withKey:inKey withValues:inValues];
}
- (tDirStatus) mergeKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return [self modify:ATTR_MERGE withKey:inKey withValues:inValues];
}
- (tDirStatus) changeKey:(NSString*)inKey oldAndNewValues:(NSArray*)inValues
{
return [self modify:ATTR_CHANGE withKey:inKey withValues:inValues];
}
- (tDirStatus) changeKey:(NSString*)inKey indexAndNewValue:(NSArray*)inValues
{
return [self modify:ATTR_CHANGE_INDEX withKey:inKey withValues:inValues];
}
- (NSString*)nodeName
{
return [[_record node] getName];
}
- (NSDictionary*)getDictionary:(NSArray*)inKeys
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *attribs = nil;
NS_DURING
if (inKeys == nil || [inKeys count] == 0)
{
attribs = [_record getAllAttributesAndValues];
}
else
{
NSArray* niceKeys = prefixedAttributeKeysWithNode([_record node], inKeys);
attribs = [_record getAttributes:niceKeys];
}
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
[attribs retain];
[pool release];
return [attribs autorelease];
}
- (tDirStatus) setPassword:(NSArray*)inParams
{
if (!strcmp([_record getType], kDSStdRecordTypeUsers))
{
// This is a user record, proceed to set the password
if ([inParams count] == 2)
[(DSoUser*)_record changePassword:[inParams objectAtIndex:0]
toNewPassword:[inParams objectAtIndex:1]];
else
{
NS_DURING
[(DSoUser*)_record setPassword:[inParams objectAtIndex:0]];
NS_HANDLER
if (DS_EXCEPTION_STATUS_IS(eDSPermissionError))
{
NSString* oldPassword = [NSString stringWithUTF8String:getpass("Permission denied. Please enter user's old password:")];
[(DSoUser*)_record changePassword:oldPassword toNewPassword:[inParams objectAtIndex:0]];
}
else
[localException raise];
NS_ENDHANDLER
}
}
else
{
// This is some other record type, we can't set a password
[DSoException raiseWithStatus:eDSInvalidRecordType];
}
return eDSNoErr;
}
// ----------------------------------------------------------------------------
// Utility methods
#pragma mark ******** Utility methods ********
- (tDirStatus) modify:(tAttrCAM)inAction withKey:(NSString*)inKey withValues:(NSArray*)inValues
{
NSString *attrib = nil;
tDirStatus nError = eDSNoErr;
tDirStatus firstError = eDSNoErr;
if ([inKey hasPrefix:@kDSStdAttrTypePrefix] || [inKey hasPrefix:@kDSNativeAttrTypePrefix])
{
attrib = inKey;
}
else
{
attrib = [@kDSStdAttrTypePrefix stringByAppendingString:inKey];
if (![[[[_record node] directory] standardAttributeTypes] containsObject:attrib])
attrib = [@kDSNativeAttrTypePrefix stringByAppendingString:inKey];
}
NS_DURING
switch (inAction)
{
case ATTR_CREATE:
[_record setAttribute:[attrib UTF8String] values:inValues];
break;
case ATTR_APPEND:
[_record addAttribute:[attrib UTF8String] values:inValues mergeValues:NO];
break;
case ATTR_MERGE:
[_record addAttribute:[attrib UTF8String] values:inValues mergeValues:YES];
break;
case ATTR_DELETE:
if (inValues == nil || [inValues count] == 0)
[_record removeAttribute:[attrib UTF8String]];
else
[_record removeAttribute:[attrib UTF8String] values:inValues];
break;
case ATTR_CHANGE:
[_record changeAttribute:[attrib UTF8String] oldValue:[inValues objectAtIndex:0]
newValue:[inValues objectAtIndex:1]];
break;
case ATTR_CHANGE_INDEX:
[_record changeAttribute:[attrib UTF8String] index:[[inValues objectAtIndex:0] intValue]
newValue:[inValues objectAtIndex:1]];
break;
}
NS_HANDLER
if ([localException isKindOfClass:[DSoException class]])
{
nError = [(DSoException*)localException status];
firstError = nError;
//printf("standard createKey status was: %d\n", nError);
}
else
[localException raise];
NS_ENDHANDLER
return nError;
}
-(DSoRecord*) record
{
// ATM - give PlugInManager access to record instance
return _record;
}
@end

44
dscl/PathRecordConfig.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathRecordConfig
*/
#import <Foundation/Foundation.h>
#import "PathRecord.h"
@class DSoRecord;
@interface PathRecordConfig : PathRecord
{
AuthorizationExternalForm _authExternalForm;
BOOL _haveRights;
}
- (void)setAuthExternalForm:(AuthorizationExternalForm*)externalForm;
- (tDirStatus)setPluginEnabled:(NSString*)newState;
@end

294
dscl/PathRecordConfig.m Normal file
View File

@ -0,0 +1,294 @@
/*
* Copyright (c) 2003-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathRecordConfig
*/
#import "PathRecordConfig.h"
#import "DSoDirectory.h"
#import "DSoNode.h"
#import "DSoNodeConfig.h"
#import "DSoRecord.h"
#import "DSoUser.h"
#import "DSoException.h"
#import <DirectoryService/DirServicesConst.h>
#import <opendirectory/odutils.h>
@interface PathRecordConfig (Private)
- (void) _destroyRights;
@end
@implementation PathRecordConfig (Private)
- (void)_destroyRights
{
// free _authExternalForm
if (_haveRights) {
[[_record node] customCall:eODCustomCallConfigureDestroyAuthRef
withAuthorization:&_authExternalForm];
_haveRights = NO;
}
}
@end
@implementation PathRecordConfig
// ----------------------------------------------------------------------------
// Initialization / teardown
#pragma mark ******** Initialization / teardown ********
- init
{
[super init];
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- initWithRecord:(DSoRecord*)inRec
{
[super initWithRecord:inRec];
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- (void)dealloc
{
[self _destroyRights];
[super dealloc];
}
- (void)setAuthExternalForm:(AuthorizationExternalForm*)externalForm {
// don't set _haveRights here since a node above us owns the auth right
memcpy(&_authExternalForm, externalForm, sizeof(AuthorizationExternalForm));
}
// ----------------------------------------------------------------------------
// PathItemProtocol implementations
#pragma mark ******** PathItemProtocol implementations ********
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword authOnly:(BOOL)inAuthOnly
{
NSAutoreleasePool* pool = [NSAutoreleasePool new];
DSoSearchNode* searchNode = [[[_record node] directory] searchNode];
DSoUser* user = nil;
tDirStatus status = eDSAuthFailed;
NSMutableData* outputData = nil;
NS_DURING
user = [searchNode findUser:inUsername];
if (user != nil) {
status = [[user node] authenticateName:inUsername withPassword:inPassword authOnly:YES];
if (status == eDSNoErr && inAuthOnly == NO) {
outputData = [NSMutableData dataWithLength:sizeof(AuthorizationExternalForm)];
status = [[_record node] customCall:eODCustomCallConfigureGetAuthRef
sendItems:[NSArray arrayWithObjects:inUsername,inPassword,nil]
outputData:outputData];
if (status == eDSNoErr && [outputData length] >= sizeof( AuthorizationExternalForm ) )
{
[outputData getBytes:&_authExternalForm length:sizeof( AuthorizationExternalForm )];
_haveRights = YES;
}
}
}
NS_HANDLER
NS_ENDHANDLER
[pool release];
return status;
}
- (tDirStatus) createKey:(NSString*)inKey withValues:(NSArray*)inValues
{
return [self modify:ATTR_CREATE withKey:inKey withValues:inValues];
}
- (tDirStatus) deleteItem
{
tDirStatus nError = eDSNoErr;
NS_DURING
[_record removeRecord];
NS_HANDLER
if ([localException isKindOfClass:[DSoException class]])
nError = [(DSoException*)localException status];
else
[localException raise];
NS_ENDHANDLER
return nError;
}
- (NSDictionary*)getDictionary:(NSArray*)inKeys
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *records = nil;
NSDictionary *attribs = nil;
NS_DURING
if ([[NSString stringWithUTF8String:[_record getType]] hasPrefix:@kDSStdRecordTypePrefix])
records = [[_record node] findRecordNames:@kDSRecordsAll
andAttributes:[NSArray arrayWithObject:@kDSAttributesAll]
ofType:[_record getType]
matchType:eDSExact];
else
records = [[_record node] findRecordNames:@kDSRecordsAll
andAttributes:[NSArray arrayWithObject:@kDSAttributesAll]
ofType:[_record getType]
matchType:eDSExact];
for (NSDictionary *recordDict in records) {
NSArray *values = [recordDict objectForKey:@kDSNAttrRecordName];
if ([values count] > 0 && [[values objectAtIndex:0] isEqual: [_record getName]]) {
attribs = recordDict;
break;
}
}
if ([inKeys count] > 0)
{
//NSArray* niceKeys = prefixedAttributeKeysWithNode([_record node], inKeys);
NSMutableDictionary* attribsFiltered = [NSMutableDictionary dictionary];
for (NSString *key in inKeys) {
NSString *niceKey = nil;
if ([key hasPrefix:@kDSStdAttrTypePrefix] || [key hasPrefix:@kDSNativeAttrTypePrefix])
{
niceKey = key;
}
else
{
niceKey = [@kDSStdAttrTypePrefix stringByAppendingString:key];
if ([attribs objectForKey: niceKey] == nil && ![[[[_record node] directory] standardAttributeTypes] containsObject:niceKey])
niceKey = [@kDSNativeAttrTypePrefix stringByAppendingString:key];
}
id value = [attribs objectForKey:niceKey];
if (value != nil) {
[attribsFiltered setObject:value forKey:niceKey];
}
}
attribs = [[attribsFiltered copy] autorelease];
}
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
[attribs retain];
[pool release];
return [attribs autorelease];
}
// ----------------------------------------------------------------------------
// Utility methods
#pragma mark ******** Utility methods ********
- (tDirStatus) modify:(tAttrCAM)inAction withKey:(NSString*)inKey withValues:(NSArray*)inValues
{
tDirStatus nError = eDSReadOnly;
tDirStatus firstError = eDSNoErr;
NSUInteger index = NSNotFound;
NSDictionary *valuesDict = nil;
NSArray *oldValues = nil;
if (![[NSString stringWithUTF8String:[_record getType]] hasSuffix:@":Plugins"]) {
return eDSReadOnly;
}
if (![inKey isEqualToString:@kDS1AttrFunctionalState]
&& ![[@kDSStdAttrTypePrefix stringByAppendingString:inKey] isEqualToString:@kDS1AttrFunctionalState])
{
return eDSReadOnly;
}
NS_DURING
switch (inAction)
{
case ATTR_CREATE:
if ([inValues count] == 1) {
nError = [self setPluginEnabled:[inValues lastObject]];
}
break;
case ATTR_APPEND:
case ATTR_MERGE:
case ATTR_DELETE:
// these are not supported
break;
case ATTR_CHANGE:
valuesDict = [self getDictionary: [NSArray arrayWithObject:@kDS1AttrFunctionalState]];
oldValues = (NSArray*)[valuesDict objectForKey:@kDS1AttrFunctionalState];
if ([oldValues count] == 1 && [[inValues objectAtIndex:0] isEqual:[oldValues objectAtIndex:0]]) {
nError = [self setPluginEnabled:[inValues objectAtIndex:1]];
} else {
nError = eDSAttributeValueNotFound;
}
break;
case ATTR_CHANGE_INDEX:
index = [[inValues objectAtIndex:0] intValue];
if (index == 0) {
nError = [self setPluginEnabled:[inValues objectAtIndex:1]];
}
break;
}
NS_HANDLER
if ([localException isKindOfClass:[DSoException class]])
{
nError = [(DSoException*)localException status];
firstError = nError;
}
else
[localException raise];
NS_ENDHANDLER
return nError;
}
- (tDirStatus)setPluginEnabled:(NSString*)newState
{
BOOL newStateBool;
if ([newState isEqualToString:@"Active"])
{
newStateBool = YES;
}
else if ([newState isEqualToString:@"Inactive"]) {
newStateBool = NO;
}
else
{
return eDSReadOnly;
}
[(DSoNodeConfig*)[_record node] setPlugin:[_record getName] enabled:newStateBool withAuthorization:&_authExternalForm];
return eDSNoErr;
}
@end

46
dscl/PathRecordType.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathRecordType
*/
#import <Foundation/Foundation.h>
#import "PathItem.h"
@class DSoNode;
@interface PathRecordType : PathItem
{
DSoNode *_node;
NSString *_recordType;
}
// Initialize with a DS Node object and the name of this record type.
- initWithNode:(DSoNode*)inNode recordType:(NSString*)inType;
// ATM - PlugInManager needs access to node & recordType
-(DSoNode*) node;
-(NSString*) recordType;
@end

497
dscl/PathRecordType.m Normal file
View File

@ -0,0 +1,497 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathRecordType
*/
#import "PathRecordType.h"
#import "DSoDirectory.h"
#import "DSoNode.h"
#import "PathRecord.h"
#import <DirectoryService/DirServicesConst.h>
#import "DSoException.h"
#import "DSoRecord.h"
#import "DSoRecordPriv.h"
extern BOOL gHACK;
@interface PathRecordType (PathRecordTypePrivate)
- (void)printSearch:(NSString*)inKey Results:(NSArray*)inResults;
@end
NSInteger compareRecordDicts(id leftDict, id rightDict, void * context)
{
return [[[(NSDictionary*)leftDict objectForKey:@kDSNAttrRecordName]
objectAtIndex:0]
caseInsensitiveCompare: [[(NSDictionary*)rightDict
objectForKey:@kDSNAttrRecordName] objectAtIndex:0]];
}
@implementation PathRecordType
// ----------------------------------------------------------------------------
// Initialization / teardown
#pragma mark ******** Initialization / teardown ********
- init
{
[super init];
_node = nil;
_recordType = nil;
return self;
}
- initWithNode:(DSoNode*)inNode recordType:(NSString*)inType
{
[self init];
_node = [inNode retain];
_recordType = [inType retain];
return self;
}
- (void)dealloc
{
[_recordType release];
[_node release];
[super dealloc];
}
// ----------------------------------------------------------------------------
// PathItemProtocol implementations
#pragma mark ******** PathItemProtocol implementations ********
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword authOnly:(BOOL)inAuthOnly
{
return [_node authenticateName:inUsername withPassword:inPassword authOnly:inAuthOnly];
}
- (NSString*) name
{
return [self stripDSPrefixOffValue:_recordType];
}
- (NSArray*) getList:(NSString*)inKey
{
NSArray *list = nil;
NS_DURING
if (inKey == nil)
{
list = [[_node findRecordNames:@kDSRecordsAll
ofType:[_recordType UTF8String]
matchType:eDSExact]
sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
}
else
{
list = [[_node findRecordNames:@kDSRecordsAll
andAttributes:[NSArray arrayWithObject:inKey]
ofType:[_recordType UTF8String]
matchType:eDSExact]
sortedArrayUsingFunction:compareRecordDicts context:nil];
}
NS_HANDLER
if (!DS_EXCEPTION_STATUS_IS(eDSRecordNotFound) &&
!DS_EXCEPTION_STATUS_IS(eDSInvalidRecordType))
{
[localException raise];
}
NS_ENDHANDLER
return list;
}
- (NSArray*) getList
{
return [self getList:nil];
}
- (NSArray*) getListWithKeys:(NSArray*)inKeys
{
NSArray *list = nil;
NSArray *niceKeys = nil;
NS_DURING
if ( [inKeys count] == 0 )
{
list = [[_node findRecordNames:@kDSRecordsAll
andAttributes:[NSArray arrayWithObject:@kDSAttributesAll]
ofType:[_recordType UTF8String]
matchType:eDSExact]
sortedArrayUsingFunction:compareRecordDicts context:nil];
}
else
{
niceKeys = prefixedAttributeKeysWithNode(_node, inKeys);
list = [[_node findRecordNames:@kDSRecordsAll
andAttributes:niceKeys
ofType:[_recordType UTF8String]
matchType:eDSiExact]
sortedArrayUsingFunction:compareRecordDicts context:nil];
}
NS_HANDLER
if (!DS_EXCEPTION_STATUS_IS(eDSRecordNotFound) &&
!DS_EXCEPTION_STATUS_IS(eDSInvalidRecordType))
{
[localException raise];
}
NS_ENDHANDLER
return list;
}
- (tDirStatus) list:(NSString*)inPath key:(NSString*)inKey
{
NSArray *list;
NSString *key = inKey;
unsigned long i = 0;
unsigned long count = 0;
if (inKey != nil
&& ![key hasPrefix:@kDSStdAttrTypePrefix]
&& ![key hasPrefix:@kDSNativeAttrTypePrefix])
{
key = [@kDSStdAttrTypePrefix stringByAppendingString:inKey];
if (![[[_node directory] standardAttributeTypes] containsObject:key])
key = [@kDSNativeAttrTypePrefix stringByAppendingString:inKey];
}
list = [self getList:key];
if (list != nil && [list count] > 0)
{
count = [list count];
if (inKey == nil)
{
for (i = 0; i < count; i++)
{
printf("%s\n",[[list objectAtIndex:i] UTF8String]);
}
}
else
{
int maxLength = 0;
int currentLength = 0;
for (i = 0; i < count; i++)
{
NSDictionary* record = (NSDictionary*)[list objectAtIndex:i];
NSArray* recordNames = [record objectForKey:@kDSNAttrRecordName];
NSArray* keyValues = [record objectForKey:key];
if ([keyValues count] == 0)
continue;
if ([recordNames count] > 0)
{
currentLength = strlen( [[recordNames objectAtIndex:0] UTF8String]);
if (currentLength > maxLength)
{
maxLength = currentLength;
}
}
}
for (i = 0; i < count; i++)
{
NSDictionary* record = (NSDictionary*)[list objectAtIndex:i];
NSArray* recordNames = [record objectForKey:@kDSNAttrRecordName];
NSArray* keyValues = [record objectForKey:key];
NSString* value = nil;
NSEnumerator* valueEnum = [keyValues objectEnumerator];
if ([keyValues count] == 0)
continue;
if ([recordNames count] > 0)
{
printf("%s",[[recordNames objectAtIndex:0] UTF8String]);
}
currentLength = maxLength
- strlen([[recordNames objectAtIndex:0] UTF8String]) + 2;
while (currentLength > 0)
{
printf(" ");
currentLength--;
}
while ((value = (NSString*)[valueEnum nextObject]) != nil)
{
printValue(value, NO);
}
printf("\n");
}
}
}
return eDSNoErr;
}
- (NSArray*) getPossibleCompletionsFor:(NSString*)inPrefix
{
NSMutableArray* possibleCompletions = [NSMutableArray array];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *searchResults = nil;
NSArray *recordTypes = [NSArray arrayWithObject:_recordType];
NSString *key = [NSString stringWithUTF8String:kDSNAttrRecordName];
NSMutableArray *attribList = [NSMutableArray arrayWithObjects:
key, nil];
tDirPatternMatch type = eDSiStartsWith;
NS_DURING
searchResults = [_node findRecordsOfTypes:recordTypes withAttribute:[key UTF8String]
value:inPrefix matchType:type retrieveAttributes:attribList];
if (searchResults != nil)
{
NSEnumerator* listEnum = [searchResults objectEnumerator];
NSDictionary* currentItem = nil;
while (currentItem = (NSDictionary*)[listEnum nextObject])
{
id recordName = [currentItem objectForKey:key];
if ([recordName isKindOfClass:[NSArray class]]
&& [recordName count] > 0) {
recordName = [recordName objectAtIndex:0];
}
if ([recordName isKindOfClass:[NSString class]]
&& [[recordName lowercaseString] hasPrefix:inPrefix]
&& ![possibleCompletions containsObject:recordName])
[possibleCompletions addObject:recordName];
}
}
NS_HANDLER
if (!DS_EXCEPTION_STATUS_IS(eNotYetImplemented) &&
!DS_EXCEPTION_STATUS_IS(eNotHandledByThisNode))
{
[localException retain];
[pool release];
[[localException autorelease] raise];
}
else
{
possibleCompletions = nil;
}
NS_ENDHANDLER
[pool release];
if (possibleCompletions == nil)
possibleCompletions = (NSMutableArray*)[super getPossibleCompletionsFor:inPrefix];
return possibleCompletions;
}
- (PathItem*) cd:(NSString*)dest
{
DSoRecord *rec = nil;
PathRecord *p = nil;
if (dest != nil && [dest length] > 0)
{
NS_DURING
rec = [_node findRecord:dest ofType:[_recordType UTF8String]];
NS_HANDLER
if (gHACK && DS_EXCEPTION_STATUS_IS(eDSRecordNotFound)) // Hack to force read-only entry into a record which doesn't implement dsOpenRecord()
rec = [[[DSoRecord alloc] initInNode:_node
type:[_recordType UTF8String] name:dest create:NO] autorelease];
else
[localException raise];
NS_ENDHANDLER
if (rec != nil)
p = [[PathRecord alloc] initWithRecord:rec];
return [p autorelease];
}
else
return nil;
}
- (tDirStatus) createKey:(NSString*)inKey withValues:(NSArray*)inValues
{
tDirStatus status = eDSNoErr;
NS_DURING
[_node newRecord:inKey ofType:[_recordType UTF8String]];
NS_HANDLER
if ([localException isKindOfClass:[DSoException class]])
status = [(DSoException*)localException status];
else
[localException raise];
NS_ENDHANDLER
return status;
}
- (tDirStatus) deleteItem
{
NSArray *list;
DSoRecord *rec;
unsigned long i = 0;
unsigned long count = 0;
const char *recType = NULL;
tDirStatus status = eDSNoErr;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
recType = [_recordType UTF8String];
NS_DURING
list = [_node findRecordNames:@kDSRecordsAll
ofType:recType
matchType:eDSAnyMatch];
count = [list count];
for (i = 0; i < count; i++)
{
rec = [_node findRecord:[list objectAtIndex:i] ofType:recType];
[rec removeRecord];
}
NS_HANDLER
if ([localException isKindOfClass:[DSoException class]])
{
status = [(DSoException*)localException status];
}
else
{
[localException retain];
[pool release];
[[localException autorelease] raise];
}
NS_ENDHANDLER
[pool release];
return status;
}
- (NSString*)nodeName
{
return [_node getName];
}
- (tDirStatus) read:(NSArray*)inKeys
{
printf("name: %s\n", [_recordType UTF8String]);
return eDSNoErr;
}
- (tDirStatus) read:(NSString*)inPath keys:(NSArray*)inKeys
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
tDirStatus status = eDSRecordNotFound;
NSArray* niceKeys = [inKeys count] > 0 ? prefixedAttributeKeysWithNode(_node, inKeys) : [NSArray arrayWithObject:@kDSAttributesAll];
NSArray* foundRecords = nil;
NSUInteger recordIndex = 0;
NSUInteger recordCount = 0;
NS_DURING
foundRecords = [_node findRecordNames:inPath andAttributes:niceKeys
ofType:[_recordType UTF8String] matchType:eDSExact];
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
recordCount = [foundRecords count];
for (recordIndex = 0; recordIndex < recordCount; recordIndex++)
{
NSMutableDictionary* foundRecord = [[[foundRecords objectAtIndex:recordIndex] mutableCopy] autorelease];
if ([inKeys count] > 0 && ![niceKeys containsObject:@kDSNAttrRecordName])
{
[foundRecord removeObjectForKey:@kDSNAttrRecordName];
}
[self printDictionary:foundRecord withRequestedKeys:inKeys];
status = eDSNoErr;
}
[pool release];
return status;
}
- (tDirStatus) searchForKey:(NSString*)inKey withValue:(NSString*)inValue matchType:(NSString*)inType
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *searchResults = nil;
NSArray *recordTypes = [NSArray arrayWithObject:_recordType];
NSMutableArray *attribList = [NSMutableArray arrayWithObject:@kDSNAttrRecordName];
NSString *key = nil;
tDirPatternMatch type = eDSExact;
NS_DURING
if ([inKey hasPrefix:@kDSStdAttrTypePrefix] || [inKey hasPrefix:@kDSNativeAttrTypePrefix])
{
key = inKey;
}
else
{
key = [@kDSStdAttrTypePrefix stringByAppendingString:inKey];
if (![[[_node directory] standardAttributeTypes] containsObject:key])
key = [@kDSNativeAttrTypePrefix stringByAppendingString:inKey];
}
[attribList addObject:key];
searchResults = [_node findRecordsOfTypes:recordTypes withAttribute:[key UTF8String]
value:inValue matchType:type retrieveAttributes:attribList];
[self printSearch:key Results:searchResults];
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
[pool release];
return eDSNoErr;
}
-(DSoNode*) node
{
// ATM - needed for PlugInManager
return _node;
}
-(NSString*) recordType
{
// ATM - needed for PlugInManager
return _recordType;
}
@end
// ----------------------------------------------------------------------------
// Private methods
#pragma mark ******** Private methods ********
@implementation PathRecordType (PathRecordTypePrivate)
- (void)printSearch:(NSString*)inKey Results:(NSArray*)inResults
{
NSEnumerator *resultEnumerator = [inResults objectEnumerator];
id d = nil;
while(d = [resultEnumerator nextObject])
{
printf("%s\t\t%s = %s\n", [[[d objectForKey:@kDSNAttrRecordName] objectAtIndex:0] UTF8String],
[[self stripDSPrefixOffValue:inKey] UTF8String], [[[d objectForKey:inKey] description] UTF8String]);
}
}
@end

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathRecordTypeConfig
*/
#import <Foundation/Foundation.h>
#import "PathRecordType.h"
@interface PathRecordTypeConfig : PathRecordType
{
AuthorizationExternalForm _authExternalForm;
BOOL _haveRights;
}
- (void)setAuthExternalForm:(AuthorizationExternalForm*)externalForm;
@end

301
dscl/PathRecordTypeConfig.m Normal file
View File

@ -0,0 +1,301 @@
/*
* Copyright (c) 2003-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PathRecordTypeConfig
*/
#import "PathRecordTypeConfig.h"
#import "PathRecordConfig.h"
#import "DSoException.h"
#import "DSoDirectory.h"
#import "DSoNode.h"
#import "DSoRecord.h"
#import "DSoRecordPriv.h"
#import <opendirectory/odutils.h>
extern BOOL gHACK;
@interface PathRecordTypeConfig (Private)
- (void) _destroyRights;
@end
@implementation PathRecordTypeConfig (Private)
- (void)_destroyRights
{
// free _authExternalForm
if (_haveRights) {
[_node customCall:eODCustomCallConfigureDestroyAuthRef
withAuthorization:&_authExternalForm];
}
}
@end
@implementation PathRecordTypeConfig
// ----------------------------------------------------------------------------
// Initialization / teardown
#pragma mark ******** Initialization / teardown ********
- init
{
[super init];
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- initWithNode:(DSoNode*)inNode recordType:(NSString*)inType
{
[super initWithNode:inNode recordType:inType];
bzero(&_authExternalForm,sizeof(_authExternalForm));
return self;
}
- (void)dealloc
{
[self _destroyRights];
[super dealloc];
}
- (void)setAuthExternalForm:(AuthorizationExternalForm*)externalForm {
// don't set _haveRights here since a node above us owns the auth right
memcpy(&_authExternalForm, externalForm, sizeof(AuthorizationExternalForm));
}
// ----------------------------------------------------------------------------
// PathItemProtocol implementations
#pragma mark ******** PathItemProtocol implementations ********
- (NSArray*) getList:(NSString*)inKey
{
NSArray *list = nil;
NS_DURING
if ([_recordType hasPrefix:@kDSStdRecordTypePrefix])
list = [[_node findRecordNames:@kDSRecordsAll
ofType:[_recordType UTF8String]
matchType:eDSExact]
sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
else
list = [[_node findRecordNames:@kDSRecordsAll
ofType:[_recordType UTF8String]
matchType:eDSExact]
sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
NS_HANDLER
if (!DS_EXCEPTION_STATUS_IS(eDSRecordNotFound) &&
!DS_EXCEPTION_STATUS_IS(eDSInvalidRecordType))
{
[localException raise];
}
NS_ENDHANDLER
return list;
}
- (NSArray*) getPossibleCompletionsFor:(NSString*)inPrefix
{
NSMutableArray* possibleCompletions = nil;
NSArray* currentList = [self getList];
if (currentList != nil)
{
inPrefix = [inPrefix lowercaseString];
possibleCompletions = [NSMutableArray array];
NSEnumerator* listEnum = [currentList objectEnumerator];
NSString* currentItem = nil;
while (currentItem = (NSString*)[listEnum nextObject])
{
if ([[currentItem lowercaseString] hasPrefix:inPrefix])
[possibleCompletions addObject:currentItem];
}
}
return possibleCompletions;
}
- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword authOnly:(BOOL)inAuthOnly
{
NSAutoreleasePool* pool = [NSAutoreleasePool new];
DSoSearchNode* searchNode = [[_node directory] searchNode];
DSoUser* user = nil;
tDirStatus status = eDSAuthFailed;
NSMutableData* outputData = nil;
NS_DURING
user = [searchNode findUser:inUsername];
if (user != nil) {
status = [[user node] authenticateName:inUsername withPassword:inPassword authOnly:YES];
if (status == eDSNoErr && inAuthOnly == NO) {
outputData = [NSMutableData dataWithLength:sizeof(AuthorizationExternalForm)];
status = [_node customCall:eODCustomCallConfigureGetAuthRef
sendItems:[NSArray arrayWithObjects:inUsername,inPassword,nil]
outputData:outputData];
if (status == eDSNoErr && [outputData length] >= sizeof( AuthorizationExternalForm ) )
{
[outputData getBytes:&_authExternalForm length:sizeof( AuthorizationExternalForm )];
_haveRights = YES;
}
}
}
NS_HANDLER
NS_ENDHANDLER
[pool release];
return status;
}
- (tDirStatus) createKey:(NSString*)inKey withValues:(NSArray*)inValues
{
if (inValues == nil && [self cd:inKey] != nil)
{
return eDSNoErr;
}
else
{
return eDSPermissionError;
}
}
- (PathItem*) cd:(NSString*)dest
{
DSoRecord *rec = nil;
PathRecordConfig *p = nil;
if (dest != nil && [dest length] > 0)
{
NS_DURING
rec = [_node findRecord:dest ofType:[_recordType UTF8String]];
NS_HANDLER
if (gHACK && DS_EXCEPTION_STATUS_IS(eDSRecordNotFound)) // Hack to force read-only entry into a record which doesn't implement dsOpenRecord()
rec = [[[DSoRecord alloc] initInNode:_node
type:[_recordType UTF8String] name:dest create:NO] autorelease];
else
[localException raise];
NS_ENDHANDLER
if (rec != nil)
p = [[PathRecordConfig alloc] initWithRecord:rec];
[p setAuthExternalForm:&_authExternalForm];
return [p autorelease];
}
else
return nil;
}
- (tDirStatus) read:(NSString*)inPath keys:(NSArray*)inKeys
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
tDirStatus status = eDSRecordNotFound;
NSArray* foundRecords = nil;
NSMutableDictionary* foundRecord = nil;
NSUInteger recordIndex = 0;
NSUInteger recordCount = 0;
NS_DURING
if ([_recordType hasPrefix:@kDSStdRecordTypePrefix])
foundRecords = [_node findRecordNames:@kDSRecordsAll andAttributes:[NSArray arrayWithObject:@kDSAttributesAll]
ofType:[_recordType UTF8String] matchType:eDSExact];
else
foundRecords = [_node findRecordNames:@kDSRecordsAll andAttributes:[NSArray arrayWithObject:@kDSAttributesAll]
ofType:[_recordType UTF8String] matchType:eDSExact];
NS_HANDLER
[localException retain];
[pool release];
[[localException autorelease] raise];
NS_ENDHANDLER
recordCount = [foundRecords count];
for (recordIndex = 0; recordIndex < recordCount; recordIndex++)
{
NSDictionary *record = [foundRecords objectAtIndex:recordIndex];
NSArray *values = [record objectForKey:@kDSNAttrRecordName];
if ([values count] > 0 && [values containsObject:inPath])
{
foundRecord = [[record mutableCopy] autorelease];
status = eDSNoErr;
break;
}
}
if (foundRecord != nil)
{
if ([inKeys count] > 0)
{
//NSArray* niceKeys = prefixedAttributeKeysWithNode([_record node], inKeys);
NSMutableDictionary* attribsFiltered = [NSMutableDictionary dictionary];
for (NSString *key in inKeys) {
NSString *niceKey = nil;
if ([key hasPrefix:@kDSStdAttrTypePrefix] || [key hasPrefix:@kDSNativeAttrTypePrefix])
{
niceKey = key;
}
else if ([key isEqualToString:@kDSAttributesStandardAll])
{
for (NSString *aKey in [foundRecord allKeys])
{
if ([aKey hasPrefix:@kDSStdAttrTypePrefix]) {
[attribsFiltered setObject:[foundRecord objectForKey:aKey] forKey:aKey];
}
}
continue;
}
else if ([key isEqualToString:@kDSAttributesNativeAll])
{
for (NSString *aKey in [foundRecord allKeys])
{
if ([aKey hasPrefix:@kDSNativeAttrTypePrefix]) {
[attribsFiltered setObject:[foundRecord objectForKey:aKey] forKey:aKey];
}
}
continue;
}
else
{
niceKey = [@kDSStdAttrTypePrefix stringByAppendingString:key];
if ([foundRecord objectForKey: niceKey] == nil && ![[[_node directory] standardAttributeTypes] containsObject:niceKey])
niceKey = [@kDSNativeAttrTypePrefix stringByAppendingString:key];
}
id value = [foundRecord objectForKey:niceKey];
if (value != nil) {
[attribsFiltered setObject:value forKey:niceKey];
}
}
foundRecord = [[attribsFiltered copy] autorelease];
}
[self printDictionary:foundRecord withRequestedKeys:inKeys];
}
[pool release];
return status;
}
@end

7
dscl/PlugInManager.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#import "PathManager.h"
bool dscl_PlugInDispatch(int argc, char* argv[], BOOL interactive, u_int32_t dsid, PathManager* engine, tDirStatus* status);
void dscl_PlugInShowUsage(FILE* fp);

346
dscl/PlugInManager.m Normal file
View File

@ -0,0 +1,346 @@
#import "PlugInManager.h"
#import <DSObjCWrappers/DSObjCWrappers.h>
#import "NSStringEscPath.h"
#import "dsclPlugInHelper.h"
#import "PathRecord.h"
#import "PathDirService.h"
#import "PathNode.h"
#import "PathRecordType.h"
static NSString* kPlugInFolders[] = { @"~/Library/DirectoryServices/dscl/", @"/System/Library/DirectoryServices/dscl/", nil };
static NSString* kPlugInSuffix = @"dsclext";
@protocol DSCLPlugIn
-(void) processArguments:(char**) argv numArgs:(int) argc info:(DSCLPlugInHelper*) helper returningStatus:(int*) statusP wasHandled:(BOOL*) handledP;
-(void) dumpHelpToFile:(FILE*) fp forCommand:(NSString*) cmd;
@end
//--------------------------------------------------------------------------------
static NSArray* GetPlugins()
{
static NSArray* gPlugins = nil; // will contain a list of top-level classes of the plugins, not a list of NSBundles
// If the plugins have already been loaded, just return the list
if (gPlugins)
return gPlugins;
// Build a list and assign it immediately to the global. That way if we get any error, we won't try building the list again
NSMutableArray* list = [[NSMutableArray arrayWithCapacity:1] retain];
gPlugins = list;
// Look for and load any plugins
NSMutableArray* listOfAlreadyLoaded = [NSMutableArray arrayWithCapacity:0]; // keep track of the names of plugins we've already loaded
NSString** baseFolderP = kPlugInFolders;
while (*baseFolderP)
{
NSString* baseFolder = [*baseFolderP stringByExpandingTildeInPath];
baseFolderP++;
NSArray* dirContents = [[NSFileManager defaultManager] directoryContentsAtPath: baseFolder];
unsigned int numInDir = [dirContents count];
unsigned int i;
for (i=0; i<numInDir; i++)
{
NSString* name = [dirContents objectAtIndex:i];
NSString* suffix = [name pathExtension];
if ([suffix isEqualToString: kPlugInSuffix] == false) // make sure this is a bundle type we know about
continue;
// Check to see if we've already loaded a plugin with this name. This is to allow overrides to be placed in the home directory
// that will take precedence over like-named plugins in the system /Library directory
if ([listOfAlreadyLoaded containsObject: name])
{
// NSLog(@"Skipping '%@' in '%@' because a plugin with that name was already loaded.", name, baseFolder);
continue;
}
NSString* fullPath = [baseFolder stringByAppendingPathComponent: name];
NSBundle* bundle = [NSBundle bundleWithPath:fullPath];
if (bundle == nil)
{
NSLog(@"Unable to generate bundle for: %@", fullPath);
continue;
}
if ([bundle load] == false)
{
NSLog(@"Unable to load bundle for: %@", fullPath);
continue;
}
id topObj = [[[bundle principalClass] alloc] init];
if (topObj == nil)
{
NSLog(@"Unable to instantiate principalClass for: %@", fullPath);
continue;
}
[list addObject:topObj];
[listOfAlreadyLoaded addObject: name];
}
}
return gPlugins;
}
//--------------------------------------------------------------------------------
@implementation DSCLPlugInHelper
//--------------------------------------------------------------------------------
-(id) init
{
if ((self = [super init]) == nil)
return nil;
return self;
}
//--------------------------------------------------------------------------------
-(void) dealloc
{
[fEngine release];
[super dealloc];
}
//--------------------------------------------------------------------------------
-(BOOL) isInteractive
{
return fInteractive;
}
//--------------------------------------------------------------------------------
-(BOOL) rootIsDirService
{
// Purpose of this method is so that plugin can determine whether the top level item
// in the path is a directory service or a node. In the former case, paths should be
// of the form "/LDAPv3/127.0.0.1/Users" while in the latter, they should just be "/Users"
id lastObj = [[fEngine stack] lastObject];
if (lastObj == nil)
return NO;
return [lastObj isKindOfClass:[PathDirService class]];
}
//--------------------------------------------------------------------------------
-(void) currDirRef:(tDirReference*) dirRef nodeRef:(tDirNodeReference*) nodeRef recType:(NSString**) recType recName:(NSString**) recName
{
*dirRef = 0;
*nodeRef = 0;
*recType = nil;
*recName = nil;
id lastObj = [[fEngine stack] lastObject];
if (lastObj == nil)
return;
/*
Hierarchy of stack objects appears to be:
PathDirService ()
PathNode (NetInfo/root) or, 1 each for (LDAPv3) and (127.0.0.1)
PathRecordType (Users)
PathRecord (mcxtest)
*/
DSoDirectory* dir = nil;
DSoNode* node = nil;
if ([lastObj isKindOfClass:[PathDirService class]])
{
PathDirService* obj = (PathDirService*) lastObj;
dir = [obj directory]; // via DSHacks.mm
}
else if ([lastObj isKindOfClass:[PathNode class]])
{
PathNode* obj = (PathNode*) lastObj;
node = [obj node]; // via DSHacks.mm
dir = [node directory];
}
else if ([lastObj isKindOfClass:[PathRecordType class]])
{
PathRecordType* obj = (PathRecordType*) lastObj;
node = [obj node]; // via DSHacks.mm
dir = [node directory];
*recType = [obj recordType]; // via DSHacks.mm
*recName = nil;
}
else if ([lastObj isKindOfClass:[PathRecord class]])
{
PathRecord* pathRec = (PathRecord*) lastObj;
DSoRecord* rec = [pathRec record]; // via DSHacks.mm
node = [rec node];
dir = [node directory];
const char* cRecType = [rec getType];
*recType = cRecType ? [NSString stringWithUTF8String: cRecType] : nil; // don't really expect cRecType to be nil here
*recName = [rec getName];
}
if (dir)
*dirRef = [dir verifiedDirRef]; // ?? or just -[dsDirRef] ??
if (node)
*nodeRef = [node dsNodeReference];
}
//--------------------------------------------------------------------------------
-(void) backupStack
{
[fEngine backupStack];
}
//--------------------------------------------------------------------------------
-(void) restoreStack
{
[fEngine restoreStack];
}
//--------------------------------------------------------------------------------
-(void) cd:(NSString*) path
{
[fEngine cd:path];
}
//--------------------------------------------------------------------------------
-(NSString*) cwdAsDisplayString
{
return [[fEngine cwd] unescapedString];
}
//--------------------------------------------------------------------------------
-(NSString*) getStackDescription
{
// For debugging only
return [[fEngine stack] description];
}
//--------------------------------------------------------------------------------
@end // DSCLPlugInHelper
@interface DSCLPlugInHelper(Private)
-(void) setEngine:(PathManager*) engine setInteractive:(BOOL) interactive;
@end
//--------------------------------------------------------------------------------
@implementation DSCLPlugInHelper(Private)
-(void) setEngine:(PathManager*) engine setInteractive:(BOOL) interactive
{
fInteractive = interactive;
if (fEngine != engine)
{
[fEngine release];
fEngine = [engine retain];
}
}
@end // DSCLPlugInHelper(Private)
//--------------------------------------------------------------------------------
bool dscl_PlugInDispatch(int argc, char* argv[], BOOL interactive, u_int32_t dsid, PathManager* engine, tDirStatus* status)
{
BOOL handled = false;
*status = eDSNoErr;
NS_DURING
// Try dispatching the command to various plugins
// [NSException raise:@"DSCL" format:@"Test Exception"];
NSArray* list = GetPlugins();
unsigned int numPlugins = [list count];
if (numPlugins > 0)
{
DSCLPlugInHelper* helper = [[[DSCLPlugInHelper alloc] init] autorelease];
[helper setEngine:engine setInteractive:interactive];
unsigned int i;
for (i=0; i<numPlugins; i++)
{
id plugin = [list objectAtIndex:i];
if ([plugin respondsToSelector:@selector(processArguments:numArgs:info:returningStatus:wasHandled:)])
{
id<DSCLPlugIn> dsclPlugin = plugin;
[dsclPlugin processArguments:argv numArgs:argc info:helper returningStatus:status wasHandled:&handled];
if (handled)
break;
}
}
}
NS_HANDLER
char *cmd = argv[0];
// This code is stolen from dscl_cmd()
[engine restoreStack]; // In case the error happened before the stack was restored.
if ([[localException name] isEqualToString:@"DSCL"])
{
printf("%s: %s\n", cmd, [[localException reason] UTF8String]);
*status = eDSUnknownNodeName;
}
else if ([localException isKindOfClass:[DSoException class]])
{
printf("%s: DS error: %s\n", cmd, [(DSoException*)localException statusCString]);
*status = -[(DSoException*)localException status];
}
else
[localException raise];
NS_ENDHANDLER
return handled;
}
//--------------------------------------------------------------------------------
void dscl_PlugInShowUsage(FILE* fp)
{
NS_DURING
NSArray* list = GetPlugins();
unsigned int numPlugins = [list count];
unsigned int i;
for (i=0; i<numPlugins; i++)
{
id plugin = [list objectAtIndex:i];
if ([plugin respondsToSelector:@selector(dumpHelpToFile:forCommand:)])
{
id<DSCLPlugIn> dsclPlugin = plugin;
fprintf(fp, "\n");
[dsclPlugin dumpHelpToFile:fp forCommand:NULL]; // dump entire help
}
}
NS_HANDLER
fprintf(fp, "\n** Error showing usage from plugins **\n");
NS_ENDHANDLER
}
//--------------------------------------------------------------------------------

389
dscl/dscl.1 Normal file
View File

@ -0,0 +1,389 @@
.Dd August 25, 2003
.Dt dscl 1
.Os MacOSX
.Sh NAME
.Nm dscl
.Nd Directory Service command line utility
.Sh SYNOPSIS
.Nm
.Op options
.Op Ar datasource Op command
.Pp
options:
.Bl -tag -width "-P password" -compact -offset indent
.It Fl p
prompt for password
.It Fl u Ar user
authenticate as user
.It Fl P Ar password
authentication password
.It Fl f Ar filepath
targeted local node database file path
.It Fl raw
don't strip off prefix from DirectoryService API constants
.It Fl plist
print out record(s) or attribute(s) in XML plist format
.It Fl url
print record attribute values in URL-style encoding
.It Fl q
quiet - no interactive prompt
.El
.Pp
commands:
.Bl -inset -compact -offset indent
.It Fl read Op Ar path Op Ar key Li "..."
.It Fl readall Op Ar path Op Ar key Li "..."
.It Fl readpl Ar path Ar key Ar plist_path
.It Fl readpli Ar path Ar key Ar value_index Ar plist_path
.It Fl list Ar path Op key
.It Fl search Ar path key val
.It Fl create Ar record_path
.Oo
.Ar key
.Op Ar val Li "..."
.Oc
.It Fl createpl Ar record_path Ar key Ar plist_path Ar val1 Op Ar val2 Li "..."
.It Fl createpli Ar record_path Ar key Ar value_index Ar plist_path Ar val1 Op Ar val2 Li "..."
.It Fl append Ar record_path key val Li "..."
.It Fl merge Ar record_path key val Li "..."
.It Fl delete Ar path
.Oo
.Ar key Op Ar val Li "..."
.Oc
.It Fl deletepl Ar record_path Ar key Ar plist_path Op val Li "..."
.It Fl deletepli Ar record_path Ar key Ar value_index Ar plist_path Op val Li "..."
.It Fl change Ar record_path key old_val new_val
.It Fl changei Ar record_path key val_index new_val
.It Fl diff Ar path1 Ar path2 Op Ar key Li "..."
.It Fl passwd Ar user_path
.Oo
.Ar new_password | old_password new_password
.Oc
.El
.Pp
available only in interactive mode:
.Bl -inset -compact -offset indent
.It Fl cd Ar dir
.It Fl pushd Op Ar dir
.It Fl popd
.It Fl auth Op Ar user Op Ar password
.It Fl authonly Op Ar user Op Ar password
.It Fl quit
.El
.Pp
.Sh DESCRIPTION
.Nm
is a general-purpose utility for operating on Directory Service directory nodes. Its commands allow one to create, read, and manage Directory Service data. If invoked without any commands,
.Nm
runs in an interactive mode, reading commands from standard input. Interactive processing is terminated by the
.Ar quit
command. Leading dashes ("-") are optional for all commands.
.Pp
.Nm
operates on a datasource specified on the command line. This may be a node name or a Mac OS X Server (10.2 or later) host specified by DNS hostname or IP address. Node names may be absolute paths beginning with a slash ("/"), or relative domain paths beginning with a dot (".") character, which specifies the local domain, or "..", specifying the local domain's parent. If the hostname or IP address form is used then the user must specify the
.Fl u
option and either the
.Fl P
of
.Fl p
options to specify an administrative user and password on the remote host to authenticate with to the remote host. The exception to this is if "localhost" is specified. Passing passwords on the command line is inherently insecure and can cause password exposure. For better security do not provide the password as part of the command and you will be securely prompted.
.Pp
The datasource may also be specified as "localonly" in which case a separate DirectoryService daemon process is activated which contains only the Local plugin for use by dscl. If no file path is provided then access goes only to the registered local nodes on the system. However, if the
.Fl f
option is specified then access is added to the local node "/Local/Target" which points to the database located at the provided filepath. One example is to provide the filepath of "/Volumes/Build100/var/db/dslocal/nodes/Default" and then access to that database is provided via the nodename "/Local/Target".
.Pp
.Sh PATH SPECIFICATION
There are two modes of operation when specifying paths to operate on. The two modes correspond to whether the datasource is a node or a host. In the case of specifying a node, the top level of paths will be record types. Example top level paths would be:
.Pp
.Dl /Users/alice
.Dl /Groups/admin
.Pp
In the case of specifying a host as a data source, the top level of paths correspond to Open Directory plug-ins and Search Paths. One can specify the plug-in to traverse to a node name, after which the paths are equivalent to the former usage. The following might be the equivalent paths as the above paths:
.Pp
.Dl /NetInfo/root/Users/alice
.Dl /LDAPv3/10.0.1.42/Groups/admin
.Pp
If path components contain keys or values with embedded slash characters, the slash characters must be escaped with a leading backslash character. Since the shell also processes escape characters, an extra backslash is required to correctly specify an escape. For example, to read a mount record with the name "ldapserver:/Users" in the "/Mounts" path, the following path would be used:
.Pp
.Dl Nm Li "\& ." Fl read Li "/Mounts/ldaphost:\\e\\&/Users"
.Pp
All pathnames are case-sensitive.
.Sh COMMANDS
The action of each command is described below. Some commands have aliases. For example, "cat" and "." are aliases for "read". Command aliases are listed in parentheses.
.Ss read (cat .)
Usage: read
.Op Ar path Op Ar key Li "..."
.Pp
Prints a directory. The property key is followed by colon, then a space-separated list of the values for that property. If any value contains embedded spaces, the list will instead be displayed one entry per line, starting on the line after the key.
.Pp
If The
.Fl raw
flag for raw output has been given, then
.Sx read
prints the full DirectoryService API constant for record and attribute types.
.Pp
If the
.Fl url
flag has been specified then printed record path attribute values are encoded in the style of URLs. This is useful if a script or program is trying to process the output since values will not have any spaces or other control characters.
.Ss readall
Usage: readall
.Op Ar path Op Ar key Li "..."
.Pp
.Sx readall
prints all the records of a given type. The output of readall is formatted in the same way as
.Sx read
with a "-" on a line as a delimeter between records.
.Ss readpl
Usage: readpl
.Ar path Ar key Ar plist_path
.Pp
Prints the contents of
.Ar plist_path "."
The
.Ar plist_path
is followed by a colon, then a whitespace, and then the value for the path.
.Pp
If the
.Ar plist_path
is the key for a dictionary or array, the contents of it are displayed in plist form after the
.Ar plist_path "."
If
.Ar plist_path
is the key for a string, number, bool, date, or data object, only the value is printed out after the
.Ar plist_path "."
.Ss readpli
Usage: readpli
.Ar path Ar key Ar value_index Ar plist_path
.Pp
Prints the contents of
.Ar plist_path
for the plist at
.Ar value_index
of the key.
The
.Ar plist_path
is followed by a colon, then a whitespace, and then the value for the path.
.Pp
If the
.Ar plist_path
is the key for a dictionary or array, the contents of it are displayed in plist form after the
.Ar plist_path "."
If
.Ar plist_path
is the key for a string, number, bool, date, or data object, only the value is printed out after the
.Ar plist_path "."
.Ss list (ls)
Usage: list
.Ar path
.Pp
Lists the subdirectories of the given directory. Subdirectories are listed one per line. In the case of listing a search path, the names are preceded by an index number that can act as a shortcut and used in place of the name when specifying a path.
.Pp
When used in interactive mode, the path is optional. With no path given, the current directory will be used.
.Ss search
.Ar path key val
.Pp
Searches for records that match a pattern. The search is rooted at the given path. The path may be a node path or a record type path. Valid keys are Directory Service record attribute types.
.Ss create (mk)
Usage: create
.Ar record_path
.Oo Ar key
.Op Ar val Li "..."
.Oc
.Pp
Creates a record, property, or value. If only a record path is given, the
.Sx create
command will create the record if it does not exist. If a key is given, then a property with that key will be created.
.Pp
WARNING - If a property with the given key already exists, it will be destroyed and a new property will be created in its place. To add values to an existing property, use the
.Sx append
or
.Sx merge
commands.
.Pp
If values are included in the command, these values will be set for the given key.
.Pp
NOTE - Not all directory nodes support a property without a value. An error will be given if you attempt to create a property with no value in such a directory node.
.Ss createpl
Usage: createpl
.Ar record_path Ar key Ar plist_path Ar val1 Op Ar val2 Li "..."
.Pp
Creates a string, or array of strings at
.Ar plist_path "."
.Pp
If you are creating a value at the root of a plist that is an array, simply use "0" as the
.Ar plist_path "."
.Pp
If only
.Ar val1
is specified, a string will be created at
.Ar plist_path "."
If
.Ar val1 val2 Li "..."
are specified, an array of strings will be created at
.Ar plist_path "."
.Pp
WARNING - If a value with the given
.Ar plist_path
already exists, it will be destroyed and a new value will be created in its place.
.Ss createpli
Usage: createpli
.Ar record_path Ar key Ar value_index Ar plist_path Ar val1 Op Ar val2 Li "..."
.Pp
Creates a string, or array of strings at
.Ar plist_path
for the plist at
.Ar value_index
of the key.
.Pp
If you are creating a value at the root of a plist that is an array, simply use "0" as the
.Ar plist_path "."
.Pp
If only
.Ar val1
is specified, a string will be created at
.Ar plist_path "."
If
.Ar val1 val2 Li "..."
are specified, an array of strings will be created at
.Ar plist_path "."
.Pp
WARNING - If a value with the given
.Ar plist_path
already exists, it will be destroyed and a new value will be created in its place.
.Ss append
Usage: append
.Ar record_path key val Li "..."
.Pp
Appends one or more values to a property in a given record. The property is created if it does not exist.
.Ss merge
Usage: merge
.Ar record_path key val Li "..."
.Pp
Appends one or more values to a property in a given directory if the property does not already have those values. The property is created if it does not exist.
.Ss change
Usage: change
.Ar record_path key old_val new_val
.Pp
Replaces the given old value in the list of values of the given key with the new value in the specified record.
.Ss changei
Usage: changei
.Ar path key index val
.Pp
Replaces the value at the given index in the list of values of the given key with the new value in the specified record.
.Ar index
is an integer value. An index of 1 specifies the first value. An index greater than the number of values in the list will result in an error.
.Ss diff
Usage: diff
.Ar path1 path2 key Li "..."
.Pp
Compares the data from path1 and path2 looking at the specified keys (or all if no keys are specified).
.Ss delete (rm)
Usage: delete
.Ar path
.Oo
.Ar key Op Ar val Li "..."
.Oc
.Pp
Delete a directory, property, or value. If a directory path is given, the
.Sx delete
command will delete the directory. This can only be used on record type and record paths. If a key is given, then a property with that key will be deleted. If one or more values are given, those values will be removed from the property with the given key.
.Ss deletepl
Usage: deletepl
.Ar record_path Ar key Ar plist_path Op val Li "..."
.Pp
Deletes a value in a plist. If no values are given
.Sx deletepl
deletes the
.Ar plist_path "."
If one or more values are given,
.Sx deletepl
deletes the values within
.Ar plist_path "."
.Ss deletepli
Usage: deletepli
.Ar record_path Ar key Ar value_index Ar plist_path Op val Li "..."
.Pp
Deletes a value for the plist at
.Ar value_index
of the key. If no values are given
.Sx deletepli
deletes the
.Ar plist_path "."
If one or more values are given,
.Sx deletepli
deletes the values within
.Ar plist_path "."
.Ss passwd
Usage: passwd
.Ar user_path
.Op Ar new_pasword | old_password new_pasword
.Pp
Changes a password for a user. The user must be specified by full path, not just a username. If you are authenticated to the node (either by specifying the
.Fl u
and
.Fl P
flags or by using the auth command when in interactive node) then you can simply specify a new password. If you are not authenticated then the user's old password must be specified. If passwords are not specified while in interactive mode, you will be prompted for them. Passing these passwords on the command line is inherently insecure and can cause password exposure. For better security do not provide the password as part of the command and you will be securely prompted.
.Sh INTERACTIVE COMMANDS
.Ss cd
Usage: cd dir
.Pp
Sets the current directory. Path names for other
.Nm
commands may be relative to the current directory.
.Ss pushd (pd)
Usage: pushd path
.Pp
Similar to the pushd command commonly found in Unix shells. When a path is specified it sets the current directory while pushing the previous directory on to the directory stack. If no path is specified it exchanges the top two elements of the directory stack. It will also print the final directory stack.
.Ss popd
Usage: popd
.Pp
Pops the directory stack and returns to the new top directory. It will also print the final directory stack.
.Ss auth (su)
Usage: auth
.Op Ar user Op Ar password
.Pp
Authenticate as the named user, or as "root" if no user is specified. If a password is supplied, then that password is used for authentication, otherwise the command prompts for a password.
.Pp
If
.Nm
is run in host mode, then when this command is run the current directory must be in the subdirectories of a node.
.Ss authonly
Usage: authonly
.Op Ar user Op Ar password
.Pp
Used to verify the password of a named user, or of "root" if no user is specified. If a password is supplied, then that password is used for authentication, otherwise the command prompts for a password.
.Pp
If
.Nm
is run in host mode, then when this command is run the current directory must be in the subdirectories of a node.
.Ss quit (q)
Usage: quit
.Pp
Ends processing of interactive commands and terminates the program.
.Ss command history
The up and down arrow keys will scan through the command history.
.Ss tab completion
When pathnames are being typed, pressing the tab key will result in a search to auto-complete the typed partial subdirectory name. It will also attempt to correct capitilization in the process.
.Sh EXAMPLES
.Pp
.Bl -tag -width -indent \" Differs from above in tag removed
.It Fl "view a record in the local directory node"
dscl . -read /Users/www
.It Fl "create or replace the UserShell attribute value for the www user record"
dscl . -create /Users/www UserShell /usr/bin/false
.It Fl "create or replace the test key of the mcx_application_data:loginwindow plist value for the MCXSettings attribute of the user1 user record"
dscl . -createpl /Users/user1 MCXSettings mcx_application_data:loginwindow:test value
.It Fl "list the uniqueID values for all user records on a given node"
dscl /LDAPv3/ldap.company.com -list /Users UniqueID
.It Fl "append a value that has spaces in it"
dscl . -append /Users/www Comment "This is a comment"
.El \" Ends the list
.Pp
.Sh DIAGNOSTICS
.Pp
.Nm
will return -1 (255) on error.
.Pp
.Sh SEE ALSO
.Xr DirectoryService 8 ,
.Xr DirectoryServiceAttributes 7

1475
dscl/dscl.m Normal file

File diff suppressed because it is too large Load Diff

25
dscl/dsclPlugInHelper.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#import <DirectoryService/DirServicesTypes.h>
@class PathManager;
@interface DSCLPlugInHelper : NSObject
{
@private
BOOL fInteractive;
PathManager* fEngine;
}
-(BOOL) isInteractive;
-(void) currDirRef:(tDirReference*) dirRef nodeRef:(tDirNodeReference*) nodeRef recType:(NSString**) recType recName:(NSString**) recName;
// PathManager stack-related access
-(void) backupStack;
-(void) restoreStack;
-(void) cd:(NSString*) path;
-(NSString*) cwdAsDisplayString;
-(BOOL) rootIsDirService; // to differentiate whether paths should be "/LDAPv3/127.0.0.1/Users" or just "/Users"
// For debugging only
-(NSString*) getStackDescription;
@end

129
dsconfigldap/dsconfigldap.1 Normal file
View File

@ -0,0 +1,129 @@
.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
.\"See Also:
.\"man mdoc.samples for a complete listing of options
.\"man mdoc for the short list of editing options
.\"/usr/share/misc/mdoc.template
.Dd April 24 2010 \" DATE
.Dt dsconfigldap 1 \" Program name and manual section number
.Os Mac OS X
.Sh NAME \" Section Header - required - don't modify
.Nm dsconfigldap
.Nd LDAP server configuration/binding add/remove tool.
.Sh SYNOPSIS \" Section Header - required - don't modify
.Nm
.Op Fl fvixsgmeS
.Fl a Ar servername
.Op Fl n Ar configname
.Op Fl c Ar computerid
.Op Fl u Ar username
.Op Fl p Ar password
.Op Fl l Ar username
.Op Fl q Ar password
.Pp
.Nm
.Op Fl fviS
.Fl r Ar servername
.Op Fl u Ar username
.Op Fl p Ar password
.Op Fl l Ar username
.Op Fl q Ar password
.Pp
options:
.Bl -tag -width "1234567890123" -compact -offset indent
.It Fl f
force authenticated binding/unbinding
.It Fl v
verbose logging to stdout
.It Fl i
prompt for passwords as required
.It Fl x
choose SSL connection
.It Fl s
enforce secure authentication only
.It Fl g
enforce packet signing security policy
.It Fl m
enforce man-in-middle security policy
.It Fl e
enforce encryption security policy
.It Fl S
do not update search policies
.It Fl h
display usage statement
.It Fl a Ar servername
add config of servername
.It Fl r Ar servername
remove config of servername
.It Fl n Ar configname
name given to LDAP server config
.It Fl c Ar computerid
name used if binding to directory
.It Fl u Ar username
privileged network username
.It Fl p Ar password
privileged network user password
.It Fl l Ar username
local admin username
.It Fl q Ar password
local admin password
.El
.Pp
.Sh DESCRIPTION \" Section Header - required - don't modify
.Nm
allows addition or removal of LDAP server configurations. Presented below is a discussion of possible parameters. Usage has three intents: add server config, remove server config, or display help.
.Pp \" Inserts a space
Options list and their descriptions:
.Bl -tag -width -indent \" Differs from above in tag removed
.It Fl f
Bindings will be established or dropped in conjunction with the addition or removal of the LDAP server configuration.
.It Fl v
This enables the logging to stdout of the details of the operations. This can be redirected to a file.
.It Fl i
You will be prompted for a password to use in conjunction with a specified username.
.It Fl s
This ensures that no clear text passwords will be sent to the LDAP server during authentication. This will only be enabled if the server supports non-cleartext methods.
.It Fl e
This ensures that if the server is capable of supporting encryption methods (i.e., SSL or Kerberos) that encryption will be enforced at all times via policy.
.It Fl m
This ensures that man-in-the-middle capabilities will be enforced via Kerberos, if the server supports the capability.
.It Fl g
This ensures that packet signing capabilities will be enforced via Kerberos, if the server supports the capability.
.It Fl x
Connection to the LDAP server will only be made over SSL.
.It Fl S
Will skip updating the search policies.
.It Fl h
Display usage statement.
.It Fl a Ar servername
This is either the fully qualified domain name or correct IP address of the LDAP server to be added to the DirectoryService LDAPv3 configuration.
.It Fl r Ar servername
This is either the fully qualified domain name or correct IP address of the LDAP server to be removed from the DirectoryService LDAPv3 configuration.
.It Fl n Ar configname
This is the UI configuration label that is to be given the LDAP server configuration.
.It Fl c Ar computerid
This is the name to be used for directory binding to the LDAP server. If none is given the first substring, before a period, of the hostname (the defined environment variable "HOST") is used.
.It Fl u Ar username
Username of a privileged network user to be used in authenticated directory binding.
.It Fl p Ar password
Password for the privileged network user. This is a less secure method of providing a password, as it may be viewed via process list. For stronger security leave the option off and you will be prompted for a password.
.It Fl l Ar username
Username of a local administrator.
.It Fl q Ar password
Password for the local administrator. This is a less secure method of providing a password, as it may be viewed via process list. For stronger security leave the option off and you will be prompted for a password.
.El \" Ends the list
.Pp \" Inserts a space
.Sh EXAMPLES
.Nm
-a ldap.company.com
.Pp
The LDAP server config for the LDAP server myldap.company.com will be added. If authenticated directory binding is required by the LDAP server, then this call will fail. Otherwise, the following parameters configname, computerid, and local admin name will respectively pick up these defaults: ip address of the LDAP servername, substring up to first period of fully qualified hostname, and username of the user in the shell this tool was invoked.
.Pp
.Nm
-r ldap.company.com
.Pp
The LDAP server config for the LDAP server myldap.company.com will be removed but not unbound since no network user credentials were supplied. The local admin name will be the username of the user in the shell this tool was invoked.
.Pp
.Sh SEE ALSO
.Pp
opendirectoryd(8), odutil(1)
.Pp

472
dsconfigldap/main.m Normal file
View File

@ -0,0 +1,472 @@
/*
* Copyright (c) 2004-2010 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header dsconfigldap
*/
#include <Security/Authorization.h>
#include <SystemConfiguration/SCDynamicStore.h>
#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
#include <OpenDirectory/OpenDirectory.h>
#include <OpenDirectory/OpenDirectoryPriv.h>
#include <OpenDirectoryConfig/OpenDirectoryConfig.h>
#include <getopt.h>
#include <sysexits.h>
#include "dstools_version.h"
#pragma mark -
#pragma mark Functions
static void
usage(void)
{
const char *progname = getprogname();
printf("dsconfigldap: Add or remove LDAP server configurations\n"
"Version %s\n"
"Usage: %s -h\n"
"Usage: %s [-fvixsgemS] -a servername [-n configname] [-c computerid]\n"
" [-u username] [-p userpassword] [-l localusername]\n"
" [-q localuserpassword]\n"
"Usage: %s [-fvi] -r servername [-u username] [-p password]\n"
" [-l localusername] [-q localuserpassword]\n"
" -f force authenticated bind/unbind\n"
" -v log details\n"
" -i prompt for passwords\n"
" -s enforce not using cleartext authentication via policy\n"
" -e enforce use of encryption capabilities via policy\n"
" -m enforce use of man-in-middle capabilities via policy\n"
" -g enforce use of packet signing capabilities via policy\n"
" -x SSL connection to LDAP server\n"
" -h display usage statement\n"
" -a servername add config of servername\n"
" -r servername remove config of servername, unbind if necessary\n"
" -n configname name to give this new server config\n"
" -c computerid name to use if when binding to directory\n"
" -u username username of a privileged network user for binding\n"
" -p password password of a privileged network user for binding\n"
" -l username username of a local administrator\n"
" -q password password of a local administrator\n"
" -S add to authentication and contact search policy\n\n"
, TOOLS_VERSION, progname, progname, progname);
}
int
main(int argc, char *argv[])
{
NSString *serverName = nil;
NSString *configName = nil;
NSString *computerID = nil;
NSString *userName = nil;
NSString *userPassword = nil;
NSString *localName = nil;
NSString *localPassword = nil;
BOOL appleVersion = NO;
BOOL addServer = NO;
BOOL removeServer = NO;
BOOL force = NO;
BOOL prompt = NO;
BOOL useSSL = NO;
BOOL ybErrors = NO;
BOOL verbose = NO;
BOOL secureAuthOnly = NO;
BOOL defaultUser = NO;
BOOL manInMiddle = NO;
BOOL encryptPackets = NO;
BOOL signPackets = NO;
BOOL updateSearch = YES;
int ch;
int longindex;
const struct option longopts[] = {
{ "appleversion", no_argument, NULL, 1 }, // 0
{ "force", no_argument, NULL, 'f' }, // 1
{ "verbose", no_argument, NULL, 'v' }, // 2
{ "prompt", no_argument, NULL, 'i' }, // 3
{ "secureonly", no_argument, NULL, 's' }, // 4
{ "usessl", no_argument, NULL, 'x' }, // 5
{ "signpackets", no_argument, NULL, 'g' }, // 6
{ "encrypt", no_argument, NULL, 'e' }, // 7
{ "mim", no_argument, NULL, 'm' }, // 9
{ "add", required_argument, NULL, 'a' }, // 10
{ "remove", required_argument, NULL, 'r' }, // 11
{ "comment", required_argument, NULL, 'n' }, // 12
{ "computerid", required_argument, NULL, 'c' }, // 13
{ "netuser", required_argument, NULL, 'u' }, // 15
{ "netpassword", required_argument, NULL, 'p' }, // 14
{ "localuser", required_argument, NULL, 'l' }, // 16
{ "localpassword", required_argument, NULL, 'q' }, // 17
{ "help", no_argument, NULL, 'h' }, // 18
{ "searchpolicy", no_argument, NULL, 'S' }, // 19
{ NULL, 0, NULL, 0 }
};
if (argc < 2) {
usage();
return EX_USAGE;
}
while ((ch = getopt_long(argc, argv, "fvisxgema:r:n:c:u:p:l:q:hS", longopts, &longindex)) != -1) {
switch (ch) {
case 'f':
force = YES;
break;
case 'v':
verbose = YES;
break;
case 'i':
prompt = YES;
break;
case 's':
secureAuthOnly = YES;
break;
case 'x':
useSSL = YES;
break;
case 'g':
signPackets = YES;
break;
case 'e':
encryptPackets = YES;
break;
case 'm':
manInMiddle = YES;
break;
case 'a':
addServer = YES;
serverName = [NSString stringWithUTF8String: optarg];
break;
case 'r':
removeServer = YES;
serverName = [NSString stringWithUTF8String: optarg];
break;
case 'n':
configName = [NSString stringWithUTF8String: optarg];
break;
case 'c':
computerID = [NSString stringWithUTF8String: optarg];
break;
case 'u':
userName = [NSString stringWithUTF8String: optarg];
break;
case 'l':
localName = [NSString stringWithUTF8String: optarg];
break;
case 'p':
userPassword = [NSString stringWithUTF8String: optarg];
memset(optarg, '*', strlen(optarg)); // blank out with *****
break;
case 'q':
localPassword = [NSString stringWithUTF8String: optarg];
memset(optarg, '*', strlen(optarg)); // blank out with *****
break;
case 'S':
updateSearch = NO;
break;
case 'h':
usage();
return 0;
default:
usage();
return EX_USAGE;
}
}
if (appleVersion) {
dsToolAppleVersionExit(argv[0]);
return EX_OK;
}
if (localName == nil) {
const char *envStr = getenv("USER");
if (envStr != NULL) {
defaultUser = YES;
localName = [NSString stringWithUTF8String: envStr];
}
}
if (verbose == YES) {
fprintf(stdout, "dsconfigldap verbose mode\n");
}
if (addServer == YES) {
if (computerID == NULL) {
computerID = [ODCAction calculateSuggestedComputerID];
if (verbose) {
fprintf(stdout, "Using suggested computer ID <%s>\n", [computerID UTF8String]);
}
}
if ([computerID rangeOfString: @" "].location != NSNotFound) {
fprintf(stderr, "Illegal character ' ' in Computer ID, configuration cancelled.\n");
return EX_USAGE;
}
}
if (verbose) {
fprintf(stdout,"Options selected by user:\n");
if (force) {
fprintf(stdout,"Force authenticated (un)binding option selected\n");
}
if (prompt) {
fprintf(stdout,"Interactive password option selected\n");
}
if (secureAuthOnly) {
fprintf(stdout,"Enforce Secure Authentication is enabled\n");
}
if (useSSL) {
fprintf(stdout,"SSL was chosen\n");
}
if (addServer) {
fprintf(stdout,"Add server option selected\n");
}
if (removeServer) {
fprintf(stdout,"Remove server option selected\n");
}
if (serverName) {
fprintf(stdout,"Server name provided as <%s>\n", [serverName UTF8String]);
}
if (configName) {
fprintf(stdout,"LDAP Configuration name provided as <%s>\n", [configName UTF8String]);
}
if (computerID) {
fprintf(stdout,"Computer ID provided as <%s>\n", [computerID UTF8String]);
}
if (userName) {
fprintf(stdout,"Network username provided as <%s>\n", [userName UTF8String]);
}
if (userPassword && !prompt) {
fprintf(stdout,"Network user password provided as <%s>\n", [userPassword UTF8String]);
}
if (localName && !defaultUser) {
fprintf(stdout,"Local username provided as <%s>\n", [localName UTF8String]);
} else if (localName) {
fprintf(stdout,"Local username determined to be <%s>\n", [localName UTF8String]);
} else {
fprintf(stdout,"No Local username determined\n");
}
if (localPassword && !prompt) {
fprintf(stdout,"Local user password provided as <%s>\n", [localPassword UTF8String]);
}
if (manInMiddle) {
fprintf(stdout, "Enforce man-in-the-middle only policy if server supports it.\n");
}
if (updateSearch) {
fprintf(stdout, "Adding new node to search policies\n");
}
if (encryptPackets) {
fprintf(stdout, "Enforce packet encryption policy if server supports it.\n");
}
if (signPackets) {
fprintf(stdout, "Enforce packet signing policy if server supports it.\n");
}
fprintf(stdout, "\n");
}
if (addServer && removeServer) {
fprintf(stdout,"Can't add and remove at the same time.\n");
usage();
return EX_USAGE;
} else {
NSError *error = nil;
//add or remove server correctly selected
if (userName != nil && (userPassword == nil || prompt)) {
char *tmp = getpass("Please enter network user password: ");
userPassword = [NSString stringWithUTF8String: tmp];
}
// we were asked to prompt for password or we had a user provided but no password
if (prompt || (defaultUser == NO && localName != nil && localPassword == nil)) {
char *tmp = getpass("Please enter local user password: ");
localPassword = [NSString stringWithUTF8String: tmp];
}
if (addServer) {
ODCAddODServerAction *action = [ODCAddODServerAction action];
if ([action preflightAuthRightsWithUsername:localName password:localPassword]) {
BOOL promptForAdd = NO;
action.serverName = serverName;
action.clientComputerID = computerID;
action.userName = userName;
action.password = userPassword;
action.addServerToSearchPaths = updateSearch;
action.forceBind = (force != 0);
if (useSSL) {
action.useSSL = YES;
action.autoSSL = NO;
} else {
action.autoSSL = YES;
}
// see if the certs are there first
ODCGetODServerInfoAction *getInfoAction = [[[ODCGetODServerInfoAction alloc] init] autorelease];
getInfoAction.serverName = serverName;
[getInfoAction runSynchronously];
if (getInfoAction.error == nil) {
NSData *certData = [getInfoAction.results objectForKey:ODCServerSSLCertificates];
promptForAdd = ([certData isKindOfClass:[NSData class]] && [certData length] > 0);
}
if (promptForAdd) {
char answer[2];
if (action.useSSL) {
printf("Certificates will be automatically added to your system keychain in order to talk to this server.\n"
"Would you like to continue (y/n)? ");
} else {
printf("Certificates are available for this server.\n"
"Would you like to add them to system keychain automatically (y/n)? ");
}
while (1) {
fgets(answer, sizeof(answer), stdin);
if (tolower(answer[0]) == 'y') {
action.addCertificates = YES;
break;
} else if (tolower(answer[0]) == 'n') {
if (action.useSSL == YES) {
printf("\nOperation cancelled.\n");
return EX_PROTOCOL;
}
break;
} else {
printf("\nPlease answer (y or n): ");
}
}
}
action.manInMiddle = (manInMiddle != 0);
action.secureAuthOnly = (secureAuthOnly != 0);
action.encryptionOnly = (encryptPackets != 0);
action.signPackets = (signPackets != 0);
[action runSynchronously];
error = action.error;
} else {
fprintf(stderr, "Unable to get rights to change configuration\n");
return EX_NOPERM;
}
} else if (removeServer) {
ODCRemoveODServerAction *action = [ODCRemoveODServerAction action];
if ([action preflightAuthRightsWithUsername:localName password:localPassword]) {
action.serverName = serverName;
action.forceUnbind = force;
action.userName = userName;
action.password = userPassword;
action.removeServerFromSearchPaths = updateSearch;
[action runSynchronously];
error = action.error;
} else {
fprintf(stderr, "Unable to get rights to change configuration\n");
return EX_NOPERM;
}
}
switch ([error code]) {
case kODErrorRecordAlreadyExists:
fprintf(stderr, "Computer with the name '%s' already exists\n", [computerID UTF8String]);
return EX_CONFIG;
case kODErrorNodeUnknownHost:
fprintf(stderr, "Could not contact a server at that address.\n");
return EX_NOHOST;
case kODErrorRecordPermissionError:
if (removeServer && !force) {
fprintf(stderr, "Permission denied, to force remove this server use -f\n");
} else {
fprintf(stderr, "Permission error\n");
}
return EX_NOPERM;
case kODErrorCredentialsInvalid:
fprintf(stderr, "Invalid credentials supplied %s server\n", (addServer ? "for binding to the" : "to remove the bound"));
return EX_NOUSER;
case kODErrorCredentialsMethodNotSupported:
fprintf(stderr, "Server does not meet security requirements.\n");
return EX_IOERR;
case kODErrorRecordParameterError:
if (removeServer) {
fprintf( stderr, "Bound need credentials to unbind\n" );
} else {
fprintf( stderr, "Directory is not allowing anonymous queries\n" );
}
return EX_IOERR;
case 0:
break;
default:
fprintf(stderr, "Error: %s (%ld)\n",
[[error localizedFailureReason] UTF8String] ?: "Description unavailable",
(long)[error code]);
return EX_IOERR;
}
}
return EX_OK;
}

View File

@ -0,0 +1,46 @@
.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
.\"See Also:
.\"man mdoc.samples for a complete listing of options
.\"man mdoc for the short list of editing options
.\"/usr/share/misc/mdoc.template
.Dd August 08 2003 \" DATE
.Dt dsenableroot 8 \" Program name and manual section number
.Os Mac OS X
.Sh NAME \" Section Header - required - don't modify
.Nm dsenableroot
.Nd enables or disables the root account.
.Sh SYNOPSIS \" Section Header - required - don't modify
.Nm
.Op Fl d
.Op Fl u Ar username \" [-a path]
.Op Fl p Ar password \" [-a path]
.Op Fl r Ar rootPassword \" [-a path]
.Pp
.Sh DESCRIPTION \" Section Header - required - don't modify
.Nm
sets the password for the root account if enabling the root user account. Otherwise, if disable [-d] is chosen, the root account passwords are removed and the root user is disabled.
.Pp \" Inserts a space
A list of flags and their descriptions:
.Bl -tag -width -indent \" Differs from above in tag removed
.It Fl u Ar username
Username of a user that has administrative privileges on this computer.
.It Fl p Ar password
Password to use in conjunction with the specified username. If this is not specified, you will be prompted for entry.
.It Fl r Ar rootPassword
Password to be used for the root account. If this is not specified for enabling, you will be prompted for entry.
.El \" Ends the list
.Pp
.Sh EXAMPLES
.Pp
.Bl -tag -width -indent \" Differs from above in tag removed
.It Fl "dsenableroot"
Your username will be used and you will be queried for both your password and the new root password to be set to enable the root account.
.It Fl "dsenableroot -d"
Your username will be used and you will be queried for only your password to disable the root account.
.It Fl "dsenableroot -u username -p userpassword -r rootpassword"
The supplied arguments will be used to enable the root account.
.It Fl "dsenableroot -d -u username -p userpassword"
The supplied arguments will be used to disable the root account.
.El \" Ends the list
.Pp
.Pp

View File

@ -0,0 +1,966 @@
/*
* Copyright (c) 2000-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header dsenableroot
* Tool used to enable the root user account.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <CoreFoundation/CoreFoundation.h>
#include <DirectoryService/DirectoryService.h>
#include "dstools_version.h"
SInt32 EnableRootUser( const char *userName, const char *password, const char *rootPassword );
SInt32 EnableRootUser( const char *userName, const char *password, const char *rootPassword )
{
SInt32 siResult = eDSAuthFailed;
tDirReference aDSRef = 0;
tDataBufferPtr dataBuff = nil;
UInt32 nodeCount = 0;
tContextData context = 0;
tDataListPtr nodeName = nil;
tDirNodeReference aSearchNodeRef = 0;
tDataListPtr recName = nil;
tDataListPtr recType = nil;
tDataListPtr attrTypes = nil;
UInt32 recCount = 1;
tAttributeListRef attrListRef = 0;
tRecordEntry *pRecEntry = nil;
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
char* authName = nil;
tDirNodeReference nodeRef = 0;
tDataNodePtr authMethod = nil;
tDataBufferPtr authBuff = nil;
UInt32 length = 0;
char* ptr = nil;
tDataNodePtr recordName = nil;
tDataNodePtr recordType = nil;
tRecordReference recRef = 0;
tDataNodePtr attrName = nil;
tDataNodePtr attrValue = nil;
bool bFoundGUID = false;
if( (userName == nil) || (password == nil) || (rootPassword == nil) )
{
return(siResult);
}
//adapted from try/catch code so using do/while and break
do
{
siResult = dsOpenDirService( &aDSRef );
if ( siResult != eDSNoErr ) break;
dataBuff = dsDataBufferAllocate( aDSRef, 1024 );
if ( dataBuff == nil ) break;
do {
siResult = dsFindDirNodes( aDSRef, dataBuff, nil, eDSAuthenticationSearchNodeName, &nodeCount, &context );
if (siResult == eDSBufferTooSmall) {
UInt32 newSize = dataBuff->fBufferSize * 2;
dsDataBufferDeAllocate(aDSRef, dataBuff);
dataBuff = dsDataBufferAllocate(aDSRef, newSize);
}
} while (siResult == eDSBufferTooSmall);
if ( siResult != eDSNoErr ) break;
if ( nodeCount < 1 ) break;
siResult = dsGetDirNodeName( aDSRef, dataBuff, 1, &nodeName );
if ( siResult != eDSNoErr ) break;
siResult = dsOpenDirNode( aDSRef, nodeName, &aSearchNodeRef );
if ( siResult != eDSNoErr ) break;
if ( nodeName != NULL )
{
dsDataListDeallocate( aDSRef, nodeName );
free( nodeName );
nodeName = NULL;
}
recName = dsBuildListFromStrings( aDSRef, userName, NULL );
recType = dsBuildListFromStrings( aDSRef, kDSStdRecordTypeUsers, NULL );
attrTypes = dsBuildListFromStrings( aDSRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, NULL );
recCount = 1; // only care about first match
do
{
siResult = dsGetRecordList( aSearchNodeRef, dataBuff, recName, eDSExact, recType,
attrTypes, false, &recCount, &context);
if (siResult == eDSBufferTooSmall)
{
UInt32 bufSize = dataBuff->fBufferSize;
dsDataBufferDeAllocate( aDSRef, dataBuff );
dataBuff = nil;
dataBuff = ::dsDataBufferAllocate( aDSRef, bufSize * 2 );
} else if (siResult == eDSNoErr && recCount == 1) {
dsReleaseContinueData(aSearchNodeRef, context);
break;
}
} while (siResult == eDSBufferTooSmall || (siResult == eDSNoErr && context != 0));
//worry about multiple calls (ie. continue data) since we continue until first match or no more searching
if ( (siResult == eDSNoErr) && (recCount > 0) )
{
siResult = ::dsGetRecordEntry( aSearchNodeRef, dataBuff, 1, &attrListRef, &pRecEntry );
if ( (siResult == eDSNoErr) && (pRecEntry != nil) )
{
//index starts at one - should have two entries
for (unsigned int i = 1; i <= pRecEntry->fRecordAttributeCount; i++)
{
siResult = ::dsGetAttributeEntry( aSearchNodeRef, dataBuff, attrListRef, i, &valueRef, &pAttrEntry );
//need to have at least one value - get first only
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
// Get the first attribute value
siResult = ::dsGetAttributeValue( aSearchNodeRef, dataBuff, 1, valueRef, &pValueEntry );
// Is it what we expected
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
nodeName = dsBuildFromPath( aDSRef, pValueEntry->fAttributeValueData.fBufferData, "/" );
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
authName = (char*)calloc( 1, pValueEntry->fAttributeValueData.fBufferLength + 1 );
strncpy( authName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( aDSRef, pValueEntry );
pValueEntry = NULL;
}
}
dsCloseAttributeValueList(valueRef);
if (pAttrEntry != nil)
{
dsDeallocAttributeEntry(aDSRef, pAttrEntry);
pAttrEntry = nil;
}
} //loop over attrs requested
}//found 1st record entry
dsCloseAttributeList(attrListRef);
if (pRecEntry != nil)
{
dsDeallocRecordEntry(aDSRef, pRecEntry);
pRecEntry = nil;
}
}// got records returned
else
{
siResult = eDSAuthUnknownUser;
}
if ( (siResult == eDSNoErr) && (nodeName != nil) && (authName != nil) )
{
siResult = dsOpenDirNode( aDSRef, nodeName, &nodeRef );
if ( siResult != eDSNoErr ) break;
authMethod = dsDataNodeAllocateString( aDSRef, kDSStdAuthNodeNativeClearTextOK );
authBuff = dsDataBufferAllocate( aDSRef, strlen( authName ) + strlen( password ) + 10 );
// 4 byte length + username + null byte + 4 byte length + password + null byte
length = strlen( authName ) + 1;
ptr = authBuff->fBufferData;
::memcpy( ptr, &length, 4 );
ptr += 4;
authBuff->fBufferLength += 4;
::memcpy( ptr, authName, length );
ptr += length;
authBuff->fBufferLength += length;
length = strlen( password ) + 1;
::memcpy( ptr, &length, 4 );
ptr += 4;
authBuff->fBufferLength += 4;
::memcpy( ptr, password, length );
ptr += length;
authBuff->fBufferLength += length;
//if this process is run as root then the session auth is not even required
siResult = dsDoDirNodeAuth( nodeRef, authMethod, false, authBuff, dataBuff, NULL );
dsDataNodeDeAllocate( aDSRef, authMethod );
authMethod = NULL;
dsDataBufferDeAllocate( aDSRef, authBuff );
authBuff = NULL;
if (siResult == eDSNoErr)
{
recordType = dsDataNodeAllocateString( aDSRef, kDSStdRecordTypeUsers );
recordName = dsDataNodeAllocateString( aDSRef, "root" );
//open the root user record
siResult = dsOpenRecord( nodeRef, recordType, recordName, &recRef );
if ( siResult != eDSNoErr ) break;
//need to determine if the GUID already exists
attrName = dsDataNodeAllocateString( aDSRef, kDS1AttrGeneratedUID );
siResult = dsGetRecordAttributeInfo( recRef, attrName, &pAttrEntry );
if (siResult == eDSNoErr)
{
if (pAttrEntry != nil)
{
if (pAttrEntry->fAttributeValueCount > 0 )
{
bFoundGUID = true;
}
dsDeallocAttributeEntry(aDSRef, pAttrEntry);
pAttrEntry = nil;
}
}
if (!bFoundGUID)
{
//calculate a generated UID here
CFUUIDRef myUUID;
CFStringRef myUUIDString;
char genUIDValue[100];
myUUID = CFUUIDCreate(kCFAllocatorDefault);
myUUIDString = CFUUIDCreateString(kCFAllocatorDefault, myUUID);
CFStringGetCString(myUUIDString, genUIDValue, 100, kCFStringEncodingASCII);
CFRelease(myUUID);
CFRelease(myUUIDString);
attrValue = dsDataNodeAllocateString( aDSRef, genUIDValue );
//add the correct GeneratedUID
siResult = dsAddAttribute( recRef, attrName, NULL, attrValue );
if ( siResult != eDSNoErr ) break;
dsDataNodeDeAllocate( aDSRef, attrValue );
attrValue = nil;
}
dsDataNodeDeAllocate( aDSRef, attrName );
attrName = nil;
attrName = dsDataNodeAllocateString( aDSRef, kDSNAttrAuthenticationAuthority );
attrValue = dsDataNodeAllocateString( aDSRef, kDSValueAuthAuthorityShadowHash );
//remove the authentication authority if it already exists - don't check status
dsRemoveAttribute( recRef, attrName );
//add the correct authentication authority
siResult = dsAddAttribute( recRef, attrName, NULL, attrValue );
if ( siResult != eDSNoErr ) break;
dsDataNodeDeAllocate( aDSRef, attrName );
attrName = nil;
dsDataNodeDeAllocate( aDSRef, attrValue );
attrValue = nil;
attrName = dsDataNodeAllocateString( aDSRef, kDS1AttrPassword );
attrValue = dsDataNodeAllocateString( aDSRef, kDSValueNonCryptPasswordMarker );
//remove the password if it already exists - don't check status
dsRemoveAttribute( recRef, attrName );
//add the correct password marker
siResult = dsAddAttribute( recRef, attrName, NULL, attrValue );
if ( siResult != eDSNoErr ) break;
siResult = dsCloseRecord( recRef );
authMethod = dsDataNodeAllocateString( aDSRef, kDSStdAuthSetPasswdAsRoot );
authBuff = dsDataBufferAllocate( aDSRef, strlen( "root" ) + strlen( rootPassword ) + 10 );
// 4 byte length + "root" + null byte + 4 byte length + rootPassword + null byte
length = strlen( "root" ) + 1;
ptr = authBuff->fBufferData;
::memcpy( ptr, &length, 4 );
ptr += 4;
authBuff->fBufferLength += 4;
::memcpy( ptr, "root", length );
ptr += length;
authBuff->fBufferLength += length;
length = strlen( rootPassword ) + 1;
::memcpy( ptr, &length, 4 );
ptr += 4;
authBuff->fBufferLength += 4;
::memcpy( ptr, rootPassword, length );
ptr += length;
authBuff->fBufferLength += length;
//set the root user password
siResult = dsDoDirNodeAuth( nodeRef, authMethod, true, authBuff, dataBuff, NULL );
}
}
//always leave the while
break;
} while(true);
if (context != 0) {
dsReleaseContinueData(aSearchNodeRef, context);
}
if ( recName != nil )
{
dsDataListDeallocate( aDSRef, recName );
free( recName );
recName = nil;
}
if ( recType != nil )
{
dsDataListDeallocate( aDSRef, recType );
free( recType );
recType = nil;
}
if ( attrTypes != nil )
{
dsDataListDeallocate( aDSRef, attrTypes );
free( attrTypes );
attrTypes = nil;
}
if ( dataBuff != nil )
{
dsDataBufferDeAllocate( aDSRef, dataBuff );
dataBuff = nil;
}
if ( nodeName != nil )
{
dsDataListDeallocate( aDSRef, nodeName );
free( nodeName );
nodeName = nil;
}
if ( authName != nil )
{
free( authName );
authName = nil;
}
if ( recordName != nil )
{
dsDataNodeDeAllocate( aDSRef, recordName );
recordName = nil;
}
if ( recordType != nil )
{
dsDataNodeDeAllocate( aDSRef, recordName );
recordType = nil;
}
if ( attrName != nil )
{
dsDataNodeDeAllocate( aDSRef, attrName );
attrName = nil;
}
if ( attrValue != nil )
{
dsDataNodeDeAllocate( aDSRef, attrValue );
attrValue = nil;
}
if ( authMethod != nil )
{
dsDataNodeDeAllocate( aDSRef, authMethod );
authMethod = nil;
}
if ( authBuff != nil )
{
dsDataBufferDeAllocate( aDSRef, authBuff );
authBuff = nil;
}
if ( nodeRef != 0 )
{
dsCloseDirNode( nodeRef );
nodeRef = 0;
}
if ( aSearchNodeRef != 0 )
{
dsCloseDirNode( aSearchNodeRef );
aSearchNodeRef = 0;
}
if ( aDSRef != 0 )
{
dsCloseDirService( aDSRef );
aDSRef = 0;
}
return(siResult);
}
SInt32 DisableRootUser( const char *userName, const char *password );
SInt32 DisableRootUser( const char *userName, const char *password )
{
SInt32 siResult = eDSAuthFailed;
tDirReference aDSRef = 0;
tDataBufferPtr dataBuff = nil;
UInt32 nodeCount = 0;
tContextData context = 0;
tDataListPtr nodeName = nil;
tDirNodeReference aSearchNodeRef = 0;
tDataListPtr recName = nil;
tDataListPtr recType = nil;
tDataListPtr attrTypes = nil;
UInt32 recCount = 1;
tAttributeListRef attrListRef = 0;
tRecordEntry *pRecEntry = nil;
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
char* authName = nil;
tDirNodeReference nodeRef = 0;
tDataNodePtr authMethod = nil;
tDataBufferPtr authBuff = nil;
UInt32 length = 0;
char* ptr = nil;
tDataNodePtr recordName = nil;
tDataNodePtr recordType = nil;
tRecordReference recRef = 0;
tDataNodePtr attrName = nil;
tDataNodePtr attrValue = nil;
if( (userName == nil) || (password == nil) )
{
return(siResult);
}
//adapted from try/catch code so using do/while and break
do
{
siResult = dsOpenDirService( &aDSRef );
if ( siResult != eDSNoErr ) break;
dataBuff = dsDataBufferAllocate( aDSRef, 1024 );
if ( dataBuff == nil ) break;
siResult = dsFindDirNodes( aDSRef, dataBuff, nil, eDSAuthenticationSearchNodeName, &nodeCount, &context );
if ( siResult != eDSNoErr ) break;
if ( nodeCount < 1 ) break;
siResult = dsGetDirNodeName( aDSRef, dataBuff, 1, &nodeName );
if ( siResult != eDSNoErr ) break;
siResult = dsOpenDirNode( aDSRef, nodeName, &aSearchNodeRef );
if ( siResult != eDSNoErr ) break;
if ( nodeName != NULL )
{
dsDataListDeallocate( aDSRef, nodeName );
free( nodeName );
nodeName = NULL;
}
recName = dsBuildListFromStrings( aDSRef, userName, NULL );
recType = dsBuildListFromStrings( aDSRef, kDSStdRecordTypeUsers, NULL );
attrTypes = dsBuildListFromStrings( aDSRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, NULL );
recCount = 1; // only care about first match
do
{
siResult = dsGetRecordList( aSearchNodeRef, dataBuff, recName, eDSExact, recType,
attrTypes, false, &recCount, &context);
if (siResult == eDSBufferTooSmall)
{
SInt32 bufSize = dataBuff->fBufferSize;
dsDataBufferDeAllocate( aDSRef, dataBuff );
dataBuff = nil;
dataBuff = ::dsDataBufferAllocate( aDSRef, bufSize * 2 );
} else if (siResult == eDSNoErr && recCount == 1) {
dsReleaseContinueData(aSearchNodeRef, context);
break;
}
} while (siResult == eDSBufferTooSmall || (siResult == eDSNoErr && context != 0));
//worry about multiple calls (ie. continue data) since we continue until first match or no more searching
if ( (siResult == eDSNoErr) && (recCount > 0) )
{
siResult = ::dsGetRecordEntry( aSearchNodeRef, dataBuff, 1, &attrListRef, &pRecEntry );
if ( (siResult == eDSNoErr) && (pRecEntry != nil) )
{
//index starts at one - should have two entries
for (unsigned int i = 1; i <= pRecEntry->fRecordAttributeCount; i++)
{
siResult = ::dsGetAttributeEntry( aSearchNodeRef, dataBuff, attrListRef, i, &valueRef, &pAttrEntry );
//need to have at least one value - get first only
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
// Get the first attribute value
siResult = ::dsGetAttributeValue( aSearchNodeRef, dataBuff, 1, valueRef, &pValueEntry );
// Is it what we expected
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
nodeName = dsBuildFromPath( aDSRef, pValueEntry->fAttributeValueData.fBufferData, "/" );
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
authName = (char*)calloc( 1, pValueEntry->fAttributeValueData.fBufferLength + 1 );
strncpy( authName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( aDSRef, pValueEntry );
pValueEntry = NULL;
}
}
dsCloseAttributeValueList(valueRef);
if (pAttrEntry != nil)
{
dsDeallocAttributeEntry(aDSRef, pAttrEntry);
pAttrEntry = nil;
}
} //loop over attrs requested
}//found 1st record entry
dsCloseAttributeList(attrListRef);
if (pRecEntry != nil)
{
dsDeallocRecordEntry(aDSRef, pRecEntry);
pRecEntry = nil;
}
}// got records returned
else
{
siResult = eDSAuthUnknownUser;
}
if ( (siResult == eDSNoErr) && (nodeName != nil) && (authName != nil) )
{
siResult = dsOpenDirNode( aDSRef, nodeName, &nodeRef );
if ( siResult != eDSNoErr ) break;
authMethod = dsDataNodeAllocateString( aDSRef, kDSStdAuthNodeNativeClearTextOK );
authBuff = dsDataBufferAllocate( aDSRef, strlen( authName ) + strlen( password ) + 10 );
// 4 byte length + username + null byte + 4 byte length + password + null byte
length = strlen( authName ) + 1;
ptr = authBuff->fBufferData;
::memcpy( ptr, &length, 4 );
ptr += 4;
authBuff->fBufferLength += 4;
::memcpy( ptr, authName, length );
ptr += length;
authBuff->fBufferLength += length;
length = strlen( password ) + 1;
::memcpy( ptr, &length, 4 );
ptr += 4;
authBuff->fBufferLength += 4;
::memcpy( ptr, password, length );
ptr += length;
authBuff->fBufferLength += length;
//if this process is run as root then the session auth is not even required
siResult = dsDoDirNodeAuth( nodeRef, authMethod, false, authBuff, dataBuff, NULL );
dsDataNodeDeAllocate( aDSRef, authMethod );
authMethod = NULL;
dsDataBufferDeAllocate( aDSRef, authBuff );
authBuff = NULL;
if (siResult == eDSNoErr)
{
recordType = dsDataNodeAllocateString( aDSRef, kDSStdRecordTypeUsers );
recordName = dsDataNodeAllocateString( aDSRef, "root" );
//open the root user record
siResult = dsOpenRecord( nodeRef, recordType, recordName, &recRef );
if ( siResult != eDSNoErr ) break;
attrName = dsDataNodeAllocateString( aDSRef, kDSNAttrAuthenticationAuthority );
//remove the authentication authority if it already exists - don't check status
dsRemoveAttribute( recRef, attrName );
dsDataNodeDeAllocate( aDSRef, attrName );
attrName = nil;
attrName = dsDataNodeAllocateString( aDSRef, kDS1AttrPassword );
attrValue = dsDataNodeAllocateString( aDSRef, "*" );
//remove the password if it already exists - don't check status
dsRemoveAttribute( recRef, attrName );
//add the correct password legacy disabled marker
siResult = dsAddAttribute( recRef, attrName, NULL, attrValue );
if ( siResult != eDSNoErr ) break;
siResult = dsCloseRecord( recRef );
}
}
//always leave the while
break;
} while(true);
if (context != 0) {
dsReleaseContinueData(aSearchNodeRef, context);
}
if ( recName != nil )
{
dsDataListDeallocate( aDSRef, recName );
free( recName );
recName = nil;
}
if ( recType != nil )
{
dsDataListDeallocate( aDSRef, recType );
free( recType );
recType = nil;
}
if ( attrTypes != nil )
{
dsDataListDeallocate( aDSRef, attrTypes );
free( attrTypes );
attrTypes = nil;
}
if ( dataBuff != nil )
{
dsDataBufferDeAllocate( aDSRef, dataBuff );
dataBuff = nil;
}
if ( nodeName != nil )
{
dsDataListDeallocate( aDSRef, nodeName );
free( nodeName );
nodeName = nil;
}
if ( authName != nil )
{
free( authName );
authName = nil;
}
if ( recordName != nil )
{
dsDataNodeDeAllocate( aDSRef, recordName );
recordName = nil;
}
if ( recordType != nil )
{
dsDataNodeDeAllocate( aDSRef, recordName );
recordType = nil;
}
if ( attrName != nil )
{
dsDataNodeDeAllocate( aDSRef, attrName );
attrName = nil;
}
if ( attrValue != nil )
{
dsDataNodeDeAllocate( aDSRef, attrValue );
attrValue = nil;
}
if ( authMethod != nil )
{
dsDataNodeDeAllocate( aDSRef, authMethod );
authMethod = nil;
}
if ( authBuff != nil )
{
dsDataBufferDeAllocate( aDSRef, authBuff );
authBuff = nil;
}
if ( nodeRef != 0 )
{
dsCloseDirNode( nodeRef );
nodeRef = 0;
}
if ( aSearchNodeRef != 0 )
{
dsCloseDirNode( aSearchNodeRef );
aSearchNodeRef = 0;
}
if ( aDSRef != 0 )
{
dsCloseDirService( aDSRef );
aDSRef = 0;
}
return(siResult);
}
//-----------------------------------------------------------------------------
// intcatch
//
// Helper function for read_passphrase
//-----------------------------------------------------------------------------
volatile int intr;
void
intcatch(int dontcare)
{
intr = 1;
}
//-----------------------------------------------------------------------------
// read_passphrase
//
// Returns: malloc'd C-str
// Provides a secure prompt for inputting passwords
/*
* Reads a passphrase from /dev/tty with echo turned off. Returns the
* passphrase (allocated with xmalloc), being very careful to ensure that
* no other userland buffer is storing the password.
*/
//-----------------------------------------------------------------------------
char *
read_passphrase(const char *prompt, int from_stdin)
{
char buf[1024], *p, ch;
struct termios tio, saved_tio;
sigset_t oset, nset;
struct sigaction sa, osa;
int input, output, echo = 0;
if (from_stdin) {
input = STDIN_FILENO;
output = STDERR_FILENO;
} else
input = output = open("/dev/tty", O_RDWR);
if (input == -1)
fprintf(stderr, "You have no controlling tty. Cannot read passphrase.\n");
/* block signals, get terminal modes and turn off echo */
sigemptyset(&nset);
sigaddset(&nset, SIGTSTP);
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = intcatch;
(void) sigaction(SIGINT, &sa, &osa);
intr = 0;
if (tcgetattr(input, &saved_tio) == 0 && (saved_tio.c_lflag & ECHO)) {
echo = 1;
tio = saved_tio;
tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
(void) tcsetattr(input, TCSANOW, &tio);
}
fflush(stdout);
(void)write(output, prompt, strlen(prompt));
for (p = buf; read(input, &ch, 1) == 1 && ch != '\n';) {
if (intr)
break;
if (p < buf + sizeof(buf) - 1)
*p++ = ch;
}
*p = '\0';
if (!intr)
(void)write(output, "\n", 1);
/* restore terminal modes and allow signals */
if (echo)
tcsetattr(input, TCSANOW, &saved_tio);
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
(void) sigaction(SIGINT, &osa, NULL);
if (intr) {
kill(getpid(), SIGINT);
sigemptyset(&nset);
/* XXX tty has not neccessarily drained by now? */
sigsuspend(&nset);
}
if (!from_stdin)
(void)close(input);
p = (char *)malloc(strlen(buf)+1);
strcpy(p, buf);
memset(buf, 0, sizeof(buf));
return (p);
}
//-----------------------------------------------------------------------------
// usage
//
//-----------------------------------------------------------------------------
void
usage(void)
{
printf("\ndsenableroot:: Enable or disable root user with Directory Services.\n");
printf("Version %s\n", TOOLS_VERSION);
printf("Usage: dsenableroot [-d] [-u username] [-p password] [-r rootPassword]\n");
printf("Example 1: dsenableroot\n");
printf("Attempt to enable root account.\n");
printf("Your username will be used.\n");
printf("Both passwords will be prompted for.\n");
printf("Example 2: dsenableroot -d -u username\n");
printf("Attempt to disable root account.\n");
printf("Only user password will be prompted for.\n");
printf("In all cases passwords cannot be empty strings.\n");
printf("\n");
}
int main(int argc, char *argv[])
{
int ch;
char *name = nil;
char *pwd = nil;
char *rootpwd = nil;
char *verifyrootpwd = nil;
SInt32 result = eDSAuthFailed;
bool bEchoName = false;
bool bDisableRootUser= false;
if ( argc == 2 && strcmp(argv[1], "-appleversion") == 0 )
dsToolAppleVersionExit( argv[0] );
while ((ch = getopt(argc, argv, "u:p:r:dv?h")) != -1) {
switch (ch) {
case 'u':
name = strdup(optarg);
break;
case 'p':
pwd = strdup(optarg);
break;
case 'r':
rootpwd = strdup(optarg);
break;
case 'd':
bDisableRootUser = true;
break;
case 'v':
printf("\ndsenableroot:: Version %s\n", TOOLS_VERSION);
exit(0);
case '?':
case 'h':
default:
{
usage();
exit(0);
}
}
}
if ( (argc > 1) && (name == nil) && (pwd == nil) && (rootpwd == nil) && (!bDisableRootUser) )
{
usage();
exit(0);
}
if ( (argc > 2) && (name == nil) && (pwd == nil) && bDisableRootUser )
{
usage();
exit(0);
}
// get the prompts we still need
if (name == nil)
{
bEchoName = true;
name = getenv("USER");
if (name != nil)
{
printf("username = %s\n", name);
}
else
{
printf("***Username <-u username> must be explicitly provided in this shell***\n");
exit(0);
}
}
if (pwd == nil)
{
pwd = read_passphrase("user password:", 1);
}
if ( (rootpwd == nil) && (!bDisableRootUser) )
{
rootpwd = read_passphrase("root password:", 1);
verifyrootpwd = read_passphrase("verify root password:", 1);
if (strcmp(rootpwd, verifyrootpwd) != 0)
{
printf("\ndsenableroot:: ***Root password was not verified with dual entries.\n");
exit(0);
}
}
if ( (name != nil) && (pwd != nil) )
{
if (bDisableRootUser)
{
result = DisableRootUser( name, pwd );
}
else
{
result = EnableRootUser( name, pwd, rootpwd );
}
free(pwd);
pwd = nil;
if (rootpwd)
{
free(rootpwd);
rootpwd = nil;
}
if (bDisableRootUser)
{
if (result == eDSNoErr)
{
printf("\ndsenableroot:: ***Successfully disabled root user.\n");
}
else
{
printf("\ndsenableroot:: ***Failed to disable root user.\n");
}
}
else
{
if (result == eDSNoErr)
{
printf("\ndsenableroot:: ***Successfully enabled root user.\n");
}
else
{
printf("\ndsenableroot:: ***Failed to enable root user.\n");
}
}
}
if (!bEchoName && name != nil)
{
free(name);
name = nil;
}
return 0;
}

18
dserr/dserr.8 Normal file
View File

@ -0,0 +1,18 @@
.\" $Id: dserr.8,v 1.1 2005/04/13 17:16:32 snsimon Exp $
.\"
.\" Copyright (c) 2005 Apple Computer, Inc., all rights reserved.
.\" Distributed as unsupported software for Mac OS X Server
.Dd 13 April 2005
.Dt dserr 8
.Os "Mac OS X Server"
.sp
.Sh NAME
.Nm dserr
.Nd prints a description for an error code.
.Sh SYNOPSIS
.Nm
.Ar errcode
.sp
.Sh DESCRIPTION
.Nm
prints a description for an error code.

71
dserr/dserr.cpp Normal file
View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* dserr.cpp
* DSTools
*/
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
#include <stdlib.h>
#include <DirectoryService/DirectoryService.h>
#include "dstools_version.h"
void usage(const char *toolName);
int main( int argc, char * const *argv )
{
long dsStatus = eDSNoErr;
if ( argc != 2 )
usage(argv[0]);
if ( strcmp(argv[1], "-appleversion") == 0 )
dsToolAppleVersionExit( argv[0] );
sscanf( argv[1], "%ld", &dsStatus );
if ( dsStatus > 0 )
dsStatus *= -1;
char *statusStr = dsCopyDirStatusName( dsStatus );
if ( statusStr != NULL ) {
printf( "%ld: %s\n", dsStatus, statusStr );
}
else {
printf( "%ld: <unknown>\n", dsStatus );
}
return EX_OK;
}
void usage(const char *toolName)
{
printf( "Usage: %s errCode\n", toolName );
exit( EX_USAGE );
}

783
dsmbrutil/dsmbrutil.c Normal file
View File

@ -0,0 +1,783 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <membership.h>
#include <membershipPriv.h>
#include <servers/bootstrap.h>
#include <DSlibinfoMIG_types.h>
//#include <DSmemberdMIG.h>
/* Return codes:
0 Success
1 Unknown error
2 memberd not reachable
3 Usage error (and nothing else)
4 Incorrect id (uid, and gid)
5 UUID error
6 Incorrect option specified
7 The user or group does not exist
8 The user or group does not have an sid
*/
#define SUCCESS 0
#define UNKNOWN 1
#define NOTREACHABLE 2
#define USAGE 3
#define INCORRECTID 4
#define UUIDERROR 5
#define INCORRECTOPT 6
#define EXISTENCE 7
#define NOSID 8
#define NULLARG 9
static int isVerbose = 0;
static char myname[256];
typedef enum tReqType
{
kUnknown = 0,
kUserID,
kUserName,
kUserSID,
kUserUUID,
kGroupID,
kGroupName,
kGroupSID,
kGroupUUID
} tReqType;
#pragma mark *** Helper Functions ***
void printfullusage()
{
fprintf(stderr, "Usage: %s [flags] <command> [options]\n", myname);
fprintf(stderr, "flags:\n");
fprintf(stderr, " -v verbose mode\n");
fprintf(stderr, " -h this usage output\n");
fprintf(stderr, "commands:\n");
fprintf(stderr, " getuuid [-ugUGsS] value\n");
fprintf(stderr, " getid [-UGsSX] value\n");
fprintf(stderr, " getsid [-ugUGX] value\n");
fprintf(stderr, " checkmembership [-uUxs] value [-gGXS] value\n");
fprintf(stderr, " flushcache\n");
fprintf(stderr, " dumpstate\n");
fprintf(stderr, " statistics [-f]\n");
}
int notreachable()
{
fprintf(stderr, "memberd is not reachable\n");
return NOTREACHABLE;
}
int unknownerror()
{
fprintf(stderr, "There was an unknown error.\n");
return UNKNOWN;
}
int usernamecheck(char *username, uuid_t uuid)
{
if(isVerbose)
printf("Attempting to convert username to UUID\n");
int err = mbr_user_name_to_uuid(username, uuid);
if(err == EIO)
{
return notreachable();
}
else if(err == ENOENT)
{
fprintf(stderr, "The user %s cannot be found\n", username);
return EXISTENCE;
}
if(isVerbose)
printf("Conversion successful\n");
return SUCCESS;
}
int groupnamecheck(char *groupname, uuid_t uuid)
{
if(isVerbose)
printf("Attempting to convert the groupname to a UUID\n");
int err = mbr_group_name_to_uuid(groupname, uuid);
if(err == EIO)
{
return notreachable();
}
else if(err == ENOENT)
{
fprintf(stderr, "The group %s cannot be found\n", groupname);
return EXISTENCE;
}
return SUCCESS;
}
int getuuidforreqtype( tReqType reqType, uint32_t idValue, char *strValue, uuid_t theUUID )
{
int err = SUCCESS;
if ( reqType == kUserID )
{
err = mbr_uid_to_uuid( idValue, theUUID );
}
else if ( reqType == kGroupID )
{
err = mbr_gid_to_uuid( idValue, theUUID );
}
else if ( reqType == kUserName )
{
err = usernamecheck( strValue, theUUID );
}
else if ( reqType == kUserSID || reqType == kGroupSID )
{
nt_sid_t sid;
err = mbr_string_to_sid( strValue, &sid );
if ( err == 0 )
{
if( isVerbose )
printf("Attempting to find the sid for the UUID\n");
err = mbr_sid_to_uuid( &sid, theUUID );
}
}
else if ( reqType == kGroupName )
{
err = groupnamecheck( strValue, theUUID );
}
else if ( reqType == kGroupUUID || reqType == kUserUUID ) // we use group or user
{
if ( uuid_parse( strValue, theUUID ) != 0 )
{
printf( "The UUID entered is not valid.\n" );
return UUIDERROR;
}
}
if ( err == ENOENT )
printf( "Entry not found\n" );
if ( err == EIO )
notreachable();
else if ( err != 0 )
unknownerror();
return err;
}
int getidopt( int argc, char *argv[], char *options, tReqType *outType, uint32_t *outid, char **outvalue )
{
int ch;
char *lastChar = NULL;
(*outType) = kUnknown;
while ( (*outType) == kUnknown && (ch = getopt(argc, argv, options)) != -1 )
{
switch (ch)
{
case 'u':
(*outid) = strtol( optarg, &lastChar, 10 );
if ( lastChar == NULL || lastChar[0] == '\0' )
(*outType) = kUserID;
else
fprintf( stderr, "ID supplied was not a number\n" );
break;
case 'U':
(*outType) = kUserName;
(*outvalue) = optarg;
break;
case 's':
(*outType) = kUserSID;
(*outvalue) = optarg;
break;
case 'x':
(*outType) = kUserUUID;
(*outvalue) = optarg;
break;
case 'g':
(*outid) = strtol( optarg, &lastChar, 10 );
if ( lastChar == NULL || lastChar[0] == '\0' )
(*outType) = kGroupID;
else
fprintf( stderr, "ID supplied was not a number\n" );
break;
case 'G':
(*outType) = kGroupName;
(*outvalue) = optarg;
break;
case 'S':
(*outType) = kGroupSID;
(*outvalue) = optarg;
break;
case 'X':
(*outType) = kGroupUUID;
(*outvalue) = optarg;
break;
case '?':
exit( EINVAL );
break;
default:
return EINVAL;
}
}
return ((*outType) == kUnknown ? EINVAL : 0);
}
int printuuid(const uuid_t uuid)
{
char string[37];
if(isVerbose)
printf("Attempting to convert the UUID to a string\n");
int err = mbr_uuid_to_string(uuid, string);
if(err == ENOENT)
{
return unknownerror();
}
else if(err == EIO)
{
return notreachable();
}
printf("%s\n", string);
return SUCCESS;
}
// stringprint and idprint make the above code neater
// since there is a lot of repeat code. user should
// be set to 1 if being used to output something related
// to a user, and 0 if related to a group.
// stringprint will print the uuid corresponding to string
int stringprint(char *string, int user)
{
if(strlen(string) > 255)
{
fprintf(stderr, "Names cannot be longer than 255 characters\n");
return 1;
}
uuid_t uuid;
if(user)
{
if(isVerbose)
printf("Attempting to convert username to UUID\n");
int err = mbr_user_name_to_uuid(string, uuid);
if(err == EIO)
{
return notreachable();
}
else if(err != ENOENT)
{
// We were able to find a uuid for this username. Print it out
if(isVerbose)
printf("Conversion successful\n");
return printuuid(uuid);
}
else
{
// We were not able to find a uuid, display an error.
printf("There is no uuid for user %s\n", string);
return UUIDERROR;
}
}
else
{
if(isVerbose)
printf("Attempting to convert groupname to UUID\n");
int err = mbr_group_name_to_uuid(string, uuid);
if(err == EIO)
{
return notreachable();
}
else if(err != ENOENT)
{
// We were able to find a uuid for this groupname. Print it out
if(isVerbose)
printf("Conversion successful\n");
return printuuid(uuid);
}
else
{
// We were not able to find a uuid, display an error.
printf("There is no uuid for group %s\n", string);
return UUIDERROR;
}
}
}
int sidprint( char *strValue, int user )
{
nt_sid_t sid;
int err = EXISTENCE;
if(isVerbose)
printf("Attempting to convert the string to a SID\n");
if ( mbr_string_to_sid( strValue, &sid) == 0 )
{
uuid_t theUUID;
int err = mbr_sid_to_uuid( &sid, theUUID );
if ( err == 0 )
printuuid( theUUID );
else
printf( "SID not found\n" );
}
else
{
printf( "Invalid SID value\n" );
}
return err;
}
int idprint(int id, int user)
{
uuid_t uuid;
if(user)
{
if(isVerbose)
printf("Attempting to convert the uid to a UUID\n");
int err = mbr_uid_to_uuid(id, uuid);
if(err == EIO)
{
return notreachable();
}
else if(err != ENOENT)
{
// We were able to find a uuid for this, output it here.
if(isVerbose)
printf("Conversion successful\n");
return printuuid(uuid);
}
else
{
// We were not able to find a uuid for this, output an error.
printf("There is no uuid for uid %i\n", id);
return UUIDERROR;
}
}
else
{
if(isVerbose)
printf("Attempting to convert the gid to a UUID\n");
int err = mbr_gid_to_uuid(id, uuid);
if(err == EIO)
{
return notreachable();
}
else if(err != ENOENT)
{
// We were able to find a uuid for this, output it here.
if(isVerbose)
printf("Conversion successful\n");
return printuuid(uuid);
}
else
{
// We were not able to find a uuid for this, output an error.
printf("There is no uuid for gid %i\n", id);
return UUIDERROR;
}
}
}
void PrintAverageTime(uint64_t numMicroSeconds)
{
if (numMicroSeconds < 500ULL)
printf(" average time %llu uSecs\n", numMicroSeconds);
else if (numMicroSeconds < 10ULL * 1000ULL)
{
uint64_t numMilliseconds = numMicroSeconds / 1000ULL;
uint64_t fraction = (numMicroSeconds % 1000ULL) / 100ULL;
printf(" average time %llu.%llu mSecs\n", numMilliseconds, fraction);
}
else if (numMicroSeconds < 1000ULL * 1000ULL)
{
uint64_t numMilliseconds = numMicroSeconds / 1000ULL;
printf(" average time %llu mSecs\n", numMilliseconds);
}
else
{
uint64_t numSeconds = numMicroSeconds / 1000000ULL;
uint64_t fraction = (numMicroSeconds % 1000000ULL) / 100000ULL;
printf(" average time %llu.%llu seconds\n", numSeconds, fraction);
}
}
#pragma mark *** Memberd abstracted API calls ***
int getUUID( int argc, char *argv[] )
{
tReqType reqType;
uint32_t idValue = 0;
char *strValue = NULL;
optind = 0;
if ( getidopt( argc, argv, "u:U:g:G:s:S:", &reqType, &idValue, &strValue ) == EINVAL || optind != argc )
{
fprintf( stderr, "Usage: %s getuuid must have one flag and parameter\n", myname );
return EINVAL;
}
switch (reqType)
{
case kUserID:
return idprint( idValue, 1 );
case kUserName:
return stringprint( strValue, 1 );
case kUserSID:
return sidprint( strValue, 1 );
case kGroupID:
return idprint( idValue, 0 );
case kGroupName:
return stringprint( strValue, 0 );
case kGroupSID:
return sidprint( strValue, 0 );
default:
fprintf( stderr, "Unknown lookup type %d\n", reqType );
return EINVAL;
}
return SUCCESS;
}
int getID( int argc, char *argv[] )
{
tReqType reqType;
uint32_t idValue = 0;
char *strValue = NULL;
uuid_t theUUID;
optind = 0;
if ( getidopt( argc, argv, "U:G:s:S:x:X:", &reqType, &idValue, &strValue ) == EINVAL || optind != argc )
{
fprintf( stderr, "Usage: %s getid must have one flag and parameter\n", myname );
return EINVAL;
}
uuid_clear( theUUID );
if ( getuuidforreqtype( reqType, idValue, strValue, theUUID) == 0 && uuid_is_null(theUUID) == 0 )
{
id_t id;
int type;
if(isVerbose)
printf("Attempting to find the id for the UUID\n");
int err = mbr_uuid_to_id( theUUID, &id, &type );
if ( err == 0 )
{
if ( isVerbose )
printf( "id was found\n" );
if ( type == ID_TYPE_UID )
printf( "uid: %i\n", id );
else if ( type == ID_TYPE_GID )
printf( "gid: %i\n", id );
}
else if( err == EIO )
return notreachable();
else
return unknownerror();
}
else
{
printf( "id not found\n" );
}
return SUCCESS;
}
int getSID(int argc, char *argv[])
{
tReqType reqType;
uint32_t idValue = 0;
char *strValue = NULL;
uuid_t theUUID;
int err = SUCCESS;
optind = 0;
if ( getidopt( argc, argv, "u:g:U:G:x:X:", &reqType, &idValue, &strValue ) == EINVAL || optind != argc )
{
fprintf( stderr, "Usage: %s getsid must have one flag and parameter\n", myname );
return EINVAL;
}
uuid_clear( theUUID );
if ( getuuidforreqtype( reqType, idValue, strValue, theUUID) == 0 && uuid_is_null(theUUID) == 0 )
{
nt_sid_t sid;
if(isVerbose)
printf("Attempting to find the SID for the UUID\n");
err = mbr_uuid_to_sid( theUUID, &sid );
if ( err == 0 )
{
char string[MBR_MAX_SID_STRING_SIZE];
if(isVerbose)
printf("Attempting to convert the SID to a string\n");
err = mbr_sid_to_string( &sid, string );
if ( err == 0 )
printf( "%s\n", string );
else if(err == EIO)
return notreachable();
else
return unknownerror();
}
if ( err == EIO )
return notreachable();
else if ( err == ENOENT )
printf( "no SID found\n" );
else if ( err != 0 )
return unknownerror();
}
else
{
printf( "no SID found\n" );
}
return err;
}
int checkmembership(int argc, char *argv[])
{
tReqType reqType;
uint32_t idValue = 0;
char *strValue = NULL;
uuid_t userUUID;
uuid_t groupUUID;
int err = SUCCESS;
optind = 0;
uuid_clear( userUUID );
uuid_clear( groupUUID );
err = getidopt( argc, argv, "u:U:x:s:", &reqType, &idValue, &strValue );
if ( err == 0 )
{
err = getuuidforreqtype( reqType, idValue, strValue, userUUID );
if ( err == 0 )
{
err = getidopt( argc, argv, "g:G:X:S:", &reqType, &idValue, &strValue );
if ( err == 0 )
{
err = getuuidforreqtype( reqType, idValue, strValue, groupUUID );
}
}
}
if ( err == EINVAL )
{
fprintf( stderr, "Usage: %s checkmembership missing appropriate options\n", myname );
fprintf( stderr, " checkmembership [-uUx] value [-GX] value\n" );
return EINVAL;
}
else if ( uuid_is_null(userUUID) )
{
printf( "User not found\n" );
err = EXISTENCE;
}
else if ( uuid_is_null(groupUUID) )
{
printf( "Group not found\n" );
err = EXISTENCE;
}
else
{
// we made it here we are good
int isMember;
err = mbr_check_membership( userUUID, groupUUID, &isMember );
if ( err == 0 )
{
if ( isMember == 1 )
printf( "user is a member of the group\n" );
else
printf( "user is not a member of the group\n");
}
else if ( err == EIO )
return notreachable();
}
return err;
}
int flushcache( void )
{
mbr_reset_cache();
return 0;
}
int dumpstate( void )
{
printf("This functionality has been removed dsmbrutil in real macOS");
/*
mach_port_t serverPort;
kern_return_t kr;
kr = bootstrap_look_up(bootstrap_port, kDSStdMachDSMembershipPortName, &serverPort);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Failed to contact opendirectoryd (%d).\n", kr);
exit(EIO);
}
kr = memberdDSmig_DumpState( serverPort );
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Operation failed (%d).\n", kr);
exit(EIO);
}
*/
return 0;
}
int statistics( int argc, char *argv[] )
{
printf("This functionality has been removed dsmbrutil in real macOS");
/* StatBlock stats;
int temp, minutes, hours;
mach_port_t serverPort;
int flushStats = 0;
char ch;
kern_return_t kr;
optind = 0;
while ( (ch = getopt(argc, argv, "f")) != -1 )
{
switch (ch)
{
case 'f':
flushStats = 1;
break;
}
}
kr = bootstrap_look_up(bootstrap_port, kDSStdMachDSMembershipPortName, &serverPort);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Failed to contact opendirectoryd (%d).\n", kr);
exit(EIO);
}
if ( flushStats == 1 )
{
memberdDSmig_ClearStats( serverPort );
}
else
{
memset(&stats, 0, sizeof(stats));
kr = memberdDSmig_GetStats( serverPort, &stats );
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Operation failed (%d).\n", kr);
exit(EIO);
}
temp = stats.fTotalUpTime / 60;
minutes = temp % 60;
temp /= 60;
hours = temp % 24;
temp /= 24;
printf("opendirectoryd running for %d days, %d hours and %d minutes\n", temp, hours, minutes);
printf("%llu requests,", stats.fTotalCallsHandled);
PrintAverageTime(stats.fAverageuSecPerCall);
printf("%llu cache hits, %llu cache misses\n", stats.fCacheHits, stats.fCacheMisses);
printf("%llu Directory record lookups (%llu failed),",
stats.fTotalRecordLookups, stats.fNumFailedRecordLookups);
PrintAverageTime(stats.fAverageuSecPerRecordLookup);
printf("%llu membership searches,", stats.fTotalMembershipSearches);
PrintAverageTime(stats.fAverageuSecPerMembershipSearch);
printf("%llu searches for legacy groups,", stats.fTotalLegacySearches);
PrintAverageTime(stats.fAverageuSecPerLegacySearch);
printf("%llu searches for groups containing user,", stats.fTotalGUIDMemberSearches);
PrintAverageTime(stats.fAverageuSecPerGUIDMemberSearch);
printf("%llu nested group membership searches,", stats.fTotalNestedMemberSearches);
PrintAverageTime(stats.fAverageuSecPerNestedMemberSearch);
}
*/
return 0;
}
#pragma mark *** Main ***
int main(int argc, char *argv[])
{
int ch;
strcpy( myname, argv[0] );
if(argc < 2)
{
printfullusage();
return SUCCESS;
}
while ( (ch = getopt(argc, argv, "vh")) != -1 )
{
switch (ch)
{
case 'v':
isVerbose = 1;
break;
case 'h':
printfullusage();
return 0;
case '?':
printfullusage();
return EINVAL;
default:
break;
}
}
argc -= optind;
argv += optind;
char *command = argv[0];
// now increment past command
argc--;
argv++;
if ( strcasecmp(command, "getuuid") == 0 )
return getUUID(argc, argv);
else if ( strcasecmp(command, "getid") == 0 )
return getID( argc, argv );
else if (strcasecmp(command, "getsid") == 0 )
return getSID( argc, argv );
else if ( strcasecmp(command, "checkmembership") == 0 )
return checkmembership(argc, argv);
else if ( strcasecmp(command, "flushcache") == 0 )
return flushcache();
else if ( strcasecmp(command, "dumpstate") == 0 )
return dumpstate();
else if ( strcasecmp(command, "statistics") == 0 )
return statistics( argc, argv );
printfullusage();
return USAGE;
}

96
dsmbrutil/dsmemberutil.1 Normal file
View File

@ -0,0 +1,96 @@
.Dd Jan 1, 2007
.Dt dsmemberutil 1
.Os Darwin
.Sh NAME
.Nm dsmemberutil
.Nd various operations for the membership APIs, including state dump, check memberships, UUIDs, etc.
.Sh SYNOPSIS
.Nm
.Op Fl v
.Op Fl h
.Ar command
.Op options
.Pp
.Sh DESCRIPTION
.Nm
is a program that implements the membership API calls in a command line utility.
.Pp
.Sh FLAGS
A list of flags and their descriptions:
.Bl -tag -width -ident
.It Fl h
Lists the options for calling
.Nm
.It Fl v
Causes
.Nm
to operate in verbose mode.
.El
.Pp
.Sh COMMANDS
The action of each command is described below:
.Bl -tag -width "xxxxxxxxxx"
.It Ar getuuid Fl ugUGsS Ar value
Takes any of the options and returns the associated UUID.
.It Ar getid Fl UGsSX Ar value
Takes any of the options and returns the associated UID or GID depending on option provided.
.It Ar getsid Fl ugUGX Ar value
Takes any of the options and returns the associated SID.
.It Ar checkmembership Fl uUxs Ar param Fl gGXS Ar param
Returns if a user or group with the associated option is a member of the group.
.It Ar flushcache
Flushes the current membership cache.
.It Ar dumpstate
Dumps the current state of the cache to /Library/Logs/membership_dump.log.
.It Ar statistics Op Fl f
Dumps the membership call statistics or optionally flushes them with the option
.Fl f .
.El
.Pp
A list of options available. In some cases
.Fl xX
and
.Fl sS
can be used synonymously due to nature of the value.
.Bl -tag -width "-x xxxxxxxxxxxx"
.It Fl u Ar uid
Using user with UID
.It Fl U Ar name
Using user with name
.It Fl s Ar sid
Using user with SID
.It Fl x Ar uuid
Using user with UUID
.It Fl g Ar gid
Using group with GID
.It Fl G Ar name
Using group with name
.It Fl S Ar sid
Using group with SID
.It Fl X Ar uuid
Using group with UUID
.El
.Sh EXAMPLES
.Pp
.Bl -tag -width -indent \" Differs from above in tag removed
.It Get a user's uuid:
.Dl % dsmemberutil getuuid -u 501
.Dl EEA4F2F6-B268-49E7-9C6F-E3C4A37DA4FD
.It Get a group's uuid
.Dl % dsmemberutil getuuid -g 0
.Dl ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000000
.It Get a user's or group's id from a uuid
.Dl % dsmemberutil getid -X ABCDEFAB-CDEF-ABCD-EFAB-CDEF0000000C
.Dl gid: 12
.It Check a user's membership in a group (using UID and GID)
.Dl % dsmemberutil checkmembership -u 501 -g 0
.Dl user is not a member of the group
.It Check a user's membership in a group (using names)
.Dl % dsmemberutil checkmembership -U root -G wheel
.Dl user is a member of the group
.El \" Ends the list
.Pp
.Sh SEE ALSO
.Xr DirectoryService 8 ,
.Xr dseditgroup 1 ,
.Xr dscacheutil 1

1
dsmbrutil/memberd.1 Normal file
View File

@ -0,0 +1 @@
.so man1/dsmemberutil.1

163
pwpolicy/AuthFile.c Normal file
View File

@ -0,0 +1,163 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* AuthFile.m
*/
#include "AuthFile.h"
#define kMaxPolicyStrLen 2048
// from DirServicesConst.h (our layer is below DS)
#define kDSValueAuthAuthorityShadowHash ";ShadowHash;"
#define kDSTagAuthAuthorityShadowHash "ShadowHash"
#define kDSTagAuthAuthorityBetterHashOnly "BetterHashOnly"
#define kHashNameListPrefix "HASHLIST:"
static void pwsf_AppendUTF8StringToArray( const char *inUTF8Str, CFMutableArrayRef inArray )
{
CFStringRef stringRef = CFStringCreateWithCString( kCFAllocatorDefault, inUTF8Str, kCFStringEncodingUTF8 );
if ( stringRef != NULL ) {
CFArrayAppendValue( inArray, stringRef );
CFRelease( stringRef );
}
}
// ----------------------------------------------------------------------------------------
// pwsf_ShadowHashDataToArray
//
// Returns: TRUE if an array is returned in <outHashTypeArray>.
// ----------------------------------------------------------------------------------------
int pwsf_ShadowHashDataToArray( const char *inAAData, CFMutableArrayRef *outHashTypeArray )
{
CFMutableArrayRef hashTypeArray = NULL;
char hashType[256];
if ( inAAData == NULL || outHashTypeArray == NULL || *inAAData == '\0' )
return 0;
*outHashTypeArray = NULL;
// get the existing list (if any)
if ( strncmp( inAAData, kDSTagAuthAuthorityBetterHashOnly, sizeof(kDSTagAuthAuthorityBetterHashOnly)-1 ) == 0 )
{
hashTypeArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( hashTypeArray == NULL )
return 0;
pwsf_AppendUTF8StringToArray( "SMB-NT", hashTypeArray );
pwsf_AppendUTF8StringToArray( "SALTED-SHA1", hashTypeArray );
}
else
if ( strncmp( inAAData, kHashNameListPrefix, sizeof(kHashNameListPrefix)-1 ) == 0 )
{
// comma delimited list
const char *endPtr;
const char *tptr = inAAData + sizeof(kHashNameListPrefix) - 1;
hashTypeArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( hashTypeArray == NULL )
return 0;
if ( *tptr++ == '<' && strchr(tptr, '>') != NULL )
{
while ( (endPtr = strchr( tptr, ',' )) != NULL )
{
strlcpy( hashType, tptr, (endPtr - tptr) + 1 );
pwsf_AppendUTF8StringToArray( hashType, hashTypeArray );
tptr += (endPtr - tptr) + 1;
}
endPtr = strchr( tptr, '>' );
if ( endPtr != NULL )
{
strlcpy( hashType, tptr, (endPtr - tptr) + 1 );
pwsf_AppendUTF8StringToArray( hashType, hashTypeArray );
}
}
}
*outHashTypeArray = hashTypeArray;
return 1;
}
// ----------------------------------------------------------------------------------------
// pwsf_ShadowHashArrayToData
// ----------------------------------------------------------------------------------------
char *pwsf_ShadowHashArrayToData( CFArrayRef inHashTypeArray, long *outResultLen )
{
char *aaNewData = NULL;
char *newDataCStr = NULL;
long len = 0;
CFMutableStringRef newDataString = NULL;
CFStringRef stringRef;
CFIndex stringLen;
// build the new string
CFIndex typeCount = CFArrayGetCount( inHashTypeArray );
if ( typeCount > 0 )
{
newDataString = CFStringCreateMutable( kCFAllocatorDefault, 0 );
if ( newDataString == NULL )
return NULL;
CFIndex index;
for ( index = 0; index < typeCount; index++ )
{
stringRef = (CFStringRef) CFArrayGetValueAtIndex( inHashTypeArray, index );
if ( stringRef != NULL )
{
if ( CFStringGetLength(newDataString) > 0 )
CFStringAppend( newDataString, CFSTR(",") );
CFStringAppend( newDataString, stringRef );
}
}
}
// build the auth-authority
stringLen = CFStringGetLength( newDataString );
newDataCStr = (char *) calloc( 1, stringLen + 1 );
CFStringGetCString( newDataString, newDataCStr, stringLen + 1, kCFStringEncodingUTF8 );
aaNewData = (char *) calloc( 1, sizeof(kDSValueAuthAuthorityShadowHash) + sizeof(kHashNameListPrefix) + stringLen + 2 );
// build string
if ( newDataCStr != NULL && aaNewData != NULL )
len = sprintf( aaNewData, "%s<%s>", kHashNameListPrefix, newDataCStr );
// clean up
if ( newDataString != NULL )
CFRelease( newDataString );
if ( newDataCStr != NULL )
free( newDataCStr );
// return string length (if requested)
if ( outResultLen != NULL )
*outResultLen = len;
return aaNewData;
}

36
pwpolicy/AuthFile.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef __AUTHFILE_H__
#define __AUTHFILE_H__
#include <CoreFoundation/CoreFoundation.h>
__BEGIN_DECLS
int pwsf_ShadowHashDataToArray( const char *inAAData, CFMutableArrayRef *outHashTypeArray );
char * pwsf_ShadowHashArrayToData( CFArrayRef inHashTypeArray, long *outResultLen );
__END_DECLS
#endif

482
pwpolicy/CAuthAuthority.cpp Normal file
View File

@ -0,0 +1,482 @@
/*
* Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include "CAuthAuthority.h"
#include <DirectoryService/DirServicesConst.h>
#include <DirectoryService/DirServicesUtilsPriv.h>
CAuthAuthority::CAuthAuthority()
{
mValueArray = NULL;
mDisabledAuthorityStorage = NULL;
}
CAuthAuthority::CAuthAuthority(CAuthAuthority &inAuthAuthority)
{
mValueArray = CFArrayCreateMutableCopy( kCFAllocatorDefault, 0, inAuthAuthority.mValueArray );
mDisabledAuthorityStorage = NULL;
}
CAuthAuthority::~CAuthAuthority()
{
if (mValueArray) {
CFRelease(mValueArray);
mValueArray = NULL;
}
if (mDisabledAuthorityStorage) {
CFRelease(mDisabledAuthorityStorage);
mDisabledAuthorityStorage = NULL;
}
}
bool
CAuthAuthority::AddValue( const char *inAuthAuthorityStr )
{
bool added = false;
CFMutableDictionaryRef aaDict = dsConvertAuthAuthorityToCFDict( inAuthAuthorityStr );
if ( aaDict != NULL )
{
if ( mValueArray == NULL )
mValueArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( mValueArray != NULL ) {
CFArrayAppendValue( mValueArray, aaDict );
added = true;
}
CFRelease( aaDict );
}
return added;
}
bool
CAuthAuthority::AddValue( CFStringRef inAuthAuthorityString )
{
char aaBuffer[1024];
if ( CFStringGetCString(inAuthAuthorityString, aaBuffer, sizeof(aaBuffer), kCFStringEncodingUTF8) )
return AddValue( aaBuffer );
return false;
}
bool
CAuthAuthority::AddValues( CFArrayRef inAuthAuthorityArray )
{
bool added = false;
CFIndex index = 0;
CFIndex aryCount = 0;
CFStringRef aaString = NULL;
CFMutableDictionaryRef aaDict = NULL;
char aaBuffer[1024];
if ( inAuthAuthorityArray == NULL )
return false;
if ( mValueArray == NULL ) {
mValueArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( mValueArray == NULL )
return false;
}
aryCount = CFArrayGetCount( inAuthAuthorityArray );
for ( index = 0; index < aryCount; index++ )
{
aaString = (CFStringRef) CFArrayGetValueAtIndex( inAuthAuthorityArray, index );
if ( aaString != NULL )
{
if ( CFStringGetCString(aaString, aaBuffer, sizeof(aaBuffer), kCFStringEncodingUTF8) )
{
aaDict = dsConvertAuthAuthorityToCFDict( aaBuffer );
if ( aaDict != NULL )
{
CFArrayAppendValue( mValueArray, aaDict );
CFRelease( aaDict );
added = true;
}
}
}
}
return added;
}
CFIndex
CAuthAuthority::GetValueCount( void )
{
CFIndex theResult = 0;
if ( mValueArray != NULL )
theResult = CFArrayGetCount( mValueArray );
return theResult;
}
char *
CAuthAuthority::GetValueAtIndex( int inIndex )
{
if ( mValueArray == NULL )
return NULL;
return dsConvertCFDictToAuthAuthority( (CFMutableDictionaryRef) CFArrayGetValueAtIndex(mValueArray, inIndex) );
}
char *
CAuthAuthority::GetValueForTag( const char *inTagStr )
{
return dsConvertCFDictToAuthAuthority( this->GetValueForTagAsCFDict(inTagStr) );
}
CFMutableDictionaryRef
CAuthAuthority::GetValueForTagAsCFDict( const char *inTagStr )
{
CFMutableDictionaryRef theDict = NULL;
CFMutableDictionaryRef aDict = NULL;
CFIndex arrayCount = 0;
CFIndex index = 0;
CFStringRef tagValueString = NULL;
CFStringRef searchTagValueString = NULL;
if ( mValueArray == NULL )
return NULL;
searchTagValueString = CFStringCreateWithCString( kCFAllocatorDefault, inTagStr, kCFStringEncodingUTF8 );
if ( searchTagValueString == NULL )
return NULL;
arrayCount = CFArrayGetCount( mValueArray );
for ( index = 0; index < arrayCount; index++ )
{
aDict = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( mValueArray, index );
if ( aDict != NULL )
{
tagValueString = (CFStringRef) CFDictionaryGetValue( aDict, CFSTR("tag") );
if ( tagValueString != NULL &&
CFStringCompare(tagValueString, searchTagValueString, kCFCompareCaseInsensitive) == kCFCompareEqualTo )
{
theDict = aDict;
break;
}
}
}
CFRelease( searchTagValueString );
return theDict;
}
char *
CAuthAuthority::GetDataForTag( const char *inTagStr, CFIndex inDataSegmentIndex )
{
char *retStr = NULL;
CFArrayRef aaDataArray = NULL;
CFMutableDictionaryRef aaDict = this->GetValueForTagAsCFDict( inTagStr );
if ( aaDict != NULL )
{
aaDataArray = (CFArrayRef) CFDictionaryGetValue( aaDict, CFSTR("data") );
if ( aaDataArray != NULL )
{
CFIndex arrayCount = CFArrayGetCount( aaDataArray );
if ( inDataSegmentIndex >= arrayCount )
return NULL;
CFStringRef aaDataString = (CFStringRef) CFArrayGetValueAtIndex( aaDataArray, inDataSegmentIndex );
if ( aaDataString == NULL )
return NULL;
// include room for a zero-terminator
size_t needSize = CFStringGetMaximumSizeForEncoding( CFStringGetLength(aaDataString), kCFStringEncodingUTF8 ) + 1;
retStr = (char *) malloc( needSize );
if ( retStr == NULL )
return NULL;
if ( !CFStringGetCString(aaDataString, retStr, needSize, kCFStringEncodingUTF8) ) {
free(retStr);
retStr = NULL;
}
}
}
return retStr;
}
bool
CAuthAuthority::SetValueForTag( const char *inTagStr, const char *inAuthAuthorityStr )
{
this->RemoveValueForTag( inTagStr );
return this->AddValue( inAuthAuthorityStr );
}
bool
CAuthAuthority::SetValueDisabledForTag( const char *inTagStr )
{
bool theResult = false;
CFMutableArrayRef dataArray = NULL;
CFStringRef tagString = NULL;
CFMutableDictionaryRef aaDict = this->GetValueForTagAsCFDict( inTagStr );
if ( aaDict != NULL )
{
dataArray = (CFMutableArrayRef) CFDictionaryGetValue( aaDict, CFSTR("data") );
if ( dataArray == NULL )
{
dataArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( dataArray == NULL )
return false;
CFDictionaryAddValue( aaDict, CFSTR("data"), dataArray );
CFRelease( dataArray );
}
// Insert the current tag into the data array
tagString = (CFStringRef) CFDictionaryGetValue( aaDict, CFSTR("tag") );
CFArrayInsertValueAtIndex( dataArray, 0, tagString );
CFArrayInsertValueAtIndex( dataArray, 0, CFSTR("") );
// replace the primary tag
CFDictionarySetValue( aaDict, CFSTR("tag"), CFSTR(kDSTagAuthAuthorityDisabledUser) );
theResult = true;
}
else
{
aaDict = this->GetValueForTagAsCFDict( kDSTagAuthAuthorityDisabledUser );
if ( aaDict != NULL )
{
// There's already a disabled Auth Authority, so check the first
// data item to see if it's a match for the tag
CFStringRef searchTagValueString = CFStringCreateWithCString( kCFAllocatorDefault, inTagStr, kCFStringEncodingUTF8 );
if ( searchTagValueString != NULL )
{
dataArray = (CFMutableArrayRef) CFDictionaryGetValue( aaDict, CFSTR("data") );
if ( dataArray != NULL )
{
tagString = (CFStringRef) CFArrayGetValueAtIndex( dataArray, 0 );
if ( tagString != NULL &&
CFStringCompare(searchTagValueString, tagString, kCFCompareCaseInsensitive) == kCFCompareEqualTo )
{
// already disabled
theResult = true;
}
}
CFRelease( searchTagValueString );
}
}
// if not disabled yet, disable
if ( theResult == false )
{
char disabledAAStr[256] = {0};
snprintf( disabledAAStr, sizeof(disabledAAStr), "%s;%s;", kDSValueAuthAuthorityDisabledUser, inTagStr );
theResult = this->AddValue( disabledAAStr );
}
}
return theResult;
}
bool
CAuthAuthority::SetDataForTag( const char *inTagStr, const char *inDataSegment, CFIndex inDataSegmentIndex )
{
CFIndex dataArrayCount = 0;
CFStringRef dataSegString = NULL;
CFMutableDictionaryRef aaDict = this->GetValueForTagAsCFDict( inTagStr );
if ( aaDict == NULL )
return false;
CFMutableArrayRef dataArray = (CFMutableArrayRef)CFDictionaryGetValue( aaDict, CFSTR("data") );
if ( dataArray == NULL )
{
if ( inDataSegmentIndex != 0 )
return false;
dataSegString = CFStringCreateWithCString( NULL, inDataSegment, kCFStringEncodingUTF8 );
dataArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
CFArrayAppendValue( dataArray, dataSegString );
CFRelease( dataSegString );
CFDictionaryAddValue( aaDict, CFSTR("data"), dataArray );
CFRelease( dataArray );
}
else
{
// Example: inDataSegmentIndex == 0, CFArrayGetCount(dataArray) == 1, then
// 0 (replace) & 1 (append) are valid positions, 2+ are not.
if ( inDataSegmentIndex > (dataArrayCount = CFArrayGetCount(dataArray)) )
return false;
dataSegString = CFStringCreateWithCString( NULL, inDataSegment, kCFStringEncodingUTF8 );
if ( inDataSegmentIndex == dataArrayCount )
{
CFArrayAppendValue( dataArray, dataSegString );
}
else
{
CFArraySetValueAtIndex( dataArray, inDataSegmentIndex, dataSegString );
}
CFRelease( dataSegString );
}
return true;
}
void
CAuthAuthority::RemoveValueForTag( const char *inTagStr )
{
CFIndex arrayCount = 0;
CFIndex index = 0;
CFDictionaryRef aDict = NULL;
CFStringRef tagValueString = NULL;
CFStringRef searchTagValueString = NULL;
if ( mValueArray == NULL )
return;
searchTagValueString = CFStringCreateWithCString( kCFAllocatorDefault, inTagStr, kCFStringEncodingUTF8 );
if ( searchTagValueString == NULL )
return;
arrayCount = CFArrayGetCount( mValueArray );
for ( index = arrayCount - 1; index >= 0; index-- )
{
aDict = (CFDictionaryRef) CFArrayGetValueAtIndex( mValueArray, index );
if ( aDict != NULL )
{
tagValueString = (CFStringRef) CFDictionaryGetValue( aDict, CFSTR("tag") );
if ( tagValueString != NULL &&
CFStringCompare(tagValueString, searchTagValueString, kCFCompareCaseInsensitive) == kCFCompareEqualTo )
{
CFArrayRemoveValueAtIndex( mValueArray, index );
}
}
}
CFRelease( searchTagValueString );
}
void
CAuthAuthority::ToggleDisabledAuthority( bool enable )
{
CFMutableDictionaryRef enableDict = NULL;
CFMutableArrayRef dataArray = NULL;
CFStringRef aString = NULL;
if ( enable )
{
mDisabledAuthorityStorage = this->GetValueForTagAsCFDict( kDSTagAuthAuthorityDisabledUser );
if ( mDisabledAuthorityStorage != NULL )
{
CFRetain( mDisabledAuthorityStorage );
this->RemoveValueForTag( kDSTagAuthAuthorityDisabledUser );
enableDict = CFDictionaryCreateMutableCopy( kCFAllocatorDefault, 0, mDisabledAuthorityStorage );
if ( enableDict != NULL )
{
dataArray = (CFMutableArrayRef) CFDictionaryGetValue( enableDict, CFSTR("data") );
if ( dataArray != NULL )
{
// remove the version, don't care
CFArrayRemoveValueAtIndex( dataArray, 0 );
// now, the top item is the tag
aString = (CFStringRef) CFArrayGetValueAtIndex( dataArray, 0 );
CFDictionarySetValue( enableDict, CFSTR("tag"), aString );
CFArrayRemoveValueAtIndex( dataArray, 0 );
// insert it into the authority list
CFArrayAppendValue( mValueArray, enableDict );
CFRelease( enableDict );
}
}
}
}
}
bool
CAuthAuthority::TagDisabled( const char *inTagStr )
{
bool result = false;
CFIndex arrayCount = 0;
CFIndex index = 0;
CFDictionaryRef aDict = NULL;
CFStringRef tagValueString = NULL;
CFStringRef searchTagValueString = NULL;
CFMutableArrayRef dataArray = NULL;
CFStringRef aString = NULL;
if ( mValueArray == NULL )
return false;
searchTagValueString = CFStringCreateWithCString( kCFAllocatorDefault, inTagStr, kCFStringEncodingUTF8 );
if ( searchTagValueString == NULL )
return false;
arrayCount = CFArrayGetCount( mValueArray );
for ( index = arrayCount - 1; index >= 0; index-- )
{
aDict = (CFDictionaryRef) CFArrayGetValueAtIndex( mValueArray, index );
if ( aDict != NULL )
{
tagValueString = (CFStringRef) CFDictionaryGetValue( aDict, CFSTR("tag") );
if ( tagValueString != NULL &&
CFStringCompare(tagValueString, CFSTR(kDSTagAuthAuthorityDisabledUser), kCFCompareCaseInsensitive) == kCFCompareEqualTo )
{
dataArray = (CFMutableArrayRef) CFDictionaryGetValue( aDict, CFSTR("data") );
if ( dataArray != NULL )
{
aString = (CFStringRef) CFArrayGetValueAtIndex( dataArray, 1 );
if ( aString != NULL &&
CFStringCompare(aString, searchTagValueString, kCFCompareCaseInsensitive) == kCFCompareEqualTo )
{
result = true;
break;
}
}
}
}
}
CFRelease( searchTagValueString );
return result;
}

62
pwpolicy/CAuthAuthority.h Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef __CAUTHAUTHORITY_H__
#define __CAUTHAUTHORITY_H__
#include <CoreFoundation/CoreFoundation.h>
#include <DirectoryService/DirServicesTypes.h>
class CAuthAuthority
{
public:
CAuthAuthority();
CAuthAuthority(CAuthAuthority &inAuthAuthority);
virtual ~CAuthAuthority();
virtual bool AddValue( const char *inAuthAuthorityStr );
virtual bool AddValue( CFStringRef inAuthAuthorityString );
virtual bool AddValues( CFArrayRef inAuthAuthorityArray );
virtual CFIndex GetValueCount( void );
virtual char * GetValueAtIndex( int inIndex );
virtual char * GetValueForTag( const char *inTagStr );
virtual CFMutableDictionaryRef GetValueForTagAsCFDict( const char *inTagStr );
virtual char * GetDataForTag( const char *inTagStr, CFIndex inDataSegmentIndex );
virtual bool SetValueForTag( const char *inTagStr, const char *inAuthAuthorityStr );
virtual bool SetValueDisabledForTag( const char *inTagStr );
virtual bool SetDataForTag( const char *inTagStr, const char *inDataSegment, CFIndex inDataSegmentIndex );
virtual void RemoveValueForTag( const char *inTagStr );
virtual void ToggleDisabledAuthority( bool enable );
virtual bool TagDisabled( const char *inTagStr );
protected:
CFMutableArrayRef mValueArray;
CFMutableDictionaryRef mDisabledAuthorityStorage;
private:
};
#endif

1926
pwpolicy/Main.cpp Normal file

File diff suppressed because it is too large Load Diff

1649
pwpolicy/PwdPolicyTool.cpp Normal file

File diff suppressed because it is too large Load Diff

184
pwpolicy/PwdPolicyTool.h Normal file
View File

@ -0,0 +1,184 @@
/*
* Copyright (c) 2000 - 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*!
* @header PwdPolicyTool
*/
#ifndef __PwdPolicyTool_h__
#define __PwdPolicyTool_h__ 1
#include <stdio.h>
#include <DirectoryService/DirectoryService.h>
#include <CoreServices/CoreServices.h>
#define kNewUserPass "test"
#define kHashNameListPrefix "HASHLIST:"
extern bool gVerbose;
// Main App's error types
typedef enum {
// NULL allocation errors
kErrDataBufferAllocate = 1,
kErrDataNodeAllocateBlock,
kErrDataNodeAllocateString,
kErrDataListAllocate,
kErrBuildFromPath,
kErrGetPathFromList,
kErrBuildListFromNodes,
kErrBuildListFromStrings,
kErrBuildListFromStringsAlloc,
kErrDataListCopyList,
kErrAllocAttributeValueEntry,
// Error associations
kErrOpenDirSrvc,
kErrCloseDirSrvc,
kErrDataListDeallocate,
kErrDataBufferDeAllocate,
kErrFindDirNodes,
kErrOpenRecord,
kErrCreateRecordAndOpen,
kErrCloseRecord,
kErrDeleteRecord,
kErrDataNodeDeAllocate,
kErrDataBuffDealloc,
kErrCreateRecord,
kErrAddAttribute,
kErrAddAttributeValue,
kErrSetAttributeValue,
kErrGetRecAttrValueByIndex,
kErrGetDirNodeName,
kErrOpenDirNode,
kErrCloseDirNode,
kErrGetRecordList,
kErrGetRecordEntry,
kErrGetAttributeEntry,
kErrGetAttributeValue,
kErrDeallocAttributeValueEntry,
kErrDoDirNodeAuth,
kErrGetRecordNameFromEntry,
kErrGetRecordTypeFromEntry,
kErrGetRecordAttributeInfo,
kErrGetRecordReferenceInfo,
kErrGetDirNodeInfo,
kErrGetDirNodeCount,
kErrGetDirNodeList,
kErrRemoveAttributeValue,
kErr,
kErrMemoryAlloc,
kErrEmptyDataBuff,
kErrEmptyDataParam,
kErrBuffTooSmall,
kErrMaxErrors,
kUnknownErr = 0xFF
} eErrCodes;
class PwdPolicyTool
{
public:
PwdPolicyTool ( void );
virtual ~PwdPolicyTool ( void );
tDirStatus Initialize ( void );
tDirStatus Deinitialize ( void );
tDirNodeReference GetLocalNodeRef ( void );
tDirNodeReference GetSearchNodeRef ( void );
tDirStatus GetUserByName ( tDirNodeReference inNode,
const char *inUserName,
const char *inRecordType,
char **outAuthAuthority,
char **outNodeName );
tDirStatus OpenRecord ( tDirNodeReference inNodeRef,
const char *inRecordType,
const char *inRecordName,
tRecordReference *outRecordRef,
bool inCreate = false );
void ChangeAuthAuthorityToShadowHash( tRecordReference inRecordRef );
int SetUserHashList( tRecordReference inRecordRef, int firstArg, int argc, char * const *argv );
tDirStatus FindDirectoryNodes ( char *inNodeName, tDirPatternMatch inMatch, char **outNodeNameList[], bool inPrintNames = false );
tDirStatus OpenLocalNode ( tDirNodeReference *outNodeRef );
tDirStatus OpenDirNode ( char *inNodeName, tDirNodeReference *outNodeRef );
tDirStatus CloseDirectoryNode ( tDirNodeReference inNodeRef );
tDirStatus DoNodePWAuth ( tDirNodeReference inNode,
const char *inName,
const char *inPasswd,
const char *inMethod,
const char *inUserName,
const char *inOther,
const char *inRecordType,
char *outResult );
tDirStatus DoNodeNativeAuth ( tDirNodeReference inNode, const char *inName, const char *inPasswd );
long GetHashTypes ( char **outHashTypesStr, bool inExcludeLMHash = false );
long SetHashTypes ( const char *inName, char *inPasswd, int arg1, int argc, char * const *argv );
long GetHashTypeArray ( CFMutableArrayRef *outHashTypeArray );
tDirReference GetDirRef (void) { return fDSRef; };
protected:
tDirStatus OpenDirectoryServices ( void );
tDirStatus CloseDirectoryServices ( void );
tDirStatus AllocateTDataBuff ( void );
tDirStatus DeallocateTDataBuff ( void );
tDirStatus DoGetRecordList ( tDirNodeReference inNodeRef,
const char *inRecName,
const char *inRecType,
const char *inAttrType,
tDirPatternMatch inMatchType,
char **outAuthAuthority,
char **outNodeName );
void AppendHashTypeToArray ( const char *inHashType, CFMutableArrayRef inHashTypeArray );
private:
tDirStatus SetUpAuthBuffs ( tDataBuffer **inAuthBuff, UInt32 inAuthBuffSize, tDataBuffer **inStepBuff, UInt32 inStepBuffSize, tDataBuffer **inTypeBuff, const char *inAuthMethod );
void PrintError ( long inErrCode, const char *messageTag = NULL );
tDirStatus GetDataFromDataBuff ( tDirNodeReference inNodeRef,
tDataBuffer *inTDataBuff,
UInt32 inRecCount,
char **outAuthAuthority,
char **outNodeName );
tDirReference fDSRef;
tDataBuffer *fTDataBuff;
tDirNodeReference fLocalNodeRef;
tDirNodeReference fSearchNodeRef;
tDirNodeReference fNodeRef;
};
#endif // __PwdPolicyTool_h__

Some files were not shown because too many files have changed in this diff Show More