1/*
2 * Copyright (c) 2003-2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * tokenadmin.c
24 */
25
26#include "tokenadmin.h"
27
28#include "readline.h"
29
30//#include "cmsutil.h"
31//#include "db_commands.h"
32#include "create_fv_user.h"
33//#include "authz.h"
34
35#include <ctype.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40
41#import <Foundation/Foundation.h>
42
43#include <CoreFoundation/CFRunLoop.h>
44#include <Security/SecBasePriv.h>
45#include <security_asn1/secerr.h>
46
47/* Maximum length of an input line in interactive mode. */
48#define MAX_LINE_LEN 4096
49/* Maximum number of arguments on an input line in interactive mode. */
50#define MAX_ARGS 32
51
52/* Entry in commands array for a command. */
53typedef struct command
54{
55	const char *c_name;    /* name of the command. */
56	command_func c_func;   /* function to execute the command. */
57	const char *c_usage;   /* usage sting for command. */
58	const char *c_help;    /* help string for (or description of) command. */
59} command;
60
61/* The default prompt. */
62const char *prompt_string = "tokenadmin> ";
63
64/* The name of this program. */
65const char *prog_name;
66
67
68/* Forward declarations of static functions. */
69static int help(int argc, char * const *argv);
70
71/*
72 * The command array itself.
73 * Add commands here at will.
74 * Matching is done on a prefix basis.  The first command in the array
75 * gets matched first.
76 */
77const command commands[] =
78{
79	{ "help", help,
80	  "[command ...]",
81	  "Show all commands or show usage for a command." },
82
83	{ "create-fv-user", create_fv_user,
84	  "-u <short user Name> -l <long user Name> [-p password]\n"
85	  "    -u    Use the argument as the short (i.e. unix) name for the new user.\n"
86	  "    -l    Use the argument as the long name for the new user.\n"
87	  "    -p    The option keychain password for the account.\n"
88	  "With no parameters display usage.",
89	  "Create a new FileVault user protected by a token." },
90
91	{}
92};
93
94/* Global variables. */
95int do_quiet = 0;
96int do_verbose = 0;
97
98/* Return 1 if name matches command. */
99static int
100match_command(const char *command, const char *name)
101{
102	return !strncmp(command, name, strlen(name));
103}
104
105/* The help command. */
106static int
107help(int argc, char * const *argv)
108{
109	const command *c;
110
111	if (argc > 1)
112	{
113		char * const *arg;
114		for (arg = argv + 1; *arg; ++arg)
115		{
116			int found = 0;
117
118			for (c = commands; c->c_name; ++c)
119			{
120				if (match_command(c->c_name, *arg))
121				{
122					found = 1;
123					break;
124				}
125			}
126
127			if (found)
128				printf("Usage: %s %s\n", c->c_name, c->c_usage);
129			else
130			{
131				sec_error("%s: no such command: %s", argv[0], *arg);
132				return 1;
133			}
134		}
135	}
136	else
137	{
138		for (c = commands; c->c_name; ++c)
139			printf("    %-17s %s\n", c->c_name, c->c_help);
140	}
141
142	return 0;
143}
144
145/* Print a (hopefully) useful usage message. */
146static int
147usage(void)
148{
149	printf(
150		"Usage: %s [-h] [-q] [-v] [command] [opt ...]\n"
151		"    -q    Be less verbose.\n"
152		"    -v    Be more verbose about what's going on.\n"
153		"%s commands are:\n", prog_name, prog_name);
154	help(0, NULL);
155	return 2;
156}
157
158/* Execute a single command. */
159static int
160execute_command(int argc, char * const *argv)
161{
162	const command *c;
163	int found = 0;
164
165	/* Nothing to do. */
166	if (argc == 0)
167		return 0;
168
169	for (c = commands; c->c_name; ++c)
170	{
171		if (match_command(c->c_name, argv[0]))
172		{
173			found = 1;
174			break;
175		}
176	}
177
178	if (found)
179	{
180		int result;
181
182		/* Reset getopt for command proc. */
183		optind = 1;
184		optreset = 1;
185
186		if (do_verbose)
187		{
188			int ix;
189
190			fprintf(stderr, "%s", c->c_name);
191			for (ix = 1; ix < argc; ++ix)
192				fprintf(stderr, " \"%s\"", argv[ix]);
193			fprintf(stderr, "\n");
194		}
195
196		result = c->c_func(argc, argv);
197		if (result == 2)
198			fprintf(stderr, "Usage: %s %s\n        %s\n", c->c_name, c->c_usage, c->c_help);
199
200		return result;
201	}
202	else
203	{
204		sec_error("unknown command \"%s\"", argv[0]);
205		return 1;
206	}
207}
208
209static void
210receive_notifications(void)
211{
212	/* Run the CFRunloop to get any pending notifications. */
213	while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, TRUE) == kCFRunLoopRunHandledSource);
214}
215
216
217const char *
218sec_errstr(int err)
219{
220    const char *errString;
221//    if (IS_SEC_ERROR(err))
222  //      errString = SECErrorString(err);
223  //  else
224        errString = cssmErrorString(err);
225    return errString;
226}
227
228void
229sec_error(const char *msg, ...)
230{
231    va_list args;
232
233    fprintf(stderr, "%s: ", prog_name);
234
235    va_start(args, msg);
236    vfprintf(stderr, msg, args);
237    va_end(args);
238
239    fprintf(stderr, "\n");
240}
241
242void
243sec_perror(const char *msg, int err)
244{
245    sec_error("%s: %s", msg, sec_errstr(err));
246}
247
248int
249main(int argc, char * const *argv)
250{
251	int result = 0;
252	int do_help = 0;
253	int ch;
254	const char *shortUserName = NULL;
255	const char *longUserName = NULL;
256	const char *password = NULL;
257
258	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
259	/* Remember my name. */
260	prog_name = strrchr(argv[0], '/');
261	prog_name = prog_name ? prog_name + 1 : argv[0];
262
263	/* Do getopt stuff for global options. */
264	optind = 1;
265	optreset = 1;
266	while ((ch = getopt(argc, argv, "hqv")) != -1)
267	{
268		switch  (ch)
269		{
270		case 'h':
271			do_help = 1;
272			break;
273		case 'q':
274			do_quiet = 1;
275			break;
276		case 'v':
277			do_verbose = 1;
278			break;
279		case '?':
280		default:
281			return usage();
282		}
283	}
284
285	argc -= optind;
286	argv += optind;
287
288	if (do_help)
289	{
290		/* Munge argc/argv so that argv[0] is something. */
291		return help(argc + 1, argv - 1);
292	}
293	else if (argc > 0)
294	{
295		receive_notifications();
296		result = execute_command(argc, argv);
297		if (result == 2)
298			usage();
299		receive_notifications();
300	}
301	else
302		result = usage();
303
304	[pool release];
305	return result;
306}
307