]> git.saurik.com Git - apple/system_cmds.git/blob - passwd.tproj/ds_passwd.c
38f21c9fdeb3b0f276614c53526b7c956e85a95c
[apple/system_cmds.git] / passwd.tproj / ds_passwd.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <net/if.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <sys/ioctl.h>
33 #include <errno.h>
34 #include <pwd.h>
35 #include <netdb.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include <sys/dirent.h>
39
40 #include <DirectoryService/DirServices.h>
41 #include <DirectoryService/DirServicesConst.h>
42 #include <DirectoryService/DirServicesTypes.h>
43 #include <DirectoryService/DirServicesUtils.h>
44
45 // password server can store 511 characters + a terminator.
46 #define kMaxPassword 512
47
48 //-------------------------------------------------------------------------------------
49 // ds_getpasswd
50 //-------------------------------------------------------------------------------------
51
52 void
53 ds_getpasswd(const char *loginUser, char *name, int isroot, int wasroot, int changePassOnSelf, char **old_clear, char **new_clear)
54 {
55 int tries, len;
56 char *p;
57 static char obuf[kMaxPassword];
58 static char nbuf[kMaxPassword];
59 char prompt[MAXNAMLEN + 16];
60
61 printf("Changing password for %s.\n", name);
62
63 p = "";
64
65 if (isroot == 0)
66 {
67 if ( changePassOnSelf )
68 {
69 strcpy( prompt, "Old password:" );
70 }
71 else
72 {
73 snprintf( prompt, sizeof(prompt), "password for %s:", loginUser );
74 }
75
76 p = getpass( prompt );
77 snprintf( obuf, sizeof(obuf), "%s", p );
78 }
79
80 if ( wasroot == 0 )
81 {
82 tries = 0;
83 nbuf[0] = '\0';
84 for (;;)
85 {
86 p = getpass("New password:");
87 if (!*p)
88 {
89 printf("Password unchanged.\n");
90 exit(0);
91 }
92
93 tries++;
94 len = strlen(p);
95
96 snprintf( nbuf, sizeof(nbuf), "%s", p );
97 if (!strcmp(nbuf, getpass("Retype new password:"))) break;
98
99 printf("Mismatch; try again, EOF to quit.\n");
100 }
101 }
102
103 *old_clear = obuf;
104 *new_clear = nbuf;
105 }
106
107
108 //-------------------------------------------------------------------------------------
109 // ds_passwd
110 //-------------------------------------------------------------------------------------
111
112 int
113 ds_passwd(char *uname, char *locn)
114 {
115 tDirReference dsRef = 0;
116 tDataBuffer *tDataBuff = NULL;
117 tDirNodeReference nodeRef = 0;
118 long status = eDSNoErr;
119 tContextData context = NULL;
120 unsigned long nodeCount = 0;
121 unsigned long attrIndex = 0;
122 tDataList *nodeName = NULL;
123 tAttributeEntryPtr pAttrEntry = NULL;
124 tDataList *pRecName = NULL;
125 tDataList *pRecType = NULL;
126 tDataList *pAttrType = NULL;
127 unsigned long recCount = 0;
128 tRecordEntry *pRecEntry = NULL;
129 tAttributeListRef attrListRef = 0;
130 char *pUserLocation = NULL;
131 char *pUserName = NULL;
132 tAttributeValueListRef valueRef = 0;
133 tAttributeValueEntry *pValueEntry = NULL;
134 tDataList *pUserNode = NULL;
135 tDirNodeReference userNodeRef = 0;
136 tDataBuffer *pStepBuff = NULL;
137 tDataNode *pAuthType = NULL;
138 unsigned long uiCurr = 0;
139 unsigned long uiLen = 0;
140 char *old_clear = NULL;
141 char *new_clear = NULL;
142 int isroot = 0;
143 int wasroot = 0;
144 char *loginUser = NULL;
145 int changePassOnSelf = 1;
146 const char *errMsgStr = NULL;
147 struct passwd *userRec = NULL;
148
149 if (uname == NULL)
150 return -1;
151
152 /* getlogin() is the wrong thing to use here. Use getpwuid(getuid()); */
153 /* sns 5 Jan 2005 */
154
155 userRec = getpwuid( getuid() );
156 if ( userRec != NULL ) {
157 loginUser = userRec->pw_name;
158 if ( loginUser != NULL )
159 changePassOnSelf = (strcmp(loginUser, uname) == 0);
160 }
161
162 status = dsOpenDirService( &dsRef );
163 if (status != eDSNoErr)
164 return status;
165
166 do
167 {
168 if ( tDataBuff == NULL )
169 tDataBuff = dsDataBufferAllocate( dsRef, 4096 );
170 if (tDataBuff == NULL) break;
171
172 if ( locn != NULL )
173 {
174 nodeName = dsBuildFromPath( dsRef, locn, "/" );
175 if ( nodeName == NULL ) break;
176
177 // find
178 status = dsFindDirNodes( dsRef, tDataBuff, nodeName, eDSiExact, &nodeCount, &context );
179 }
180 else
181 {
182 // find on search node
183 status = dsFindDirNodes( dsRef, tDataBuff, NULL, eDSSearchNodeName, &nodeCount, &context );
184 }
185
186 if (status != eDSNoErr) break;
187 if ( nodeCount < 1 ) {
188 status = eDSNodeNotFound;
189 break;
190 }
191
192 if ( isroot == 1 )
193 {
194 // we already tried SetPasswordAsRoot and it didn't work
195 // get the old (current) password and try again
196
197 // getpass
198 isroot = 0;
199 wasroot = 1;
200 }
201 else
202 if ( getuid() == 0 )
203 isroot = 1;
204
205 ds_getpasswd( loginUser, uname, isroot, wasroot, changePassOnSelf, &old_clear, &new_clear );
206
207 status = dsGetDirNodeName( dsRef, tDataBuff, 1, &nodeName );
208 if (status != eDSNoErr) continue;
209
210 status = dsOpenDirNode( dsRef, nodeName, &nodeRef );
211 dsDataListDeallocate( dsRef, nodeName );
212 free( nodeName );
213 nodeName = NULL;
214 if (status != eDSNoErr) continue;
215
216 pRecName = dsBuildListFromStrings( dsRef, uname, NULL );
217 pRecType = dsBuildListFromStrings( dsRef, kDSStdRecordTypeUsers, NULL );
218 pAttrType = dsBuildListFromStrings( dsRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, NULL );
219
220 recCount = 1;
221 status = dsGetRecordList( nodeRef, tDataBuff, pRecName, eDSExact, pRecType,
222 pAttrType, 0, &recCount, &context );
223 if ( status != eDSNoErr ) break;
224 if ( recCount == 0 ) {
225 status = eDSAuthUnknownUser;
226 break;
227 }
228
229 status = dsGetRecordEntry( nodeRef, tDataBuff, 1, &attrListRef, &pRecEntry );
230 if ( status != eDSNoErr ) break;
231
232 for ( attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++ )
233 {
234 status = dsGetAttributeEntry( nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry );
235 if ( status == eDSNoErr && pAttrEntry != NULL )
236 {
237 if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
238 {
239 status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
240 if ( status == eDSNoErr && pValueEntry != NULL )
241 {
242 pUserLocation = (char *) calloc( pValueEntry->fAttributeValueData.fBufferLength + 1, sizeof(char) );
243 memcpy( pUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
244 }
245 }
246 else
247 if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
248 {
249 status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
250 if ( status == eDSNoErr && pValueEntry != NULL )
251 {
252 pUserName = (char *) calloc( pValueEntry->fAttributeValueData.fBufferLength + 1, sizeof(char) );
253 memcpy( pUserName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
254 }
255 }
256
257 if ( pValueEntry != NULL )
258 dsDeallocAttributeValueEntry( dsRef, pValueEntry );
259 pValueEntry = NULL;
260
261 dsDeallocAttributeEntry( dsRef, pAttrEntry );
262 pAttrEntry = NULL;
263 dsCloseAttributeValueList( valueRef );
264 valueRef = 0;
265 }
266 }
267
268 if ( pUserLocation == NULL || pUserName == NULL ) {
269 status = eDSAuthInvalidUserName;
270 break;
271 }
272
273 pUserNode = dsBuildFromPath( dsRef, pUserLocation, "/" );
274 status = dsOpenDirNode( dsRef, pUserNode, &userNodeRef );
275 if ( status != eDSNoErr ) break;
276
277 pStepBuff = dsDataBufferAllocate( dsRef, 128 );
278
279 if ( isroot )
280 {
281 pAuthType = dsDataNodeAllocateString( dsRef, kDSStdAuthSetPasswdAsRoot );
282 uiCurr = 0;
283
284 // User name
285 uiLen = strlen( pUserName );
286 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
287 uiCurr += sizeof( unsigned long );
288 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), pUserName, uiLen );
289 uiCurr += uiLen;
290
291 // new pw
292 uiLen = strlen( new_clear );
293 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
294 uiCurr += sizeof( unsigned long );
295 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), new_clear, uiLen );
296 uiCurr += uiLen;
297
298 tDataBuff->fBufferLength = uiCurr;
299
300 status = dsDoDirNodeAuth( userNodeRef, pAuthType, 1, tDataBuff, pStepBuff, NULL );
301 }
302 else
303 if ( changePassOnSelf )
304 {
305 pAuthType = dsDataNodeAllocateString( dsRef, kDSStdAuthChangePasswd );
306 uiCurr = 0;
307
308 // User name
309 uiLen = strlen( pUserName );
310 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
311 uiCurr += sizeof( unsigned long );
312 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), pUserName, uiLen );
313 uiCurr += uiLen;
314
315 // old pw
316 uiLen = strlen( old_clear );
317 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
318 uiCurr += sizeof( unsigned long );
319 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), old_clear, uiLen );
320 uiCurr += uiLen;
321
322 // new pw
323 uiLen = strlen( new_clear );
324 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
325 uiCurr += sizeof( unsigned long );
326 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), new_clear, uiLen );
327 uiCurr += uiLen;
328
329 tDataBuff->fBufferLength = uiCurr;
330
331 status = dsDoDirNodeAuth( userNodeRef, pAuthType, 1, tDataBuff, pStepBuff, NULL );
332 }
333 else
334 if ( loginUser != NULL )
335 {
336 pAuthType = dsDataNodeAllocateString( dsRef, kDSStdAuthSetPasswd );
337 uiCurr = 0;
338
339 // User name
340 uiLen = strlen( pUserName );
341 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
342 uiCurr += sizeof( unsigned long );
343 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), pUserName, uiLen );
344 uiCurr += uiLen;
345
346 // new pw
347 uiLen = strlen( new_clear );
348 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
349 uiCurr += sizeof( unsigned long );
350 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), new_clear, uiLen );
351 uiCurr += uiLen;
352
353 // Authenticator name
354 uiLen = strlen( loginUser );
355 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
356 uiCurr += sizeof( unsigned long );
357 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), loginUser, uiLen );
358 uiCurr += uiLen;
359
360 // authenticator pw
361 uiLen = strlen( old_clear );
362 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
363 uiCurr += sizeof( unsigned long );
364 memcpy( &(tDataBuff->fBufferData[ uiCurr ]), old_clear, uiLen );
365 uiCurr += uiLen;
366
367 tDataBuff->fBufferLength = uiCurr;
368
369 status = dsDoDirNodeAuth( userNodeRef, pAuthType, 1, tDataBuff, pStepBuff, NULL );
370 }
371 else
372 {
373 status = eDSAuthFailed;
374 }
375 }
376 while ( isroot == 1 && status != eDSNoErr );
377
378 /* old_clear and new_clear are statics (don't call free) */
379 if (old_clear != NULL) {
380 memset(old_clear, 0, strlen(old_clear));
381 }
382 if (new_clear != NULL) {
383 memset(new_clear, 0, strlen(new_clear));
384 }
385 if (tDataBuff != NULL) {
386 memset(tDataBuff, 0, tDataBuff->fBufferSize);
387 dsDataBufferDeAllocate( dsRef, tDataBuff );
388 tDataBuff = NULL;
389 }
390
391 if (pStepBuff != NULL) {
392 dsDataBufferDeAllocate( dsRef, pStepBuff );
393 pStepBuff = NULL;
394 }
395 if (pUserLocation != NULL ) {
396 free(pUserLocation);
397 pUserLocation = NULL;
398 }
399 if (pRecName != NULL) {
400 dsDataListDeallocate( dsRef, pRecName );
401 free( pRecName );
402 pRecName = NULL;
403 }
404 if (pRecType != NULL) {
405 dsDataListDeallocate( dsRef, pRecType );
406 free( pRecType );
407 pRecType = NULL;
408 }
409 if (pAttrType != NULL) {
410 dsDataListDeallocate( dsRef, pAttrType );
411 free( pAttrType );
412 pAttrType = NULL;
413 }
414 if (nodeRef != 0) {
415 dsCloseDirNode(nodeRef);
416 nodeRef = 0;
417 }
418 if (dsRef != 0) {
419 dsCloseDirService(dsRef);
420 dsRef = 0;
421 }
422
423 if ( status != eDSNoErr ) {
424 errno = EACCES;
425 switch( status )
426 {
427 case eDSAuthPasswordTooShort:
428 errMsgStr = "The new password is too short.";
429 break;
430
431 case eDSAuthPasswordTooLong:
432 errMsgStr = "The new password is too long.";
433 break;
434
435 case eDSAuthPasswordNeedsLetter:
436 errMsgStr = "The new password must contain a letter.";
437 break;
438
439 case eDSAuthPasswordNeedsDigit:
440 errMsgStr = "The new password must contain a number.";
441 break;
442
443 default:
444 errMsgStr = "Sorry";
445 }
446 fprintf(stderr, "%s\n", errMsgStr);
447 exit(1);
448 }
449
450 return status;
451 }
452
453
454
455
456
457
458
459
460
461
462