]> git.saurik.com Git - apple/security.git/blob - checkpw/checkpw.c
d0a0ef761597e7feaf406fb14f9f0c7ce774d7ef
[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 pw = getpwnam( userName );
108 if (pw == NULL)
109 return CHECKPW_UNKNOWNUSER;
110
111 status = checkpw_internal(userName, password, pw);
112 endpwent();
113 return status;
114 }
115
116 int checkpw_internal( const char* userName, const char* password, const struct passwd* pw )
117 {
118 int siResult = CHECKPW_FAILURE;
119 kern_return_t result = err_none;
120 mach_port_t bsPort = 0;
121 mach_port_t serverPort = 0;
122 mach_port_t replyPort = 0;
123 const char *const srvrName = "DirectoryService";
124 sIPCMsg* msg = NULL;
125 unsigned long len = 0;
126 long curr = 0;
127 unsigned long i = 0;
128
129
130 do {
131 // Special case for empty password (this explicitly denies UNIX-like behavior)
132 if (pw->pw_passwd == NULL || pw->pw_passwd[0] == '\0') {
133 if (password == NULL || password[0] == '\0')
134 siResult = CHECKPW_SUCCESS;
135 else
136 siResult = CHECKPW_BADPASSWORD;
137
138 break;
139 }
140
141 // Correct password hash
142 if (strcmp(crypt(password, pw->pw_passwd), pw->pw_passwd) == 0) {
143 siResult = CHECKPW_SUCCESS;
144 break;
145 }
146
147 // Try Directory Services directly
148
149 result = mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &replyPort );
150 if ( result != err_none ) {
151 siResult = CHECKPW_FAILURE;
152 break;
153 }
154
155 result = task_get_bootstrap_port( mach_task_self(), &bsPort );
156 if ( result != err_none ) {
157 siResult = CHECKPW_FAILURE;
158 break;
159 }
160
161 // check if DirectoryService is alive
162 result = bootstrap_look_up( bsPort, (char *)srvrName, &serverPort );
163 if ( result != err_none ) {
164 siResult = CHECKPW_FAILURE;
165 break;
166 }
167
168 // ask directory services to do auth
169 msg = calloc( sizeof( sIPCMsg ), 1 );
170 if ( msg == NULL ) {
171 siResult = CHECKPW_FAILURE; // memory error
172 break;
173 }
174
175 // put username and password into message
176 msg->obj[0].type = ktDataBuff;
177 msg->obj[0].count = 1;
178 msg->obj[0].offset = offsetof(struct sComData, data);
179
180 // User Name
181 len = strlen( userName );
182 memcpy( &(msg->fData[ curr ]), &len, sizeof( unsigned long ) );
183 curr += sizeof( unsigned long );
184 memcpy( &(msg->fData[ curr ]), userName, len );
185 curr += len;
186
187 // Password
188 len = strlen( password );
189 memcpy( &(msg->fData[ curr ]), &len, sizeof( unsigned long ) );
190 curr += sizeof ( unsigned long );
191 memcpy( &(msg->fData[ curr ]), password, len );
192 curr += len;
193 msg->obj[0].used = curr;
194 msg->obj[0].length = curr;
195
196 msg->fHeader.msgh_bits = MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND );
197 msg->fHeader.msgh_size = sizeof( sIPCMsg ) - sizeof( mach_msg_security_trailer_t );
198 msg->fHeader.msgh_id = kCheckUserNameAndPassword;
199 msg->fHeader.msgh_remote_port = serverPort;
200 msg->fHeader.msgh_local_port = replyPort;
201
202 msg->fMsgType = kCheckUserNameAndPassword;
203 msg->fCount = 1;
204 msg->fOf = 1;
205 msg->fPort = replyPort;
206 msg->fPID = getpid();
207 msg->fMsgID = time( NULL ) + kCheckUserNameAndPassword;
208
209 // send the message
210 result = mach_msg_send( (mach_msg_header_t*)msg );
211 if ( result != MACH_MSG_SUCCESS ) {
212 siResult = CHECKPW_FAILURE;
213 break;
214 }
215
216 // get reply
217 memset( msg, 0, kIPCMsgLen );
218
219 result = mach_msg( (mach_msg_header_t *)msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT,
220 0, kIPCMsgSize, replyPort, 300 * 1000, MACH_PORT_NULL );
221
222 if ( result != MACH_MSG_SUCCESS ) {
223 siResult = CHECKPW_FAILURE;
224 break;
225 }
226
227 if ( msg->fCount != 1 ) {
228 // couldn't get reply
229 siResult = CHECKPW_FAILURE;
230 break;
231 }
232
233 for (i = 0; i < 10; i++ )
234 {
235 if ( msg->obj[ i ].type == (unsigned long)kResult )
236 {
237 siResult = msg->obj[ i ].count;
238 break;
239 }
240 }
241
242 } while (0);
243
244 if (msg != NULL) {
245 free(msg);
246 msg = NULL;
247 }
248
249 if ( replyPort != 0 )
250 mach_port_deallocate( mach_task_self(), replyPort );
251
252
253 return siResult;
254 }