2 #include "open_directory.h"
7 #include <sys/sysctl.h>
8 #include <OpenDirectory/OpenDirectory.h>
9 #include <OpenDirectory/OpenDirectoryPriv.h>
11 /*---------------------------------------------------------------------------
12 * PUBLIC setrestricted - sets the restricted flag
13 *---------------------------------------------------------------------------*/
15 setrestricted(CFDictionaryRef attrs
)
17 const char* user_allowed
[] = { "shell", "full name", "office location", "office phone", "home phone", "picture", NULL
};
18 const char* root_restricted
[] = { "password", "change", "expire", "class", NULL
};
21 int restrict_by_default
= !master_mode
;
23 // for ordinary users, everything is restricted except for the values
24 // expressly permitted above
25 // for root, everything is permitted except for the values expressly
28 for (ep
= list
; ep
->prompt
; ep
++) {
29 ep
->restricted
= restrict_by_default
;
30 pp
= restrict_by_default
? user_allowed
: root_restricted
;
32 if (strncasecmp(ep
->prompt
, *pp
, ep
->len
) == 0) {
33 ep
->restricted
= !restrict_by_default
;
38 // If not root, then it is only permitted to change the shell
39 // when the original value is one of the approved shells.
40 // Otherwise, the assumption is that root has given this user
41 // a restricted shell which they must not change away from.
42 if (restrict_by_default
&& strcmp(ep
->prompt
, "shell") == 0) {
44 CFArrayRef values
= CFDictionaryGetValue(attrs
, kODAttributeTypeUserShell
);
45 CFTypeRef value
= values
&& CFArrayGetCount(values
) > 0 ? CFArrayGetValueAtIndex(values
, 0) : NULL
;
46 if (value
&& CFGetTypeID(value
) == CFStringGetTypeID()) {
47 size_t size
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value
), kCFStringEncodingUTF8
)+1;
48 char* shell
= malloc(size
);
49 if (CFStringGetCString(value
, shell
, size
, kCFStringEncodingUTF8
)) {
50 if (ok_shell(shell
)) {
60 prompt_passwd(CFStringRef user
)
62 CFStringRef result
= NULL
;
63 CFStringRef prompt
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("Password for %@: "), user
);
64 size_t prompt_size
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(prompt
), kCFStringEncodingUTF8
);
65 char* buf
= malloc(prompt_size
);
66 CFStringGetCString(prompt
, buf
, prompt_size
, kCFStringEncodingUTF8
);
67 char* pass
= getpass(buf
);
68 result
= CFStringCreateWithCString(NULL
, pass
, kCFStringEncodingUTF8
);
69 memset(pass
, 0, strlen(pass
));
76 show_error(CFErrorRef error
) {
78 CFStringRef desc
= CFErrorCopyDescription(error
);
80 cfprintf(stderr
, "%s: %@", progname
, desc
);
83 desc
= CFErrorCopyFailureReason(error
);
84 if (desc
) cfprintf(stderr
, " %@", desc
);
86 desc
= CFErrorCopyRecoverySuggestion(error
);
87 if (desc
) cfprintf(stderr
, " %@", desc
);
89 fprintf(stderr
, "\n");
94 odGetUser(CFStringRef location
, CFStringRef authname
, CFStringRef user
, CFDictionaryRef
* attrs
)
96 ODNodeRef node
= NULL
;
97 ODRecordRef rec
= NULL
;
98 CFErrorRef error
= NULL
;
103 * Open the specified node, or perform a search.
104 * Copy the record and put the record's location into DSPath.
107 node
= ODNodeCreateWithName(NULL
, kODSessionDefault
, location
, &error
);
109 node
= ODNodeCreateWithNodeType(NULL
, kODSessionDefault
, kODNodeTypeAuthentication
, &error
);
112 CFTypeRef vals
[] = { kODAttributeTypeStandardOnly
};
113 CFArrayRef desiredAttrs
= CFArrayCreate(NULL
, vals
, 1, &kCFTypeArrayCallBacks
);
114 rec
= ODNodeCopyRecord(node
, kODRecordTypeUsers
, user
, desiredAttrs
, &error
);
115 if (desiredAttrs
) CFRelease(desiredAttrs
);
119 *attrs
= ODRecordCopyDetails(rec
, NULL
, &error
);
121 CFArrayRef values
= CFDictionaryGetValue(*attrs
, kODAttributeTypeMetaNodeLocation
);
122 DSPath
= (values
&& CFArrayGetCount(values
) > 0) ? CFArrayGetValueAtIndex(values
, 0) : NULL
;
126 * Prompt for a password if -u was specified,
127 * or if we are not root,
128 * or if we are updating something not on the
131 if (authname
|| !master_mode
||
132 (DSPath
&& CFStringCompareWithOptions(DSPath
, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo
)) {
134 CFStringRef password
= NULL
;
136 if (!authname
) authname
= user
;
138 password
= prompt_passwd(authname
);
139 if (!ODRecordSetNodeCredentials(rec
, authname
, password
, &error
)) {
146 if (error
) show_error(error
);
151 odUpdateUser(ODRecordRef rec
, CFDictionaryRef attrs_orig
, CFDictionaryRef attrs
)
153 CFErrorRef error
= NULL
;
157 for (ep
= list
; ep
->prompt
; ep
++) {
160 if (!rec
|| !attrs_orig
|| !attrs
) break;
162 // No need to update if entry is restricted
163 if (ep
->restricted
) continue;
165 CFArrayRef values_orig
= CFDictionaryGetValue(attrs_orig
, *ep
->attrName
);
166 CFTypeRef value_orig
= values_orig
&& CFArrayGetCount(values_orig
) ? CFArrayGetValueAtIndex(values_orig
, 0) : NULL
;
167 CFTypeRef value
= CFDictionaryGetValue(attrs
, *ep
->attrName
);
169 // No need to update if both values are the same
170 if (value
== value_orig
) continue;
172 // No need to update if strings are equal
173 if (value
&& value_orig
) {
174 if (CFGetTypeID(value_orig
) == CFStringGetTypeID() &&
175 CFStringCompare(value_orig
, value
, 0) == kCFCompareEqualTo
) continue;
178 // No need to update if empty string replaces NULL
179 if (!value_orig
&& value
) {
180 if (CFStringGetLength(value
) == 0) continue;
185 // if new value is an empty string, send an empty dictionary which will delete the property.
186 CFIndex count
= CFEqual(value
, CFSTR("")) ? 0 : 1;
187 CFTypeRef vals
[] = { value
};
188 CFArrayRef values
= CFArrayCreate(NULL
, vals
, count
, &kCFTypeArrayCallBacks
);
189 if (values
&& ODRecordSetValue(rec
, *ep
->attrName
, values
, &error
)) {
192 if (values
) CFRelease(values
);
193 if (error
) show_error(error
);
198 updated
= ODRecordSynchronize(rec
, &error
);
199 if (error
) show_error(error
);
202 fprintf(stderr
, "%s: no changes made\n", progname
);
205 #endif /* OPEN_DIRECTORY */