mirror of
https://github.com/darlinghq/darling-DSTools.git
synced 2024-11-23 12:09:42 +00:00
b1d05a7ba1
It's for Homebrew
1476 lines
38 KiB
Objective-C
1476 lines
38 KiB
Objective-C
/*
|
|
* 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 dscl
|
|
* directory service command-line interface
|
|
* Main command processor derived from nicl source.
|
|
*/
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
|
#import <DirectoryService/DirectoryService.h>
|
|
#import <stdio.h>
|
|
#import <unistd.h>
|
|
#import <stdlib.h>
|
|
#import <sys/types.h>
|
|
#import <sys/ioctl.h>
|
|
#import <termios.h>
|
|
#import <histedit.h>
|
|
#import "PathManager.h"
|
|
#import "DSoStatus.h"
|
|
#import "DSoException.h"
|
|
#import "DSCLCommandHistory.h"
|
|
#import "NSStringEscPath.h"
|
|
#import "dstools_version.h"
|
|
#import <sysexits.h>
|
|
#import <sys/sysctl.h>
|
|
|
|
#import "PlugInManager.h" // ATM - support for plugins
|
|
|
|
#define streq(A,B) (strcmp(A,B) == 0)
|
|
#define forever for(;;)
|
|
|
|
static char myname[256];
|
|
PathManager *engine = nil;
|
|
BOOL gHACK = NO;
|
|
BOOL gURLEncode = NO;
|
|
static int interactive = 0;
|
|
|
|
#define INPUT_LENGTH 4096
|
|
|
|
#define PROMPT_NONE 0
|
|
#define PROMPT_PLAIN 1
|
|
#define PROMPT_DS 2
|
|
|
|
#define ATTR_CREATE 0
|
|
#define ATTR_APPEND 1
|
|
#define ATTR_MERGE 2
|
|
#define ATTR_DELETE 3
|
|
#define ATTR_CHANGE 4
|
|
#define ATTR_CHANGE_INDEX 5
|
|
|
|
//not all of these are actually used but are placeholder carryovers from nicl
|
|
static int minargs[] =
|
|
{
|
|
-1, // noop
|
|
1, // create
|
|
1, // delete
|
|
3, // rename
|
|
1, // read
|
|
1, // list
|
|
3, // append
|
|
3, // merge
|
|
4, // insert
|
|
2, // move
|
|
2, // copy
|
|
3, // search
|
|
1, // path
|
|
0, // pushd
|
|
0, // popd
|
|
2, // parent
|
|
1, // cd
|
|
0, // pwd
|
|
0, // version history
|
|
0, // stats
|
|
0, // domain name
|
|
0, // rparent
|
|
0, // resync
|
|
1, // authenticate
|
|
0, // refs
|
|
2, // setrdn
|
|
4, // change
|
|
4, // changei
|
|
1, // authonly
|
|
1, // readall
|
|
2, // diff
|
|
3, // readpl
|
|
4, // createpl
|
|
3, // deletepl
|
|
4, // readpli
|
|
5, // createpli
|
|
4 // deletepli
|
|
};
|
|
|
|
#define OP_NOOP 0
|
|
#define OP_CREATE 1
|
|
#define OP_DELETE 2
|
|
#define OP_READ 4
|
|
#define OP_LIST 5
|
|
#define OP_APPEND 6
|
|
#define OP_MERGE 7
|
|
#define OP_SEARCH 11
|
|
#define OP_PUSHD 13
|
|
#define OP_POPD 14
|
|
#define OP_CD 16
|
|
#define OP_PASSWD 18
|
|
#define OP_AUTH 23
|
|
#define OP_CHANGE 26
|
|
#define OP_CHANGE_INDEX 27
|
|
#define OP_AUTH_ONLY 28
|
|
#define OP_READALL 29
|
|
#define OP_DIFF 30
|
|
#define OP_READPL 31
|
|
#define OP_CREATEPL 32
|
|
#define OP_DELETEPL 33
|
|
#define OP_READPL_INDEX 34
|
|
#define OP_CREATEPL_INDEX 35
|
|
#define OP_DELETEPL_INDEX 36
|
|
|
|
void usage()
|
|
{
|
|
fprintf(stderr, "dscl (v%s)\n", TOOLS_VERSION);
|
|
fprintf(stderr, "usage: %s [options] [<datasource> [<command>]]\n", myname);
|
|
fprintf(stderr, "datasource:\n");
|
|
fprintf(stderr, " localhost (default) or\n");
|
|
fprintf(stderr, " localonly (activates a DirectoryService daemon process \n");
|
|
fprintf(stderr, " with Local node only - daemon quits after use \n");
|
|
fprintf(stderr, " <hostname> (requires DS proxy support, >= DS-158) or\n");
|
|
fprintf(stderr, " <nodename> (Directory Service style node name) or\n");
|
|
fprintf(stderr, " <domainname> (NetInfo style domain name)\n");
|
|
fprintf(stderr, "options:\n");
|
|
fprintf(stderr, " -u <user> authenticate as user (required when using DS Proxy)\n");
|
|
fprintf(stderr, " -P <password> authentication password\n");
|
|
fprintf(stderr, " -p prompt for password\n");
|
|
fprintf(stderr, " -f <filepath> targeted file path for DS daemon running in localonly mode\n");
|
|
fprintf(stderr, " (example: /Volumes/Build100/var/db/dslocal/nodes/Default) \n");
|
|
fprintf(stderr, " (NOTE: Nodename to use is fixed at /Local/Target) \n");
|
|
fprintf(stderr, " -raw don't strip off prefix from DS constants\n");
|
|
fprintf(stderr, " -plist print out record(s) or attribute(s) in XML plist format\n");
|
|
fprintf(stderr, " -url print record attribute values in URL-style encoding\n");
|
|
fprintf(stderr, " -q quiet - no interactive prompt\n");
|
|
fprintf(stderr, "commands:\n");
|
|
fprintf(stderr, " -read <path> [<key>...]\n");
|
|
fprintf(stderr, " -readall <path> [<key>...]\n");
|
|
fprintf(stderr, " -readpl <path> <key> <plist path>\n");
|
|
fprintf(stderr, " -readpli <path> <key> <value index> <plist path>\n");
|
|
fprintf(stderr, " -create <record path> [<key> [<val>...]]\n");
|
|
fprintf(stderr, " -createpl <record path> <key> <plist path> <val1> [<val2>...]\n");
|
|
fprintf(stderr, " -createpli <record path> <key> <value index> <plist path> <val1> [<val2>...]\n");
|
|
fprintf(stderr, " -delete <path> [<key> [<val>...]]\n");
|
|
fprintf(stderr, " -deletepl <record path> <key> <plist path> [<val>...]\n");
|
|
fprintf(stderr, " -deletepli <record path> <key> <value index> <plist path> [<val>...]\n");
|
|
fprintf(stderr, " -list <path> [<key>]\n");
|
|
fprintf(stderr, " -append <record path> <key> <val>...\n");
|
|
fprintf(stderr, " -merge <record path> <key> <val>...\n");
|
|
fprintf(stderr, " -change <record path> <key> <old value> <new value>\n");
|
|
fprintf(stderr, " -changei <record path> <key> <value index> <new value>\n");
|
|
fprintf(stderr, " -diff <first path> <second path>\n");
|
|
fprintf(stderr, " -search <path> <key> <val>\n");
|
|
fprintf(stderr, " -auth [<user> [<password>]]\n");
|
|
fprintf(stderr, " -authonly [<user> [<password>]]\n");
|
|
fprintf(stderr, " -passwd <user path> [<new password> | <old password> <new password>]\n");
|
|
|
|
// ATM - give the plugins a chance to display their own help
|
|
dscl_PlugInShowUsage(stderr);
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_attribute(u_int32_t dsid, int flag, int argc, char *argv[])
|
|
{
|
|
// <path> [<key> [<val>...]]
|
|
|
|
tDirStatus status = eDSNoErr;
|
|
u_int32_t i;
|
|
NSString *path = nil;
|
|
NSString *key = nil;
|
|
NSMutableArray *values = nil;
|
|
|
|
if (argc == 0) return eDSNoErr;
|
|
|
|
path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
|
|
argc--;
|
|
argv++;
|
|
|
|
if (argc > 0 && argv[0] != NULL)
|
|
{
|
|
// We have a key to use:
|
|
key = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
argc--;
|
|
argv++;
|
|
if (argc > 0 && argv[0] != NULL)
|
|
{
|
|
// we have values
|
|
NSString *val;
|
|
values = [[NSMutableArray alloc] initWithCapacity:argc];
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
val = [[NSString alloc] initWithUTF8String:argv[i]];
|
|
[values addObject:val];
|
|
[val release];
|
|
}
|
|
}
|
|
}
|
|
|
|
NS_DURING
|
|
switch (flag)
|
|
{
|
|
case ATTR_CREATE:
|
|
status = [engine createRecord:path key:key values:values];
|
|
break;
|
|
case ATTR_APPEND:
|
|
status = [engine appendToRecord:path key:key values:values];
|
|
break;
|
|
case ATTR_MERGE:
|
|
status = [engine mergeToRecord:path key:key values:values];
|
|
break;
|
|
case ATTR_DELETE:
|
|
status = [engine deleteInRecord:path key:key values:values];
|
|
break;
|
|
case ATTR_CHANGE:
|
|
status = [engine changeInRecord:path key:key values:values];
|
|
break;
|
|
case ATTR_CHANGE_INDEX:
|
|
status = [engine changeInRecordByIndex:path key:key values:values];
|
|
break;
|
|
}
|
|
NS_HANDLER
|
|
[path release];
|
|
[key release];
|
|
[values release];
|
|
[localException raise];
|
|
NS_ENDHANDLER
|
|
|
|
if (status != eDSNoErr)
|
|
fprintf(stderr, "<main> attribute status: %s\n", [[DSoStatus sharedInstance] cStringForStatus:status]);
|
|
|
|
[path release];
|
|
[key release];
|
|
[values release];
|
|
|
|
return status;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_create(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
return dscl_attribute(dsid, ATTR_CREATE, argc, argv);
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_append(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
return dscl_attribute(dsid, ATTR_APPEND, argc, argv);
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_merge(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
return dscl_attribute(dsid, ATTR_MERGE, argc, argv);
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_change(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
return dscl_attribute(dsid, ATTR_CHANGE, argc, argv);
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_change_index(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
return dscl_attribute(dsid, ATTR_CHANGE_INDEX, argc, argv);
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_delete(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <path> [<key> [<val>...]]
|
|
|
|
tDirStatus status = eDSNoErr;
|
|
|
|
if (argc == 0)
|
|
{
|
|
fprintf(stderr, "<main> delete requires a path\n");
|
|
}
|
|
if (argc == 1)
|
|
{
|
|
// We are deleting a whole record:
|
|
status = [engine deleteRecord:[NSString stringWithUTF8String:argv[0]]];
|
|
if (status != eDSNoErr)
|
|
fprintf(stderr, "<main> delete status: %s\n", [[DSoStatus sharedInstance] cStringForStatus:status]);
|
|
}
|
|
else
|
|
{
|
|
// we are just deleting keys and/or values from a record.
|
|
status = dscl_attribute(dsid, ATTR_DELETE, argc, argv);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
tDirStatus
|
|
dscl_diff(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <path1> <path2> [<key> ...]
|
|
|
|
NSString *path1 = nil;
|
|
NSString *path2 = nil;
|
|
NSMutableArray *keys = nil;
|
|
|
|
path1 = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
path2 = [[NSString alloc] initWithUTF8String:argv[1
|
|
]];
|
|
argc -= 2;
|
|
argv += 2;
|
|
|
|
keys = [[NSMutableArray alloc] initWithCapacity:argc];
|
|
|
|
while (argc > 0)
|
|
{
|
|
[keys addObject:[NSString stringWithUTF8String:argv[0]]];
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
NS_DURING
|
|
[engine diff:path1 otherPath:path2 keys:keys];
|
|
NS_HANDLER
|
|
[keys release];
|
|
[path1 release];
|
|
[path2 release];
|
|
[localException raise];
|
|
NS_ENDHANDLER
|
|
|
|
[keys release];
|
|
[path1 release];
|
|
[path2 release];
|
|
|
|
return eDSNoErr;
|
|
}
|
|
|
|
|
|
tDirStatus
|
|
dscl_read(u_int32_t dsid, int argc, char *argv[], BOOL all)
|
|
{
|
|
// <path> [<key> ...]
|
|
|
|
NSString *path = nil;
|
|
NSMutableArray *keys = nil;
|
|
|
|
if (argc == 0)
|
|
{
|
|
if (all)
|
|
return [engine readAll:nil keys:nil];
|
|
else
|
|
return [engine read:nil keys:nil];
|
|
}
|
|
|
|
path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
argc--;
|
|
argv++;
|
|
|
|
keys = [[NSMutableArray alloc] initWithCapacity:argc];
|
|
|
|
while (argc > 0)
|
|
{
|
|
[keys addObject:[NSString stringWithUTF8String:argv[0]]];
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
@try {
|
|
if (all)
|
|
return [engine readAll:path keys:keys];
|
|
else
|
|
return [engine read:path keys:keys];
|
|
}
|
|
@finally {
|
|
[keys release];
|
|
[path release];
|
|
}
|
|
|
|
return eDSNoErr;
|
|
}
|
|
|
|
|
|
tDirStatus
|
|
dscl_readpl(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <path> <key> <plist path>
|
|
|
|
NSString *path = nil;
|
|
NSString *key = nil;
|
|
NSString *plistPath = nil;
|
|
|
|
path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
key = [[NSString alloc] initWithUTF8String:argv[1]];
|
|
plistPath = [[NSString alloc] initWithUTF8String:argv[2]];
|
|
|
|
NS_DURING
|
|
NS_VALUERETURN(([engine read:path key:key plistPath:plistPath]), tDirStatus);
|
|
NS_HANDLER
|
|
[path release];
|
|
[localException raise];
|
|
NS_ENDHANDLER
|
|
|
|
[path release];
|
|
|
|
return eDSNoErr;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_readpli(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <path> <key> <value index> <plist path>
|
|
|
|
NSString *path = nil;
|
|
NSString *key = nil;
|
|
NSString *plistPath = nil;
|
|
NSString *sindex = nil;
|
|
int index = 0;
|
|
|
|
path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
key = [[NSString alloc] initWithUTF8String:argv[1]];
|
|
sindex = [[NSString alloc] initWithUTF8String:argv[2]];
|
|
plistPath = [[NSString alloc] initWithUTF8String:argv[3]];
|
|
index = [sindex intValue];
|
|
|
|
NS_DURING
|
|
NS_VALUERETURN(([engine read:path key:key atIndex:index plistPath:plistPath]), tDirStatus);
|
|
NS_HANDLER
|
|
[path release];
|
|
[localException raise];
|
|
NS_ENDHANDLER
|
|
|
|
[path release];
|
|
|
|
return eDSNoErr;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_createpl(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <record path> <key> <plist path> <val1> [<val2>...]
|
|
|
|
NSString *path = nil;
|
|
NSString *key = nil;
|
|
NSString *plistPath = nil;
|
|
NSMutableArray *values = nil;
|
|
|
|
path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
key = [[NSString alloc] initWithUTF8String:argv[1]];
|
|
plistPath = [[NSString alloc] initWithUTF8String:argv[2]];
|
|
unsigned int c;
|
|
values = [[NSMutableArray alloc] init];
|
|
for(c = 3; c < argc; c++)
|
|
{
|
|
[values addObject:[NSString stringWithUTF8String:argv[c]]];
|
|
}
|
|
|
|
NS_DURING
|
|
NS_VALUERETURN(([engine create:path key:key plistPath:plistPath values:values]), tDirStatus);
|
|
NS_HANDLER
|
|
[path release];
|
|
[localException raise];
|
|
NS_ENDHANDLER
|
|
|
|
[path release];
|
|
return eDSNoErr;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_createpli(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <record path> <key> <plist path> <val1> [<val2>...]
|
|
|
|
NSString *path = nil;
|
|
NSString *key = nil;
|
|
NSString *plistPath = nil;
|
|
NSMutableArray *values = nil;
|
|
NSString *sindex = nil;
|
|
int index = 0;
|
|
|
|
path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
key = [[NSString alloc] initWithUTF8String:argv[1]];
|
|
sindex = [[NSString alloc] initWithUTF8String:argv[2]];
|
|
plistPath = [[NSString alloc] initWithUTF8String:argv[3]];
|
|
index = [sindex intValue];
|
|
|
|
unsigned int c;
|
|
values = [[NSMutableArray alloc] init];
|
|
for(c = 4; c < argc; c++)
|
|
{
|
|
[values addObject:[NSString stringWithUTF8String:argv[c]]];
|
|
}
|
|
|
|
NS_DURING
|
|
NS_VALUERETURN(([engine create:path key:key atIndex:index plistPath:plistPath values:values]), tDirStatus);
|
|
NS_HANDLER
|
|
[path release];
|
|
[localException raise];
|
|
NS_ENDHANDLER
|
|
|
|
[path release];
|
|
return eDSNoErr;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_deletepl(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <path> <key> <plist path> [<val>...]
|
|
NSString *path = nil;
|
|
NSString *key = nil;
|
|
NSString *plistPath = nil;
|
|
NSMutableArray *values = nil;
|
|
|
|
path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
key = [[NSString alloc] initWithUTF8String:argv[1]];
|
|
plistPath = [[NSString alloc] initWithUTF8String:argv[2]];
|
|
unsigned int c;
|
|
values = [[NSMutableArray alloc] init];
|
|
for(c = 3; c < argc; c++)
|
|
{
|
|
[values addObject:[NSString stringWithUTF8String:argv[c]]];
|
|
}
|
|
|
|
NS_DURING
|
|
NS_VALUERETURN(([engine delete:path key:key plistPath:plistPath values:values]), tDirStatus);
|
|
NS_HANDLER
|
|
[path release];
|
|
[localException raise];
|
|
NS_ENDHANDLER
|
|
|
|
[path release];
|
|
return eDSNoErr;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_deletepli(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <path> <key> <value index> <plist path> [<val>...]
|
|
NSString *path = nil;
|
|
NSString *key = nil;
|
|
NSString *plistPath = nil;
|
|
NSMutableArray *values = nil;
|
|
NSString *sindex = nil;
|
|
int index = 0;
|
|
|
|
path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
key = [[NSString alloc] initWithUTF8String:argv[1]];
|
|
sindex = [[NSString alloc] initWithUTF8String:argv[2]];
|
|
plistPath = [[NSString alloc] initWithUTF8String:argv[3]];
|
|
index = [sindex intValue];
|
|
|
|
unsigned int c;
|
|
values = [[NSMutableArray alloc] init];
|
|
for(c = 4; c < argc; c++)
|
|
{
|
|
[values addObject:[NSString stringWithUTF8String:argv[c]]];
|
|
}
|
|
|
|
NS_DURING
|
|
NS_VALUERETURN(([engine delete:path key:key atIndex:index plistPath:plistPath values:values]), tDirStatus);
|
|
NS_HANDLER
|
|
[path release];
|
|
[localException raise];
|
|
NS_ENDHANDLER
|
|
|
|
[path release];
|
|
return eDSNoErr;
|
|
}
|
|
|
|
|
|
|
|
tDirStatus
|
|
dscl_list(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <path> [<key>]
|
|
|
|
NSString *path = nil;
|
|
NSString *key = nil;
|
|
|
|
if (argc > 0)
|
|
{
|
|
if (argv[0] != NULL)
|
|
path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
if (argc > 1 && argv[1] != NULL)
|
|
key = [[NSString alloc] initWithUTF8String:argv[1]];
|
|
}
|
|
[engine list:path key:key];
|
|
[path release];
|
|
[key release];
|
|
|
|
return eDSNoErr;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_cd(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
if (argc > 0 && argv[0] != NULL)
|
|
[engine cd:[NSString stringWithUTF8String:argv[0]]];
|
|
|
|
return eDSNoErr;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_search(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <path> <key> <val> [<match type>]
|
|
|
|
tDirStatus status = eDSNoErr;
|
|
NSString *path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
NSString *key = [[NSString alloc] initWithUTF8String:argv[1]];
|
|
NSString *valuePattern = [[NSString alloc] initWithUTF8String:argv[2]];
|
|
NSString *matchType = nil;
|
|
|
|
if (argc > 3)
|
|
matchType = [[NSString alloc] initWithUTF8String:argv[3]];
|
|
|
|
NS_DURING
|
|
[engine searchInPath:path forKey:key withValue:valuePattern matchType:matchType];
|
|
NS_HANDLER
|
|
[path release];
|
|
[key release];
|
|
[valuePattern release];
|
|
[matchType release];
|
|
[localException raise];
|
|
NS_ENDHANDLER
|
|
|
|
[path release];
|
|
[key release];
|
|
[valuePattern release];
|
|
[matchType release];
|
|
|
|
return status;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_pushd(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// [<path>]
|
|
|
|
tDirStatus status = eDSNoErr;
|
|
NSString *path = nil;
|
|
|
|
if (argc == 0)
|
|
[engine pushd:nil];
|
|
else
|
|
{
|
|
path = [[NSString alloc] initWithUTF8String:argv[0]];
|
|
[engine pushd:path];
|
|
[path release];
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_popd(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
// <path> <dsid>
|
|
|
|
tDirStatus status = eDSNoErr;
|
|
|
|
[engine popd];
|
|
|
|
return status;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_set_password(u_int32_t dsid, int argc, char *argv[])
|
|
{
|
|
NSString *path;
|
|
id passwordItems = nil;
|
|
tDirStatus status = eDSNoErr;
|
|
|
|
if (argc < 1 || argc > 3)
|
|
{
|
|
return eDSAuthFailed;
|
|
}
|
|
else
|
|
{
|
|
path = [NSString stringWithUTF8String:argv[0]];
|
|
if (path == nil) return eDSAuthFailed;
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
if (argc > 0)
|
|
{
|
|
passwordItems = [NSMutableArray arrayWithCapacity:argc];
|
|
for (;argc > 0; argc--, argv++) {
|
|
[passwordItems addObject:[NSString stringWithUTF8String:argv[0]]];
|
|
bzero( argv[0], strlen(argv[0]) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
passwordItems = [NSArray arrayWithObject:[NSString stringWithUTF8String:getpass("New Password: ")]];
|
|
}
|
|
|
|
status = [engine setPasswordForUser:path withParams:passwordItems];
|
|
|
|
return status;
|
|
}
|
|
|
|
tDirStatus
|
|
dscl_authenticate(int argc, char *argv[], BOOL inAuthOnly)
|
|
{
|
|
NSString *u = nil;
|
|
NSString *p = nil;
|
|
tDirStatus status = eDSNoErr;
|
|
|
|
if (argc == 0)
|
|
{
|
|
u = @"root";
|
|
}
|
|
else
|
|
{
|
|
u = [NSString stringWithUTF8String:argv[0]];
|
|
if (u == nil) return eDSAuthFailed;
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
if (argc > 0)
|
|
{
|
|
p = [NSString stringWithUTF8String:argv[0]];
|
|
}
|
|
else
|
|
{
|
|
p = [NSString stringWithUTF8String:getpass("Password: ")];
|
|
}
|
|
|
|
if (p == NULL)
|
|
{
|
|
return eDSAuthFailed;
|
|
}
|
|
|
|
status = [engine authenticateUser:u password:p authOnly:inAuthOnly];
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
int
|
|
dscl_cmd(int cc, char *cv[])
|
|
{
|
|
tDirStatus status = eDSNoErr;
|
|
int op = OP_NOOP;
|
|
int dsid = 0; //not used but left for future?
|
|
int do_path = 1;
|
|
char *cmd = nil;
|
|
|
|
cmd = cv[0];
|
|
if (cmd[0] == '-') cmd++;
|
|
|
|
if (streq(cmd, "help"))
|
|
{
|
|
usage();
|
|
return eDSNoErr;
|
|
}
|
|
|
|
else if (streq(cmd, "create")) op = OP_CREATE;
|
|
else if (streq(cmd, "createprop")) op = OP_CREATE;
|
|
else if (streq(cmd, "createpl")) op = OP_CREATEPL;
|
|
else if (streq(cmd, "createpli")) op = OP_CREATEPL_INDEX;
|
|
else if (streq(cmd, "delete")) op = OP_DELETE;
|
|
else if (streq(cmd, "destroy")) op = OP_DELETE;
|
|
else if (streq(cmd, "destroyprop")) op = OP_DELETE;
|
|
else if (streq(cmd, "deletepl")) op = OP_DELETEPL;
|
|
else if (streq(cmd, "deletepli")) op = OP_DELETEPL_INDEX;
|
|
else if (streq(cmd, "read")) op = OP_READ;
|
|
else if (streq(cmd, "readall")) op = OP_READALL;
|
|
else if (streq(cmd, "readpl")) op = OP_READPL;
|
|
else if (streq(cmd, "readpli")) op = OP_READPL_INDEX;
|
|
else if (streq(cmd, "diff")) op = OP_DIFF;
|
|
else if (streq(cmd, "list")) op = OP_LIST;
|
|
else if (streq(cmd, "append")) op = OP_APPEND;
|
|
else if (streq(cmd, "merge")) op = OP_MERGE;
|
|
else if (streq(cmd, "search")) op = OP_SEARCH;
|
|
else if (streq(cmd, "pushd")) op = OP_PUSHD;
|
|
else if (streq(cmd, "pd")) op = OP_PUSHD;
|
|
else if (streq(cmd, "popd")) op = OP_POPD;
|
|
else if (streq(cmd, "cd")) op = OP_CD;
|
|
else if (streq(cmd, "mk")) op = OP_CREATE;
|
|
else if (streq(cmd, "rm")) op = OP_DELETE;
|
|
else if (streq(cmd, "cat")) op = OP_READ;
|
|
else if (streq(cmd, ".")) op = OP_READ;
|
|
else if (streq(cmd, "ls")) op = OP_LIST;
|
|
else if (streq(cmd, "passwd")) op = OP_PASSWD;
|
|
|
|
else if (streq(cmd, "auth") || streq(cmd, "su"))
|
|
{
|
|
op = OP_AUTH;
|
|
do_path = 0;
|
|
}
|
|
|
|
else if (streq(cmd, "authonly"))
|
|
{
|
|
op = OP_AUTH_ONLY;
|
|
do_path = 0;
|
|
}
|
|
|
|
else if (streq(cmd, "change")) op = OP_CHANGE;
|
|
else if (streq(cmd, "changei")) op = OP_CHANGE_INDEX;
|
|
|
|
// ATM - the command is not a built-in command; see if any of the plugin(s) will claim it
|
|
else if (dscl_PlugInDispatch(cc, cv, interactive, dsid, engine, &status))
|
|
{
|
|
// Exit codes seem to get truncated to 0...255 range so if we get something outside this range, convert to something standardized
|
|
if (status < 0 || status > EX__MAX /* 78 */)
|
|
status = EX_OSERR;
|
|
return status;
|
|
}
|
|
|
|
else
|
|
{
|
|
usage();
|
|
return eDSNoErr;
|
|
}
|
|
|
|
cc--;
|
|
cv++;
|
|
|
|
if ((interactive == 1) && (cc == 0) && (minargs[op] == 1))
|
|
{
|
|
// default path arg to current directory
|
|
}
|
|
else if (cc < minargs[op])
|
|
{
|
|
fprintf(stderr, "Too few parameters for %s operation\n", cmd);
|
|
usage();
|
|
return EX_USAGE;
|
|
}
|
|
|
|
status = eDSNoErr;
|
|
|
|
NS_DURING
|
|
switch (op)
|
|
{
|
|
case OP_NOOP:
|
|
status = eDSNoErr;
|
|
break;
|
|
case OP_CREATE:
|
|
status = dscl_create(dsid, cc, cv);
|
|
break;
|
|
case OP_DELETE:
|
|
status = dscl_delete(dsid, cc, cv);
|
|
break;
|
|
case OP_READ:
|
|
status = dscl_read(dsid, cc, cv, NO);
|
|
break;
|
|
case OP_READALL:
|
|
status = dscl_read(dsid, cc, cv, YES);
|
|
break;
|
|
case OP_READPL:
|
|
status = dscl_readpl(dsid, cc, cv);
|
|
break;
|
|
case OP_READPL_INDEX:
|
|
status = dscl_readpli(dsid, cc, cv);
|
|
break;
|
|
case OP_CREATEPL:
|
|
status = dscl_createpl(dsid, cc, cv);
|
|
break;
|
|
case OP_CREATEPL_INDEX:
|
|
status = dscl_createpli(dsid, cc, cv);
|
|
break;
|
|
case OP_DELETEPL:
|
|
status = dscl_deletepl(dsid, cc, cv);
|
|
break;
|
|
case OP_DELETEPL_INDEX:
|
|
status = dscl_deletepli(dsid, cc, cv);
|
|
break;
|
|
case OP_DIFF:
|
|
status = dscl_diff(dsid, cc, cv);
|
|
break;
|
|
case OP_LIST:
|
|
status = dscl_list(dsid, cc, cv);
|
|
break;
|
|
case OP_APPEND:
|
|
status = dscl_append(dsid, cc, cv);
|
|
break;
|
|
case OP_MERGE:
|
|
status = dscl_merge(dsid, cc, cv);
|
|
break;
|
|
case OP_SEARCH:
|
|
status = dscl_search(dsid, cc, cv);
|
|
break;
|
|
case OP_PUSHD:
|
|
status = dscl_pushd(dsid, cc, cv);
|
|
break;
|
|
case OP_POPD:
|
|
status = dscl_popd(dsid, cc, cv);
|
|
break;
|
|
case OP_CD:
|
|
status = dscl_cd(dsid, cc, cv);
|
|
break;
|
|
case OP_PASSWD:
|
|
status = dscl_set_password(dsid, cc, cv);
|
|
break;
|
|
case OP_AUTH_ONLY:
|
|
status = dscl_authenticate(cc, cv, YES);
|
|
break;
|
|
case OP_AUTH:
|
|
status = dscl_authenticate(cc, cv, NO);
|
|
break;
|
|
case OP_CHANGE:
|
|
status = dscl_change(dsid, cc, cv);
|
|
break;
|
|
case OP_CHANGE_INDEX:
|
|
status = dscl_change_index(dsid, cc, cv);
|
|
break;
|
|
}
|
|
|
|
NS_HANDLER
|
|
[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
|
|
if (status != eDSNoErr)
|
|
fprintf(stderr, "<dscl_cmd> DS Error: %d (%s)\n", status, [[DSoStatus sharedInstance] cStringForStatus:status]);
|
|
|
|
// Reverse the sign in order to exit with a positive value.
|
|
// Certain external tool expect this to be positive.
|
|
return -status;
|
|
}
|
|
|
|
char *
|
|
dscl_get_string(char **s)
|
|
{
|
|
char *p = nil;
|
|
char *x = nil;
|
|
int i = 0;
|
|
int quote = 0;
|
|
int esc = 0;
|
|
|
|
if (*s == NULL) return NULL;
|
|
if (**s == '\0') return NULL;
|
|
|
|
// Skip leading white space
|
|
while ((**s == ' ') || (**s == '\t')) *s += 1;
|
|
|
|
if (**s == '\0') return NULL;
|
|
|
|
x = *s;
|
|
|
|
if (*x == '\"' || *x == '\'')
|
|
{
|
|
quote = 1;
|
|
*s += 1;
|
|
x = *s;
|
|
}
|
|
|
|
forever
|
|
{
|
|
if (x[i] == '\0') break;
|
|
if ((quote == 1) && ((x[i] == '\"') || (x[i] == '\''))) break;
|
|
if ((quote == 0) && (x[i] == ' ' )) break;
|
|
if ((quote == 0) && (x[i] == '\t')) break;
|
|
|
|
if (x[i] == '\\')
|
|
{
|
|
if (esc == 0) esc = i;
|
|
i++;
|
|
if (x[i] == '\0') break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
p = malloc(i+1);
|
|
memmove(p, x, i);
|
|
p[i] = 0;
|
|
|
|
if (quote == 1) i++;
|
|
*s += i;
|
|
|
|
while (esc != 0)
|
|
{
|
|
i = esc + 1;
|
|
if (p[i] == '\\') i++;
|
|
esc = 0;
|
|
for (; p[i] != '\0'; i++)
|
|
{
|
|
p[i-1] = p[i];
|
|
if ((p[i] == '\\') && (esc == 0)) esc = i - 1;
|
|
}
|
|
p[i - 1] = '\0';
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
int
|
|
dscl_tabcomplete(EditLine *e, int ch)
|
|
{
|
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
NSArray *possibleCompletions = nil;
|
|
int cntLimit = 0;
|
|
const LineInfo *li = el_line(e);
|
|
|
|
// Remove any pre-existing trailing slash:
|
|
if (*(li->lastchar) == '/')
|
|
{
|
|
el_deletestr(e, 1);
|
|
}
|
|
|
|
NSString *inputLine = [[NSString alloc] initWithBytes:li->buffer length:(li->lastchar - li->buffer) encoding:NSUTF8StringEncoding];
|
|
NSRange cmdSeparator = [inputLine rangeOfString:@" "]; // find the command-line separator
|
|
|
|
if( cmdSeparator.location != NSNotFound )
|
|
{
|
|
NSMutableString *completePath = [NSMutableString stringWithString:[inputLine substringFromIndex: (cmdSeparator.location + 1)]];
|
|
NSMutableArray *lineComponents = [NSMutableArray arrayWithArray: [completePath unescapedPathComponents]];
|
|
NSString *partialPath = [lineComponents lastObject];
|
|
|
|
possibleCompletions = [engine getPossibleCompletionsFor: completePath];
|
|
if (possibleCompletions != nil)
|
|
{
|
|
cntLimit = [possibleCompletions count];
|
|
if (cntLimit > 0)
|
|
{
|
|
// For now, newLine is just the current completion.
|
|
NSEnumerator *compEnum = [possibleCompletions objectEnumerator];
|
|
NSString *partialMatch = [compEnum nextObject];
|
|
NSString *currentItem;
|
|
|
|
while( currentItem = [compEnum nextObject] )
|
|
{
|
|
NSString *commonMatch = [currentItem commonPrefixWithString:partialMatch options:NSCaseInsensitiveSearch];
|
|
if( [commonMatch length] < [partialMatch length] )
|
|
partialMatch = commonMatch;
|
|
}
|
|
|
|
// Remove the partial item from the input line to
|
|
// make room for the complete value.
|
|
el_deletestr(e, [[partialPath escapedString] length]);
|
|
|
|
// If there were multiple completion possibilities, list
|
|
// them out for the user.
|
|
if (cntLimit > 1)
|
|
{
|
|
putchar('\n');
|
|
|
|
compEnum = [possibleCompletions objectEnumerator];
|
|
while( currentItem = [compEnum nextObject] ) {
|
|
printf("%s \t", [[currentItem escapedString] UTF8String]);
|
|
}
|
|
|
|
putchar('\n');
|
|
// Insert the partial completion into the input line
|
|
el_insertstr(e, [[partialMatch escapedString] UTF8String]);
|
|
}
|
|
else
|
|
{
|
|
// Otherwise add a trailing slash and do in-line
|
|
// completion since this is the only completion.
|
|
el_insertstr(e, [[[partialMatch escapedString] stringByAppendingString:@"/"] UTF8String]);
|
|
}
|
|
|
|
}
|
|
else
|
|
putchar(7);
|
|
}
|
|
else
|
|
putchar(7);
|
|
}
|
|
|
|
[inputLine release];
|
|
[pool release];
|
|
|
|
switch (cntLimit)
|
|
{
|
|
case 0:
|
|
return CC_ARGHACK;
|
|
break;
|
|
case 1:
|
|
return CC_REFRESH;
|
|
break;
|
|
default:
|
|
return CC_REDISPLAY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static char *
|
|
dscl_input_line(FILE *in, EditLine *el, History *h)
|
|
{
|
|
HistEvent hev;
|
|
const char *eline = NULL;
|
|
char *out = NULL;
|
|
char fline[INPUT_LENGTH];
|
|
int count = 0;
|
|
int len = 0;
|
|
|
|
if (el == NULL)
|
|
{
|
|
count = fscanf(in, "%[^\n]%*c", fline);
|
|
if (count < 0) return NULL;
|
|
if (count == 0)
|
|
{
|
|
fscanf(in, "%*c");
|
|
out = calloc(1, 1);
|
|
return out;
|
|
}
|
|
len = strlen(fline);
|
|
out = malloc(len + 1);
|
|
memmove(out, fline, len);
|
|
out[len] = '\0';
|
|
return out;
|
|
}
|
|
|
|
eline = el_gets(el, &count);
|
|
if (eline == NULL) return NULL;
|
|
if (count <= 0) return NULL;
|
|
|
|
|
|
// Strip trailing '/' if it's not by itself.
|
|
if (count >= 3 && eline[count-2] == '/' && eline[count-3] != ' ')
|
|
len = count - 2;
|
|
else
|
|
len = count - 1;
|
|
|
|
out = malloc(len + 1);
|
|
memmove(out, eline, len);
|
|
out[len] = '\0';
|
|
if (len > 0) history(h, &hev, H_ENTER, out);
|
|
|
|
return out;
|
|
}
|
|
|
|
char *
|
|
dscl_prompt(EditLine *el)
|
|
{
|
|
NSString *P = [NSString stringWithFormat:@"\e[1m%@\e[0m > ", [[engine cwd] unescapedString]];
|
|
return (char*)[P UTF8String];
|
|
}
|
|
|
|
int
|
|
dscl_interactive(FILE *in, int pmt)
|
|
{
|
|
char *s = nil;
|
|
char *p = nil;
|
|
char **iargv = NULL;
|
|
char *line = NULL;
|
|
int i = 0;
|
|
int iargc = 0;
|
|
int quote = 0;
|
|
int esc = 0;
|
|
EditLine *el = NULL;
|
|
History *h = NULL;
|
|
HistEvent hev;
|
|
NSAutoreleasePool *foreverPool = nil;
|
|
|
|
interactive = 1;
|
|
|
|
if (pmt != PROMPT_NONE)
|
|
{
|
|
el = el_init("dscl", in, stdout, stderr);
|
|
h = history_init();
|
|
|
|
el_set(el, EL_HIST, history, h);
|
|
el_set(el, EL_PROMPT, dscl_prompt);
|
|
el_set(el, EL_EDITOR, "emacs");
|
|
el_set(el, EL_SIGNAL, 1);
|
|
el_set(el, EL_EDITMODE, 1);
|
|
|
|
// Tell the command line editor library to use
|
|
// the tab completion routine when tab is pressed.
|
|
el_set(el, EL_ADDFN, "tabcomplete", "Tab completion", dscl_tabcomplete);
|
|
el_set(el, EL_BIND, "^I", "tabcomplete", NULL);
|
|
|
|
history(h, &hev, H_SETSIZE, 100000);
|
|
}
|
|
|
|
forever
|
|
{
|
|
foreverPool = [[NSAutoreleasePool alloc] init];
|
|
line = dscl_input_line(in, el, h);
|
|
|
|
if (line == NULL) break;
|
|
if (line[0] == '\0')
|
|
{
|
|
free(line);
|
|
continue;
|
|
}
|
|
|
|
if (streq(line, "exit")) break;
|
|
if (streq(line, "quit")) break;
|
|
if (streq(line, "q")) break;
|
|
|
|
p = line;
|
|
iargc = 0;
|
|
quote = 0;
|
|
esc = 0;
|
|
|
|
forever
|
|
{
|
|
s = dscl_get_string(&p);
|
|
if (s == NULL) break;
|
|
if (iargc == 0)
|
|
iargv = (char **)malloc(sizeof(char *));
|
|
else
|
|
iargv = (char **)realloc(iargv, (iargc + 1) * sizeof(char *));
|
|
|
|
iargv[iargc++] = s;
|
|
}
|
|
|
|
dscl_cmd(iargc, iargv);
|
|
|
|
for (i = 0; i < iargc; i++) free(iargv[i]);
|
|
free(iargv);
|
|
free(line);
|
|
|
|
[foreverPool release];
|
|
}
|
|
|
|
return eDSNoErr;
|
|
}
|
|
|
|
uint32_t isSingleUserMode( void )
|
|
{
|
|
uint32_t sb = 0;
|
|
size_t sbsz = sizeof(sb);
|
|
|
|
if ( sysctlbyname("kern.singleuser", &sb, &sbsz, NULL, 0) == -1 )
|
|
return NO;
|
|
|
|
return sb;
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
int i = 0;
|
|
int opt_tag = 0;
|
|
int opt_promptpw = 0;
|
|
int opt_user = 0;
|
|
int opt_password = 0;
|
|
int opt_filePath = 0;
|
|
int prompt = PROMPT_DS;
|
|
char *slash = nil;
|
|
char *dataSource = nil;
|
|
tDirStatus status = eDSNoErr;
|
|
NSString *auth_user = nil;
|
|
NSString *auth_password = nil;
|
|
NSString *filePath = nil;
|
|
extern BOOL gRawMode;
|
|
extern BOOL gPlistMode;
|
|
|
|
@try {
|
|
|
|
slash = rindex(argv[0], '/');
|
|
if (slash == NULL) strcpy(myname, argv[0]);
|
|
else strcpy(myname, slash+1);
|
|
|
|
if ( argc == 2 && strcmp(argv[1], "-appleversion") == 0 )
|
|
dsToolAppleVersionExit( myname );
|
|
|
|
interactive = 0;
|
|
|
|
if ( isSingleUserMode() ) {
|
|
NSArray *args = [NSArray arrayWithObjects: @"load",
|
|
@"/System/Library/LaunchDaemons/com.apple.DirectoryServicesLocal.plist",
|
|
nil];
|
|
NSTask *task = [NSTask launchedTaskWithLaunchPath: @"/bin/launchctl" arguments: args];
|
|
[task waitUntilExit];
|
|
}
|
|
|
|
// Parse program options
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (streq(argv[i], "-H")) gHACK = YES;
|
|
else if (streq(argv[i], "-q")) prompt = PROMPT_NONE;
|
|
else if (streq(argv[i], "-t")) opt_tag = 1;
|
|
else if (streq(argv[i], "-raw")) gRawMode = 1;
|
|
else if (streq(argv[i], "-plist")) gPlistMode = 1;
|
|
else if (streq(argv[i], "-p")) opt_promptpw = 1;
|
|
else if (streq(argv[i], "-url")) gURLEncode = YES;
|
|
else if (streq(argv[i], "-P"))
|
|
{
|
|
i++;
|
|
opt_password = i;
|
|
}
|
|
else if (streq(argv[i], "-u"))
|
|
{
|
|
i++;
|
|
opt_user = i;
|
|
}
|
|
else if (streq(argv[i], "-f"))
|
|
{
|
|
i++;
|
|
opt_filePath = i;
|
|
}
|
|
else break;
|
|
}
|
|
|
|
if (i == argc)
|
|
{
|
|
printf("Entering interactive mode... (type \"help\" for commands)\n");
|
|
if ( isSingleUserMode() ) {
|
|
dataSource = "localonly";
|
|
}
|
|
else {
|
|
dataSource = "localhost";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dataSource = argv[i];
|
|
}
|
|
|
|
if (opt_user) opt_promptpw = 1;
|
|
if (opt_password) opt_promptpw = 0;
|
|
|
|
if ((opt_user == 0) && ((opt_password == 1) || (opt_promptpw == 1)))
|
|
{
|
|
auth_user = @"root";
|
|
}
|
|
|
|
if (opt_filePath != 0)
|
|
filePath = [NSString stringWithUTF8String:argv[opt_filePath]];
|
|
|
|
if (opt_user != 0)
|
|
auth_user = [NSString stringWithUTF8String:argv[opt_user]];
|
|
|
|
if (opt_password != 0)
|
|
{
|
|
auth_password = [NSString stringWithUTF8String:argv[opt_password]];
|
|
|
|
// after retrieving the password from the command line, blank it out from the ps listing
|
|
bzero( argv[opt_password], strlen(argv[opt_password]) );
|
|
}
|
|
else if (opt_promptpw == 1)
|
|
auth_password = [NSString stringWithUTF8String:getpass("Password: ")];
|
|
|
|
if (filePath != NULL)
|
|
{
|
|
// The data source is the raw local file, open the local only DS service.
|
|
engine = [[PathManager alloc] initWithLocalPath:filePath];
|
|
}
|
|
else if (dataSource[0] == '/')
|
|
{
|
|
// The data source begins with a "/", it's a node,
|
|
// open the node via the local DS service.
|
|
// (Authenticate to the node if necessary.)
|
|
if (auth_user && auth_password)
|
|
engine = [[PathManager alloc] initWithNodeName:[NSString stringWithUTF8String:dataSource]
|
|
user:auth_user
|
|
password:auth_password];
|
|
else
|
|
engine = [[PathManager alloc] initWithNodeName:[NSString stringWithUTF8String:dataSource]];
|
|
}
|
|
else if (strcasecmp(dataSource, "eDSLocalHostedNodes") == 0)
|
|
{
|
|
// open the node via the local DS service.
|
|
engine = [[PathManager alloc] initWithNodeEnum:eDSLocalHostedNodes];
|
|
|
|
}
|
|
else if (strcasecmp(dataSource, "eDSLocalNodeNames") == 0)
|
|
{
|
|
// open the node via the local DS service.
|
|
engine = [[PathManager alloc] initWithNodeEnum:eDSLocalNodeNames];
|
|
|
|
}
|
|
else if (streq(dataSource, "."))
|
|
{
|
|
// The data source is the local node.
|
|
if (auth_user && auth_password)
|
|
engine = [[PathManager alloc] initWithLocalNodeAuthUser:auth_user
|
|
password:auth_password];
|
|
else
|
|
engine = [[PathManager alloc] initWithLocalNode];
|
|
}
|
|
else if (strcasecmp(dataSource, "localhost") == 0)
|
|
{
|
|
// The data source is the localhost, open the local DS service.
|
|
engine = [[PathManager alloc] initWithLocal];
|
|
}
|
|
else if (strcasecmp(dataSource, "localonly") == 0)
|
|
{
|
|
// The data source is the localonly, open the local only DS service.
|
|
engine = [[PathManager alloc] initWithLocalPath:@"Default"];
|
|
}
|
|
else
|
|
{
|
|
// assume the data source is a remote host to be contacted via DS proxy.
|
|
engine = [[PathManager alloc] initWithHost:[NSString stringWithUTF8String:dataSource]
|
|
user:auth_user
|
|
password:auth_password];
|
|
}
|
|
|
|
if (engine != nil)
|
|
{
|
|
i++;
|
|
if (i >= argc)
|
|
{
|
|
status = dscl_interactive(stdin, prompt);
|
|
if (prompt != PROMPT_NONE) printf("Goodbye\n");
|
|
}
|
|
else status = dscl_cmd(argc - i, argv + i);
|
|
}
|
|
else
|
|
{
|
|
status = EX_UNAVAILABLE;
|
|
printf("Data source (%s) is not valid.\n", dataSource);
|
|
}
|
|
|
|
} @catch( DSoException *exception ) {
|
|
|
|
if ([[exception name] isEqualToString:@"DSOpenDirServiceErr"]) {
|
|
printf("Cannot open remote host, error: DSOpenDirServiceErr\n");
|
|
} else {
|
|
status = [exception status];
|
|
switch ( status )
|
|
{
|
|
case eServerSendError:
|
|
case eServerNotRunning:
|
|
if ( isSingleUserMode() ) {
|
|
fprintf( stderr, "For Single User Mode you must run the following command to enable use of dscl.\n" );
|
|
fprintf( stderr, " launchctl load /System/Library/LaunchDaemons/com.apple.DirectoryServicesLocal.plist\n" );
|
|
fprintf( stderr, " dscl localonly\n\n" );
|
|
status = EX_CONFIG;
|
|
break;
|
|
}
|
|
default:
|
|
fprintf( stderr, "Operation failed with error: %s\n", [[exception statusString] UTF8String] );
|
|
status = EX_SOFTWARE;
|
|
break;
|
|
}
|
|
}
|
|
} @catch ( id exception ) {
|
|
fprintf( stderr, "*** Uncaught Exception: <%s> (%s)\n", [[exception name] UTF8String], [[exception reason] UTF8String] );
|
|
status = EX_SOFTWARE;
|
|
}
|
|
|
|
[engine release];
|
|
|
|
[pool release];
|
|
|
|
exit(status);
|
|
}
|