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 pw
= getpwnam( userName
);
109 return CHECKPW_UNKNOWNUSER
;
111 status
= checkpw_internal(userName
, password
, pw
);
116 int checkpw_internal( const char* userName
, const char* password
, const struct passwd
* pw
)
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";
125 unsigned long len
= 0;
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
;
136 siResult
= CHECKPW_BADPASSWORD
;
141 // Correct password hash
142 if (strcmp(crypt(password
, pw
->pw_passwd
), pw
->pw_passwd
) == 0) {
143 siResult
= CHECKPW_SUCCESS
;
147 // Try Directory Services directly
149 result
= mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &replyPort
);
150 if ( result
!= err_none
) {
151 siResult
= CHECKPW_FAILURE
;
155 result
= task_get_bootstrap_port( mach_task_self(), &bsPort
);
156 if ( result
!= err_none
) {
157 siResult
= CHECKPW_FAILURE
;
161 // check if DirectoryService is alive
162 result
= bootstrap_look_up( bsPort
, (char *)srvrName
, &serverPort
);
163 if ( result
!= err_none
) {
164 siResult
= CHECKPW_FAILURE
;
168 // ask directory services to do auth
169 msg
= calloc( sizeof( sIPCMsg
), 1 );
171 siResult
= CHECKPW_FAILURE
; // memory error
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
);
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
);
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
);
193 msg
->obj
[0].used
= curr
;
194 msg
->obj
[0].length
= curr
;
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
;
202 msg
->fMsgType
= kCheckUserNameAndPassword
;
205 msg
->fPort
= replyPort
;
206 msg
->fPID
= getpid();
207 msg
->fMsgID
= time( NULL
) + kCheckUserNameAndPassword
;
210 result
= mach_msg_send( (mach_msg_header_t
*)msg
);
211 if ( result
!= MACH_MSG_SUCCESS
) {
212 siResult
= CHECKPW_FAILURE
;
217 memset( msg
, 0, kIPCMsgLen
);
219 result
= mach_msg( (mach_msg_header_t
*)msg
, MACH_RCV_MSG
| MACH_RCV_TIMEOUT
,
220 0, kIPCMsgSize
, replyPort
, 300 * 1000, MACH_PORT_NULL
);
222 if ( result
!= MACH_MSG_SUCCESS
) {
223 siResult
= CHECKPW_FAILURE
;
227 if ( msg
->fCount
!= 1 ) {
228 // couldn't get reply
229 siResult
= CHECKPW_FAILURE
;
233 for (i
= 0; i
< 10; i
++ )
235 if ( msg
->obj
[ i
].type
== (unsigned long)kResult
)
237 siResult
= msg
->obj
[ i
].count
;
249 if ( replyPort
!= 0 )
250 mach_port_deallocate( mach_task_self(), replyPort
);