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_internal( const struct passwd
* pw
, const char* password
);
104 int checkpw( const char* userName
, const char* password
)
106 struct passwd
* pw
= NULL
;
109 // Check username, NULL can crash in getpwnam
111 return CHECKPW_UNKNOWNUSER
;
113 pw
= getpwnam( userName
);
115 return CHECKPW_UNKNOWNUSER
;
117 status
= checkpw_internal(pw
, password
);
122 int checkpw_internal( const struct passwd
* pw
, const char* password
)
124 int siResult
= CHECKPW_FAILURE
;
125 kern_return_t result
= err_none
;
126 mach_port_t bsPort
= 0;
127 mach_port_t serverPort
= 0;
128 mach_port_t replyPort
= 0;
129 const char *const srvrName
= "DirectoryService";
131 unsigned long len
= 0;
137 // Special case for empty password (this explicitly denies UNIX-like behavior)
138 if (pw
->pw_passwd
== NULL
|| pw
->pw_passwd
[0] == '\0') {
139 if (password
== NULL
|| password
[0] == '\0')
140 siResult
= CHECKPW_SUCCESS
;
142 siResult
= CHECKPW_BADPASSWORD
;
147 // check password, NULL crashes crypt()
150 siResult
= CHECKPW_BADPASSWORD
;
153 // Correct password hash
154 if (strcmp(crypt(password
, pw
->pw_passwd
), pw
->pw_passwd
) == 0) {
155 siResult
= CHECKPW_SUCCESS
;
159 // Try Directory Services directly
161 result
= mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &replyPort
);
162 if ( result
!= err_none
) {
163 siResult
= CHECKPW_FAILURE
;
167 result
= task_get_bootstrap_port( mach_task_self(), &bsPort
);
168 if ( result
!= err_none
) {
169 siResult
= CHECKPW_FAILURE
;
173 // check if DirectoryService is alive
174 result
= bootstrap_look_up( bsPort
, (char *)srvrName
, &serverPort
);
175 if ( result
!= err_none
) {
176 siResult
= CHECKPW_FAILURE
;
180 // ask directory services to do auth
181 msg
= calloc( sizeof( sIPCMsg
), 1 );
183 siResult
= CHECKPW_FAILURE
; // memory error
187 // put username and password into message
188 msg
->obj
[0].type
= ktDataBuff
;
189 msg
->obj
[0].count
= 1;
190 msg
->obj
[0].offset
= offsetof(struct sComData
, data
);
193 len
= strlen( pw
->pw_name
);
194 if (curr
+ len
+ sizeof(unsigned long) > kIPCMsgLen
)
196 siResult
= CHECKPW_FAILURE
;
199 memcpy( &(msg
->fData
[ curr
]), &len
, sizeof( unsigned long ) );
200 curr
+= sizeof( unsigned long );
201 memcpy( &(msg
->fData
[ curr
]), pw
->pw_name
, len
);
205 len
= strlen( password
);
206 if (curr
+ len
+ sizeof(unsigned long) > kIPCMsgLen
)
208 siResult
= CHECKPW_FAILURE
;
211 memcpy( &(msg
->fData
[ curr
]), &len
, sizeof( unsigned long ) );
212 curr
+= sizeof ( unsigned long );
213 memcpy( &(msg
->fData
[ curr
]), password
, len
);
215 msg
->obj
[0].used
= curr
;
216 msg
->obj
[0].length
= curr
;
218 msg
->fHeader
.msgh_bits
= MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND
, MACH_MSG_TYPE_MAKE_SEND
);
219 msg
->fHeader
.msgh_size
= sizeof( sIPCMsg
) - sizeof( mach_msg_security_trailer_t
);
220 msg
->fHeader
.msgh_id
= kCheckUserNameAndPassword
;
221 msg
->fHeader
.msgh_remote_port
= serverPort
;
222 msg
->fHeader
.msgh_local_port
= replyPort
;
224 msg
->fMsgType
= kCheckUserNameAndPassword
;
227 msg
->fPort
= replyPort
;
228 msg
->fPID
= getpid();
229 msg
->fMsgID
= time( NULL
) + kCheckUserNameAndPassword
;
232 result
= mach_msg_send( (mach_msg_header_t
*)msg
);
233 if ( result
!= MACH_MSG_SUCCESS
) {
234 siResult
= CHECKPW_FAILURE
;
239 memset( msg
, 0, kIPCMsgLen
);
241 result
= mach_msg( (mach_msg_header_t
*)msg
, MACH_RCV_MSG
| MACH_RCV_TIMEOUT
,
242 0, kIPCMsgSize
, replyPort
, 300 * 1000, MACH_PORT_NULL
);
244 if ( result
!= MACH_MSG_SUCCESS
) {
245 siResult
= CHECKPW_FAILURE
;
249 if ( msg
->fCount
!= 1 ) {
250 // couldn't get reply
251 siResult
= CHECKPW_FAILURE
;
255 for (i
= 0; i
< 10; i
++ )
257 if ( msg
->obj
[ i
].type
== (unsigned long)kResult
)
259 siResult
= msg
->obj
[ i
].count
;
271 // deallocate the serverPort
272 mach_port_deallocate( mach_task_self(), serverPort
);
274 if ( replyPort
!= 0 )
275 mach_port_destroy( mach_task_self(), replyPort
);