2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 * utility to authenticate users using crypt with a fallback on Directory Services
22 * Copyright: (c) 2000 by Apple Computer, Inc., all rights reserved
27 #include <stddef.h> // for offsetof()
28 #include <stdlib.h> // for malloc()
29 #include <string.h> // for strcmp()
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>
38 // begin copied from SharedConsts.h
40 unsigned int msgt_name
: 8,
49 typedef struct sObject
58 typedef struct sComData
60 mach_msg_header_t head
;
62 unsigned long fDataSize
;
63 unsigned long fDataLength
;
67 unsigned long fIPAddress
;
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
76 #define kIPCMsgSize sizeof( sIPCMsg )
78 typedef struct sIPCMsg
80 mach_msg_header_t fHeader
;
81 unsigned long fMsgType
;
88 char fData
[ kIPCMsgLen
];
89 mach_msg_security_trailer_t fTail
;
98 /* 9 */ kCheckUserNameAndPassword
= 9
100 // end copied from SharedConsts.h
102 int checkpw( const char* userName
, const char* password
)
104 struct passwd
* pw
= NULL
;
107 // Check username, NULL can crash in getpwnam
109 return CHECKPW_UNKNOWNUSER
;
111 pw
= getpwnam( userName
);
113 return CHECKPW_UNKNOWNUSER
;
115 status
= checkpw_internal(userName
, password
, pw
);
120 int checkpw_internal( const char* userName
, const char* password
, const struct passwd
* pw
)
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";
129 unsigned long len
= 0;
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
;
140 siResult
= CHECKPW_BADPASSWORD
;
145 // check password, NULL crashes crypt()
148 siResult
= CHECKPW_BADPASSWORD
;
151 // Correct password hash
152 if (strcmp(crypt(password
, pw
->pw_passwd
), pw
->pw_passwd
) == 0) {
153 siResult
= CHECKPW_SUCCESS
;
157 // Try Directory Services directly
159 result
= mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &replyPort
);
160 if ( result
!= err_none
) {
161 siResult
= CHECKPW_FAILURE
;
165 result
= task_get_bootstrap_port( mach_task_self(), &bsPort
);
166 if ( result
!= err_none
) {
167 siResult
= CHECKPW_FAILURE
;
171 // check if DirectoryService is alive
172 result
= bootstrap_look_up( bsPort
, (char *)srvrName
, &serverPort
);
173 if ( result
!= err_none
) {
174 siResult
= CHECKPW_FAILURE
;
178 // ask directory services to do auth
179 msg
= calloc( sizeof( sIPCMsg
), 1 );
181 siResult
= CHECKPW_FAILURE
; // memory error
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
);
191 len
= strlen( userName
);
192 if (curr
+ len
+ sizeof(unsigned long) > kIPCMsgLen
)
194 siResult
= CHECKPW_FAILURE
;
197 memcpy( &(msg
->fData
[ curr
]), &len
, sizeof( unsigned long ) );
198 curr
+= sizeof( unsigned long );
199 memcpy( &(msg
->fData
[ curr
]), userName
, len
);
203 len
= strlen( password
);
204 if (curr
+ len
+ sizeof(unsigned long) > kIPCMsgLen
)
206 siResult
= CHECKPW_FAILURE
;
209 memcpy( &(msg
->fData
[ curr
]), &len
, sizeof( unsigned long ) );
210 curr
+= sizeof ( unsigned long );
211 memcpy( &(msg
->fData
[ curr
]), password
, len
);
213 msg
->obj
[0].used
= curr
;
214 msg
->obj
[0].length
= curr
;
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
;
222 msg
->fMsgType
= kCheckUserNameAndPassword
;
225 msg
->fPort
= replyPort
;
226 msg
->fPID
= getpid();
227 msg
->fMsgID
= time( NULL
) + kCheckUserNameAndPassword
;
230 result
= mach_msg_send( (mach_msg_header_t
*)msg
);
231 if ( result
!= MACH_MSG_SUCCESS
) {
232 siResult
= CHECKPW_FAILURE
;
237 memset( msg
, 0, kIPCMsgLen
);
239 result
= mach_msg( (mach_msg_header_t
*)msg
, MACH_RCV_MSG
| MACH_RCV_TIMEOUT
,
240 0, kIPCMsgSize
, replyPort
, 300 * 1000, MACH_PORT_NULL
);
242 if ( result
!= MACH_MSG_SUCCESS
) {
243 siResult
= CHECKPW_FAILURE
;
247 if ( msg
->fCount
!= 1 ) {
248 // couldn't get reply
249 siResult
= CHECKPW_FAILURE
;
253 for (i
= 0; i
< 10; i
++ )
255 if ( msg
->obj
[ i
].type
== (unsigned long)kResult
)
257 siResult
= msg
->obj
[ i
].count
;
269 if ( replyPort
!= 0 )
270 mach_port_deallocate( mach_task_self(), replyPort
);