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
;
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
75 #define kIPCMsgSize sizeof( sIPCMsg )
77 typedef struct sIPCMsg
79 mach_msg_header_t fHeader
;
80 unsigned long fMsgType
;
87 char fData
[ kIPCMsgLen
];
88 mach_msg_security_trailer_t fTail
;
97 /* 9 */ kCheckUserNameAndPassword
= 9
99 // end copied from SharedConsts.h
101 int checkpw( const char* userName
, const char* password
)
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";
111 unsigned long len
= 0;
115 pw
= getpwnam( userName
);
118 return CHECKPW_UNKNOWNUSER
;
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
;
128 siResult
= CHECKPW_BADPASSWORD
;
133 // Correct password hash
134 if (strcmp(crypt(password
, pw
->pw_passwd
), pw
->pw_passwd
) == 0) {
135 siResult
= CHECKPW_SUCCESS
;
139 // Special marker for Directory Services
140 if (strcmp(pw
->pw_passwd
,"********") != 0) {
141 siResult
= CHECKPW_BADPASSWORD
;
145 result
= mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &replyPort
);
146 if ( result
!= err_none
) {
147 siResult
= CHECKPW_FAILURE
;
151 result
= task_get_bootstrap_port( mach_task_self(), &bsPort
);
152 if ( result
!= err_none
) {
153 siResult
= CHECKPW_FAILURE
;
157 // check if DirectoryService is alive
158 result
= bootstrap_look_up( bsPort
, (char *)srvrName
, &serverPort
);
159 if ( result
!= err_none
) {
160 siResult
= CHECKPW_FAILURE
;
164 // ask directory services to do auth
165 msg
= calloc( sizeof( sIPCMsg
), 1 );
167 siResult
= CHECKPW_FAILURE
; // memory error
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
);
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
);
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
);
189 msg
->obj
[0].used
= curr
;
190 msg
->obj
[0].length
= curr
;
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
;
198 msg
->fMsgType
= kCheckUserNameAndPassword
;
201 msg
->fPort
= replyPort
;
202 msg
->fPID
= getpid();
203 msg
->fMsgID
= time( NULL
) + kCheckUserNameAndPassword
;
206 result
= mach_msg_send( (mach_msg_header_t
*)msg
);
207 if ( result
!= MACH_MSG_SUCCESS
) {
208 siResult
= CHECKPW_FAILURE
;
213 memset( msg
, 0, kIPCMsgLen
);
215 result
= mach_msg( (mach_msg_header_t
*)msg
, MACH_RCV_MSG
| MACH_RCV_TIMEOUT
,
216 0, kIPCMsgSize
, replyPort
, 300 * 1000, MACH_PORT_NULL
);
218 if ( result
!= MACH_MSG_SUCCESS
) {
219 siResult
= CHECKPW_FAILURE
;
223 if ( msg
->fCount
!= 1 ) {
224 // couldn't get reply
225 siResult
= CHECKPW_FAILURE
;
229 for (i
= 0; i
< 10; i
++ )
231 if ( msg
->obj
[ i
].type
== (unsigned long)kResult
)
233 siResult
= msg
->obj
[ i
].count
;
245 if ( replyPort
!= 0 )
246 mach_port_deallocate( mach_task_self(), replyPort
);