1/*
2 * Copyright (c) 2003-2004 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 * create_fv_user.c
24 */
25
26#include "create_fv_user.h"
27
28#include "keychain_utilities.h"
29#include "readline.h"
30#include "security.h"
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36#include <Security/SecKeychain.h>
37
38#include <Admin/LoginPrefs.h>
39
40static int
41do_lock_all(void)
42{
43	OSStatus result = SecKeychainLockAll();
44    if (result)
45        sec_perror("SecKeychainLockAll", result);
46
47	return result;
48}
49
50static int
51do_lock(const char *keychainName)
52{
53	SecKeychainRef keychain = NULL;
54	OSStatus result;
55
56	if (keychainName)
57	{
58		keychain = keychain_open(keychainName);
59		if (!keychain)
60		{
61			result = 1;
62			goto loser;
63		}
64	}
65
66	result = SecKeychainLock(keychain);
67	if (result)
68	{
69		sec_error("SecKeychainLock %s: %s", keychainName ? keychainName : "<NULL>", sec_errstr(result));
70	}
71
72loser:
73	if (keychain)
74		CFRelease(keychain);
75
76	return result;
77}
78
79int
80create_fv_user(int argc, char * const *argv)
81{
82	char *keychainName = NULL;
83	int ch, result = 0;
84	Boolean lockAll = FALSE;
85	while ((ch = getopt(argc, argv, "ah")) != -1)
86	{
87		switch  (ch)
88		{
89		case 'a':
90			lockAll = TRUE;
91			break;
92		case '?':
93		default:
94			return 2; /* @@@ Return 2 triggers usage message. */
95		}
96	}
97	argc -= optind;
98	argv += optind;
99
100	if (argc == 1 && !lockAll)
101	{
102		keychainName = argv[0];
103		if (*keychainName == '\0')
104		{
105			result = 2;
106			goto loser;
107		}
108	}
109	else if (argc != 0)
110		return 2;
111
112	if (lockAll)
113		result = do_lock_all();
114	else
115		result = do_lock(keychainName);
116
117loser:
118
119	return result;
120}
121
122
123	//
124	// Verify user Full name
125	//
126	if([[mNewUserFullName stringValue] length] == 0)
127	{
128		// NSRunAlertPanel(LOCSTRING(@"USERNAME_IS_EMPTY"), LOCSTRING(@"USERNAME_IS_EMPTY_DESC"), LOCSTRING(@"OK"), NULL, NULL);
129		[mNewUserFullNameWarn setStringValue:LOCSTRING(@"USERNAME_IS_EMPTY_SHORT")];
130		[self _showWarningForField:mNewUserFullName];
131		return;
132	}
133
134	{
135		if(([[mNewUserFullName stringValue] caseInsensitiveCompare:@"admin"] != NSOrderedSame) && ([Group findGroupByName:[mNewUserFullName stringValue]] != NULL))
136		{
137			// NSRunAlertPanel([NSString stringWithFormat:LOCSTRING(@"USERNAME_IS_NOT_AVAILABLE"), [mNewUserFullName stringValue]], LOCSTRING(@"USERNAME_IS_NOT_AVAILABLE_DESC"), LOCSTRING(@"OK"), NULL, NULL);
138			[mNewUserFullNameWarn setStringValue:LOCSTRING(@"USERNAME_IS_NOT_AVAILABLE_SHORT")];
139			[self _showWarningForField:mNewUserFullName];
140			return;
141		}
142
143		if(![User isUserNameUnique:[mNewUserFullName stringValue] searchParent:NO])
144		{
145			// NSRunAlertPanel([NSString stringWithFormat:LOCSTRING(@"USERNAME_IS_NOT_UNIQUE"), [mNewUserFullName stringValue]], LOCSTRING(@"USERNAME_IS_NOT_UNIQUE_DESC"), LOCSTRING(@"OK"), NULL, NULL);
146			[mNewUserFullNameWarn setStringValue:LOCSTRING(@"USERNAME_IS_NOT_UNIQUE_SHORT")];
147			[self _showWarningForField:mNewUserFullName];
148			return;
149		}
150	}
151
152
153	//
154	// Verify unix-user name
155	//
156	if([[mNewUserName stringValue] length] == 0))
157	{
158		// HACK to have the same behavior when user presses "Enter" and clicked "Save"
159		// right after entering full name (without even leaving the field)
160		[mNewUserName setStringValue:[User generateUnixNameUsingString:[mNewUserFullName stringValue]]];
161		[[mNewUserName window] display];
162	}
163
164	if([[mNewUserName stringValue] isEqualToString:@"ftp"])
165	{
166		// NSRunAlertPanel(LOCSTRING(@"UNIXNAME_IS_PUBLIC"), LOCSTRING(@"UNIXNAME_IS_PUBLIC_DESC"), LOCSTRING(@"OK"), NULL, NULL);
167		[mNewUserNameWarn setStringValue:LOCSTRING(@"UNIXNAME_IS_FTP_SHORT")];
168		[self _showWarningForField:mNewUserName];
169		return;
170	}
171
172	if([[mNewUserName stringValue] isEqualToString:@"public"])
173	{
174		// NSRunAlertPanel(LOCSTRING(@"UNIXNAME_IS_PUBLIC"), LOCSTRING(@"UNIXNAME_IS_PUBLIC_DESC"), LOCSTRING(@"OK"), NULL, NULL);
175		[mNewUserNameWarn setStringValue:LOCSTRING(@"UNIXNAME_IS_PUBLIC_SHORT")];
176		[self _showWarningForField:mNewUserName];
177		return;
178	}
179
180	if([[mNewUserName stringValue] length] == 0)
181	{
182		// NSRunAlertPanel(LOCSTRING(@"UNIXNAME_IS_EMPTY"), LOCSTRING(@"UNIXNAME_IS_EMPTY_DESC"), LOCSTRING(@"OK"), NULL, NULL);
183		[mNewUserNameWarn setStringValue:LOCSTRING(@"UNIXNAME_IS_EMPTY_SHORT")];
184		[self _showWarningForField:mNewUserName];
185		return;
186	}
187
188	if(![User isUserNameUnique:[mNewUserName stringValue] searchParent:NO])
189	{
190		// NSRunAlertPanel([NSString stringWithFormat:LOCSTRING(@"UNIXNAME_IS_NOT_UNIQUE"), [mNewUserName stringValue]], LOCSTRING(@"UNIXNAME_IS_NOT_UNIQUE_DESC"), LOCSTRING(@"OK"), NULL, NULL);
191		[mNewUserNameWarn setStringValue:LOCSTRING(@"UNIXNAME_IS_NOT_UNIQUE_SHORT")];
192		[self _showWarningForField:mNewUserName];
193		return;
194	}
195
196	if(![User isUnixNameValid:[mNewUserName stringValue]])
197	{
198		// NSRunAlertPanel([NSString stringWithFormat:LOCSTRING(@"UNIXNAME_IS_NOT_VALID"), [mNewUserName stringValue]], LOCSTRING(@"UNIXNAME_IS_NOT_VALID_DESC"), LOCSTRING(@"OK"), NULL, NULL);
199		[mNewUserNameWarn setStringValue:LOCSTRING(@"UNIXNAME_IS_NOT_VALID_SHORT")];
200		[self _showWarningForField:mNewUserName];
201		return;
202	}
203
204	if(([[mNewUserName stringValue] caseInsensitiveCompare:@"admin"] != NSOrderedSame) && ([Group findGroupByName:[mNewUserName stringValue]] != NULL))
205	{
206		// NSRunAlertPanel([NSString stringWithFormat:LOCSTRING(@"USERNAME_IS_NOT_AVAILABLE"), [mNewUserName stringValue]], LOCSTRING(@"USERNAME_IS_NOT_AVAILABLE_DESC"), LOCSTRING(@"OK"), NULL, NULL);
207		[mNewUserNameWarn setStringValue:LOCSTRING(@"USERNAME_IS_NOT_AVAILABLE_SHORT")];
208		[self _showWarningForField:mNewUserName];
209		return;
210	}
211
212	//
213	// Verify Password
214	//
215	if(![[mNewUserPassword stringValue] isEqualToString:[mNewUserPasswordVerify stringValue]])
216		{
217			// NSRunAlertPanel(LOCSTRING(@"PASS_VERIFY_ERR"), LOCSTRING(@"PASS_VERIFY_ERR_DESC"), LOCSTRING(@"OK"), NULL, NULL);
218			[mNewUserPassword setStringValue:@""];
219			[mNewUserPasswordVerify setStringValue:@""];
220			[mNewUserPasswordWarn setStringValue:LOCSTRING(@"PASS_VERIFY_ERR_SHORT")];
221			[self _showWarningForField:mNewUserPassword];
222			return;
223		}
224
225		// Warn about empty passowrd
226		if(![[mNewUserPassword stringValue] length])
227		{
228			if(NSRunAlertPanel(LOCSTRING(@"PASS_IS_EMPTY_WARN"), LOCSTRING(@"PASS_IS_EMPTY_WARN_DESC"), LOCSTRING(@"CANCEL"), LOCSTRING(@"OK"), NULL) == NSOKButton)
229			{
230				[[mNewUserPassword window] makeFirstResponder:mNewUserPassword];
231				return;
232			}
233		}
234
235	// Fix for 3707901
236	// Warn user if user's short name is admin
237	if([[mNewUserName stringValue] caseInsensitiveCompare:@"admin"] == NSOrderedSame)
238	{
239		if(NSRunAlertPanel(LOCSTRING(@"USERNAME_IS_ADMIN"), LOCSTRING(@"USERNAME_IS_ADMIN_DESCR"), LOCSTRING(@"OK"), LOCSTRING(@"CANCEL"), NULL) != NSOKButton)
240		{
241			[[mNewUserName window] makeFirstResponder:mNewUserName];
242			return;
243		}
244
245		[mNewUserAdmin setState:NSOnState];
246	}
247
248	// Check if home already exists
249	{
250		NSFileManager *		fm = [NSFileManager defaultManager];
251		BOOL				directory;
252		NSString *			username = [mNewUserName stringValue];
253
254		if([fm fileExistsAtPath:[@"/Users/" stringByAppendingPathComponent:username] isDirectory:&directory])
255		{
256			if(directory)
257			{
258				if(NSRunAlertPanel([NSString stringWithFormat:LOCSTRING(@"HOME_EXISTS_WARN"), username], LOCSTRING(@"HOME_EXISTS_WARN_DESCR"), LOCSTRING(@"CANCEL"), LOCSTRING(@"OK"), NULL) != NSCancelButton) return;
259			}
260			else
261			{
262				NSRunAlertPanel([NSString stringWithFormat:LOCSTRING(@"HOME_EXISTS_ERR"), username], LOCSTRING(@"HOME_EXISTS_ERR_DESCR"), LOCSTRING(@"OK"), NULL, NULL);
263				return;
264			}
265		}
266	}
267
268	if([mNewUserIsFV state] == NSOnState && (!SecFileVaultMasterPasswordEnabled(NULL)))
269	{
270		[mMasterPassword setStringValue:@""];
271		[mMasterPasswordVerify setStringValue:@""];
272		[mMasterPasswordHint setStringValue:@""];
273		[mMasterPasswordWarn setStringValue:@""];
274		[mNewUserWarningSign setHidden:YES];
275
276		[self _setContentView:mMasterPasswordView displayAndAnimate:YES];
277		[mNewUserSheet performSelector:@selector(makeFirstResponder:) withObject:mMasterPassword afterDelay:0.1];
278	}
279
280	[[NSApplication sharedApplication] endSheet:[inSender window] returnCode:NSOKButton];
281	[[inSender window] orderOut:[inSender window]];
282