]> git.saurik.com Git - apple/security.git/blob - checkpw/checkpw.c
Security-29.tar.gz
[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 sObject obj[ 10 ];
68 char data[ 1 ];
69 } sComData;
70
71 #define kMsgBlockSize (1024 * 4) // Set to average of 4k
72 #define kObjSize (sizeof( sObject ) * 10) // size of object struct
73 #define kIPCMsgLen kMsgBlockSize // IPC message block size
74
75 #define kIPCMsgSize sizeof( sIPCMsg )
76
77 typedef struct sIPCMsg
78 {
79 mach_msg_header_t fHeader;
80 unsigned long fMsgType;
81 unsigned long fCount;
82 unsigned long fOf;
83 unsigned long fMsgID;
84 unsigned long fPID;
85 unsigned long fPort;
86 sObject obj[ 10 ];
87 char fData[ kIPCMsgLen ];
88 mach_msg_security_trailer_t fTail;
89 } sIPCMsg;
90
91 typedef enum {
92 kResult = 4460,
93 ktDataBuff = 4466,
94 } eValueType;
95
96 enum eDSServerCalls {
97 /* 9 */ kCheckUserNameAndPassword = 9
98 };
99 // end copied from SharedConsts.h
100
101 int checkpw( const char* userName, const char* password )
102 {
103 int siResult = CHECKPW_FAILURE;
104 struct passwd* pw = NULL;
105 kern_return_t result = err_none;
106 mach_port_t bsPort = 0;
107 mach_port_t serverPort = 0;
108 mach_port_t replyPort = 0;
109 const char *const srvrName = "DirectoryService";
110 sIPCMsg* msg = NULL;
111 unsigned long len = 0;
112 long curr = 0;
113 unsigned long i = 0;
114
115 pw = getpwnam( userName );
116 if (pw == NULL)
117 {
118 return CHECKPW_UNKNOWNUSER;
119 }
120
121
122 do {
123 // Special case for empty password (this explicitly denies UNIX-like behavior)
124 if (pw->pw_passwd == NULL || pw->pw_passwd[0] == '\0') {
125 if (password == NULL || password[0] == '\0')
126 siResult = CHECKPW_SUCCESS;
127 else
128 siResult = CHECKPW_BADPASSWORD;
129
130 break;
131 }
132
133 // Correct password hash
134 if (strcmp(crypt(password, pw->pw_passwd), pw->pw_passwd) == 0) {
135 siResult = CHECKPW_SUCCESS;
136 break;
137 }
138
139 // Special marker for Directory Services
140 if (strcmp(pw->pw_passwd,"********") != 0) {
141 siResult = CHECKPW_BADPASSWORD;
142 break;
143 }
144
145 result = mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &replyPort );
146 if ( result != err_none ) {
147 siResult = CHECKPW_FAILURE;
148 break;
149 }
150
151 result = task_get_bootstrap_port( mach_task_self(), &bsPort );
152 if ( result != err_none ) {
153 siResult = CHECKPW_FAILURE;
154 break;
155 }
156
157 // check if DirectoryService is alive
158 result = bootstrap_look_up( bsPort, (char *)srvrName, &serverPort );
159 if ( result != err_none ) {
160 siResult = CHECKPW_FAILURE;
161 break;
162 }
163
164 // ask directory services to do auth
165 msg = calloc( sizeof( sIPCMsg ), 1 );
166 if ( msg == NULL ) {
167 siResult = CHECKPW_FAILURE; // memory error
168 break;
169 }
170
171 // put username and password into message
172 msg->obj[0].type = ktDataBuff;
173 msg->obj[0].count = 1;
174 msg->obj[0].offset = offsetof(struct sComData, data);
175
176 // User Name
177 len = strlen( userName );
178 memcpy( &(msg->fData[ curr ]), &len, sizeof( unsigned long ) );
179 curr += sizeof( unsigned long );
180 memcpy( &(msg->fData[ curr ]), userName, len );
181 curr += len;
182
183 // Password
184 len = strlen( password );
185 memcpy( &(msg->fData[ curr ]), &len, sizeof( unsigned long ) );
186 curr += sizeof ( unsigned long );
187 memcpy( &(msg->fData[ curr ]), password, len );
188 curr += len;
189 msg->obj[0].used = curr;
190 msg->obj[0].length = curr;
191
192 msg->fHeader.msgh_bits = MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND );
193 msg->fHeader.msgh_size = sizeof( sIPCMsg ) - sizeof( mach_msg_security_trailer_t );
194 msg->fHeader.msgh_id = kCheckUserNameAndPassword;
195 msg->fHeader.msgh_remote_port = serverPort;
196 msg->fHeader.msgh_local_port = replyPort;
197
198 msg->fMsgType = kCheckUserNameAndPassword;
199 msg->fCount = 1;
200 msg->fOf = 1;
201 msg->fPort = replyPort;
202 msg->fPID = getpid();
203 msg->fMsgID = time( NULL ) + kCheckUserNameAndPassword;
204
205 // send the message
206 result = mach_msg_send( (mach_msg_header_t*)msg );
207 if ( result != MACH_MSG_SUCCESS ) {
208 siResult = CHECKPW_FAILURE;
209 break;
210 }
211
212 // get reply
213 memset( msg, 0, kIPCMsgLen );
214
215 result = mach_msg( (mach_msg_header_t *)msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT,
216 0, kIPCMsgSize, replyPort, 300 * 1000, MACH_PORT_NULL );
217
218 if ( result != MACH_MSG_SUCCESS ) {
219 siResult = CHECKPW_FAILURE;
220 break;
221 }
222
223 if ( msg->fCount != 1 ) {
224 // couldn't get reply
225 siResult = CHECKPW_FAILURE;
226 break;
227 }
228
229 for (i = 0; i < 10; i++ )
230 {
231 if ( msg->obj[ i ].type == (unsigned long)kResult )
232 {
233 siResult = msg->obj[ i ].count;
234 break;
235 }
236 }
237
238 } while (0);
239
240 if (msg != NULL) {
241 free(msg);
242 msg = NULL;
243 }
244
245 if ( replyPort != 0 )
246 mach_port_deallocate( mach_task_self(), replyPort );
247
248 if (pw)
249 endpwent();
250
251 return siResult;
252 }