]> git.saurik.com Git - apple/security.git/blob - checkpw/checkpw.c
fdc4834e7a5d00cb0dcb89fc0bf4841b92fc9488
[apple/security.git] / checkpw / checkpw.c
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18 /*
19 * checkpw.c
20 * utility to authenticate users using crypt with a fallback on Directory Services
21 *
22 * Copyright: (c) 2000 by Apple Computer, Inc., all rights reserved
23 *
24 */
25
26 #include <pwd.h>
27 #include <stddef.h> // for offsetof()
28 #include <stdlib.h> // for malloc()
29 #include <string.h> // for strcmp()
30 #include <time.h>
31 #include <unistd.h> // for crypt()
32 #include <mach/mach.h>
33 #include <mach/mach_error.h>
34 #include <mach/message.h>
35 #include <servers/bootstrap.h>
36 #include "checkpw.h"
37
38 // begin copied from SharedConsts.h
39 typedef struct {
40 unsigned int msgt_name : 8,
41 msgt_size : 8,
42 msgt_number : 12,
43 msgt_inline : 1,
44 msgt_longform : 1,
45 msgt_deallocate : 1,
46 msgt_unused : 1;
47 } mach_msg_type_t;
48
49 typedef struct sObject
50 {
51 unsigned long type;
52 unsigned long count;
53 unsigned long offset;
54 unsigned long used;
55 unsigned long length;
56 } sObject;
57
58 typedef struct sComData
59 {
60 mach_msg_header_t head;
61 mach_msg_type_t type;
62 unsigned long fDataSize;
63 unsigned long fDataLength;
64 unsigned long fMsgID;
65 unsigned long fPID;
66 unsigned long fPort;
67 unsigned long fIPAddress;
68 sObject obj[ 10 ];
69 char data[ 1 ];
70 } sComData;
71
72 #define kMsgBlockSize (1024 * 4) // Set to average of 4k
73 #define kObjSize (sizeof( sObject ) * 10) // size of object struct
74 #define kIPCMsgLen kMsgBlockSize // IPC message block size
75
76 #define kIPCMsgSize sizeof( sIPCMsg )
77
78 typedef struct sIPCMsg
79 {
80 mach_msg_header_t fHeader;
81 unsigned long fMsgType;
82 unsigned long fCount;
83 unsigned long fOf;
84 unsigned long fMsgID;
85 unsigned long fPID;
86 unsigned long fPort;
87 sObject obj[ 10 ];
88 char fData[ kIPCMsgLen ];
89 mach_msg_security_trailer_t fTail;
90 } sIPCMsg;
91
92 typedef enum {
93 kResult = 4460,
94 ktDataBuff = 4466,
95 } eValueType;
96
97 enum eDSServerCalls {
98 /* 9 */ kCheckUserNameAndPassword = 9
99 };
100 // end copied from SharedConsts.h
101
102 int checkpw( const char* userName, const char* password )
103 {
104 struct passwd* pw = NULL;
105 int status;
106
107 // Check username, NULL can crash in getpwnam
108 if (!userName)
109 return CHECKPW_UNKNOWNUSER;
110
111 pw = getpwnam( userName );
112 if (pw == NULL)
113 return CHECKPW_UNKNOWNUSER;
114
115 status = checkpw_internal(userName, password, pw);
116 endpwent();
117 return status;
118 }
119
120 int checkpw_internal( const char* userName, const char* password, const struct passwd* pw )
121 {
122 int siResult = CHECKPW_FAILURE;
123 kern_return_t result = err_none;
124 mach_port_t bsPort = 0;
125 mach_port_t serverPort = 0;
126 mach_port_t replyPort = 0;
127 const char *const srvrName = "DirectoryService";
128 sIPCMsg* msg = NULL;
129 unsigned long len = 0;
130 long curr = 0;
131 unsigned long i = 0;
132
133
134 do {
135 // Special case for empty password (this explicitly denies UNIX-like behavior)
136 if (pw->pw_passwd == NULL || pw->pw_passwd[0] == '\0') {
137 if (password == NULL || password[0] == '\0')
138 siResult = CHECKPW_SUCCESS;
139 else
140 siResult = CHECKPW_BADPASSWORD;
141
142 break;
143 }
144
145 // check password, NULL crashes crypt()
146 if (!password)
147 {
148 siResult = CHECKPW_BADPASSWORD;
149 break;
150 }
151 // Correct password hash
152 if (strcmp(crypt(password, pw->pw_passwd), pw->pw_passwd) == 0) {
153 siResult = CHECKPW_SUCCESS;
154 break;
155 }
156
157 // Try Directory Services directly
158
159 result = mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &replyPort );
160 if ( result != err_none ) {
161 siResult = CHECKPW_FAILURE;
162 break;
163 }
164
165 result = task_get_bootstrap_port( mach_task_self(), &bsPort );
166 if ( result != err_none ) {
167 siResult = CHECKPW_FAILURE;
168 break;
169 }
170
171 // check if DirectoryService is alive
172 result = bootstrap_look_up( bsPort, (char *)srvrName, &serverPort );
173 if ( result != err_none ) {
174 siResult = CHECKPW_FAILURE;
175 break;
176 }
177
178 // ask directory services to do auth
179 msg = calloc( sizeof( sIPCMsg ), 1 );
180 if ( msg == NULL ) {
181 siResult = CHECKPW_FAILURE; // memory error
182 break;
183 }
184
185 // put username and password into message
186 msg->obj[0].type = ktDataBuff;
187 msg->obj[0].count = 1;
188 msg->obj[0].offset = offsetof(struct sComData, data);
189
190 // User Name
191 len = strlen( userName );
192 if (curr + len + sizeof(unsigned long) > kIPCMsgLen)
193 {
194 siResult = CHECKPW_FAILURE;
195 break;
196 }
197 memcpy( &(msg->fData[ curr ]), &len, sizeof( unsigned long ) );
198 curr += sizeof( unsigned long );
199 memcpy( &(msg->fData[ curr ]), userName, len );
200 curr += len;
201
202 // Password
203 len = strlen( password );
204 if (curr + len + sizeof(unsigned long) > kIPCMsgLen)
205 {
206 siResult = CHECKPW_FAILURE;
207 break;
208 }
209 memcpy( &(msg->fData[ curr ]), &len, sizeof( unsigned long ) );
210 curr += sizeof ( unsigned long );
211 memcpy( &(msg->fData[ curr ]), password, len );
212 curr += len;
213 msg->obj[0].used = curr;
214 msg->obj[0].length = curr;
215
216 msg->fHeader.msgh_bits = MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND );
217 msg->fHeader.msgh_size = sizeof( sIPCMsg ) - sizeof( mach_msg_security_trailer_t );
218 msg->fHeader.msgh_id = kCheckUserNameAndPassword;
219 msg->fHeader.msgh_remote_port = serverPort;
220 msg->fHeader.msgh_local_port = replyPort;
221
222 msg->fMsgType = kCheckUserNameAndPassword;
223 msg->fCount = 1;
224 msg->fOf = 1;
225 msg->fPort = replyPort;
226 msg->fPID = getpid();
227 msg->fMsgID = time( NULL ) + kCheckUserNameAndPassword;
228
229 // send the message
230 result = mach_msg_send( (mach_msg_header_t*)msg );
231 if ( result != MACH_MSG_SUCCESS ) {
232 siResult = CHECKPW_FAILURE;
233 break;
234 }
235
236 // get reply
237 memset( msg, 0, kIPCMsgLen );
238
239 result = mach_msg( (mach_msg_header_t *)msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT,
240 0, kIPCMsgSize, replyPort, 300 * 1000, MACH_PORT_NULL );
241
242 if ( result != MACH_MSG_SUCCESS ) {
243 siResult = CHECKPW_FAILURE;
244 break;
245 }
246
247 if ( msg->fCount != 1 ) {
248 // couldn't get reply
249 siResult = CHECKPW_FAILURE;
250 break;
251 }
252
253 for (i = 0; i < 10; i++ )
254 {
255 if ( msg->obj[ i ].type == (unsigned long)kResult )
256 {
257 siResult = msg->obj[ i ].count;
258 break;
259 }
260 }
261
262 } while (0);
263
264 if (msg != NULL) {
265 free(msg);
266 msg = NULL;
267 }
268
269 if ( replyPort != 0 )
270 mach_port_deallocate( mach_task_self(), replyPort );
271
272
273 return siResult;
274 }