Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * | |
3 | * aklog auth plugin, Taken from rot13 with guidance from NullAuthPlugin | |
4 | * Copyright (c) 2010 Your File System Inc. All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR | |
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 | */ | |
26 | ||
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
29 | #include <syslog.h> | |
30 | #include <unistd.h> | |
31 | #include <sys/kauth.h> | |
32 | ||
33 | #include <Security/AuthorizationTags.h> | |
34 | #include <Security/AuthorizationPlugin.h> | |
35 | #include <DirectoryService/DirectoryService.h> | |
36 | ||
37 | typedef struct PluginRef | |
38 | { | |
39 | const AuthorizationCallbacks *callbacks; | |
40 | } PluginRef; | |
41 | ||
42 | typedef struct MechanismRef | |
43 | { | |
44 | const PluginRef *plugin; | |
45 | AuthorizationEngineRef engine; | |
46 | char *mechanismArg; | |
47 | } MechanismRef; | |
48 | ||
49 | static OSStatus do_aklog(char *cell) | |
50 | { | |
51 | /* | |
52 | * The first draft used aklog source inline. In an rxgk | |
53 | * universe, that code should be encapsulated in a library | |
54 | * we call. In this version we simply fork aklog. | |
55 | * This function should be replaced with calls to a "libaklog" | |
56 | */ | |
57 | ||
58 | char *aklogCmd; | |
59 | if (cell) { | |
60 | if (asprintf(&aklogCmd, "/usr/bin/aklog %s", cell) < 0) | |
61 | aklogCmd = NULL; | |
62 | if (aklogCmd) | |
63 | return system(aklogCmd); | |
64 | else | |
65 | return -1; | |
66 | } | |
67 | ||
68 | return system("/usr/bin/aklog"); | |
69 | } | |
70 | ||
71 | static OSStatus invokeAklog(MechanismRef *mechanism) | |
72 | { | |
73 | AuthorizationContextFlags contextFlags; | |
74 | const AuthorizationValue *value; | |
75 | OSStatus status; | |
76 | uid_t uid = 0; | |
77 | gid_t gid = 0; | |
78 | ||
79 | /* a list of context values appears in the Null sample plugin */ | |
80 | status = mechanism->plugin->callbacks->GetContextValue(mechanism->engine, | |
81 | kDS1AttrUniqueID, | |
82 | &contextFlags, | |
83 | &value); | |
84 | ||
85 | /* This and the group are strings. I don't know why. */ | |
86 | if (!status) | |
87 | uid = atoi(value->data); | |
88 | else | |
89 | goto failed; | |
90 | ||
91 | status = mechanism->plugin->callbacks->GetContextValue(mechanism->engine, | |
92 | kDS1AttrPrimaryGroupID, | |
93 | &contextFlags, | |
94 | &value); | |
95 | if (!status) | |
96 | gid = atoi(value->data); | |
97 | else | |
98 | goto failed; | |
99 | ||
100 | /* in a PAGless universe, this trick works */ | |
101 | status = pthread_setugid_np(uid, gid); | |
102 | if (status == 0) { | |
103 | status = do_aklog(mechanism->mechanismArg); | |
104 | pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE); | |
105 | if (status) | |
106 | goto failed; | |
107 | } | |
108 | ||
109 | status = | |
110 | mechanism->plugin->callbacks->SetResult(mechanism->engine, | |
111 | kAuthorizationResultAllow); | |
112 | ||
113 | if (!status) | |
114 | return errAuthorizationSuccess; | |
115 | ||
116 | failed: | |
117 | return errAuthorizationInternal; | |
118 | } | |
119 | ||
120 | static OSStatus pluginDestroy(AuthorizationPluginRef inPlugin) | |
121 | { | |
122 | /* seems to not be called. can't do cleanup? */ | |
123 | PluginRef *plugin = (PluginRef *)inPlugin; | |
124 | free(plugin); | |
125 | return 0; | |
126 | } | |
127 | ||
128 | static OSStatus mechanismCreate(AuthorizationPluginRef inPlugin, | |
129 | AuthorizationEngineRef inEngine, | |
130 | AuthorizationMechanismId mechanismId, | |
131 | AuthorizationMechanismRef *outMechanism) | |
132 | { | |
133 | const PluginRef *plugin = (const PluginRef *)inPlugin; | |
134 | ||
135 | MechanismRef *mechanism = calloc(1, sizeof(MechanismRef)); | |
136 | ||
137 | mechanism->plugin = plugin; | |
138 | mechanism->engine = inEngine; | |
139 | /* | |
140 | * consider supporting a variant which backgrounds aklog and returns | |
141 | * success where tokens are desired but not critical. | |
142 | */ | |
143 | mechanism->mechanismArg = strdup(mechanismId); | |
144 | ||
145 | *outMechanism = mechanism; | |
146 | ||
147 | return 0; | |
148 | } | |
149 | ||
150 | ||
151 | static OSStatus mechanismInvoke(AuthorizationMechanismRef inMechanism) | |
152 | { | |
153 | MechanismRef *mechanism = (MechanismRef *)inMechanism; | |
154 | OSStatus status; | |
155 | ||
156 | status = invokeAklog(mechanism); | |
157 | if (status) | |
158 | return errAuthorizationInternal; | |
159 | ||
160 | /* mark success */ | |
161 | return mechanism->plugin->callbacks->SetResult(mechanism->engine, kAuthorizationResultAllow); | |
162 | } | |
163 | ||
164 | ||
165 | /** | |
166 | * Since a authorization result is provided within invoke, we don't have to | |
167 | * cancel a long(er) term operation that might have been spawned. | |
168 | * A timeout could be done here. | |
169 | */ | |
170 | static OSStatus mechanismDeactivate(AuthorizationMechanismRef inMechanism) | |
171 | { | |
172 | return 0; | |
173 | } | |
174 | ||
175 | ||
176 | static OSStatus mechanismDestroy(AuthorizationMechanismRef inMechanism) | |
177 | { | |
178 | MechanismRef *mechanism = (MechanismRef *)inMechanism; | |
179 | free(mechanism->mechanismArg); | |
180 | free(mechanism); | |
181 | ||
182 | return 0; | |
183 | } | |
184 | ||
185 | ||
186 | AuthorizationPluginInterface pluginInterface = | |
187 | { | |
188 | kAuthorizationPluginInterfaceVersion, /* UInt32 version; */ | |
189 | pluginDestroy, | |
190 | mechanismCreate, | |
191 | mechanismInvoke, | |
192 | mechanismDeactivate, | |
193 | mechanismDestroy | |
194 | }; | |
195 | ||
196 | ||
197 | /** | |
198 | * Entry point for all plugins. Plugin and the host loading it exchange interfaces. | |
199 | * Normally you'd allocate resources shared amongst all mechanisms here. | |
200 | * When a plugin is created it may not necessarily be used, so be conservative | |
201 | */ | |
202 | OSStatus AuthorizationPluginCreate(const AuthorizationCallbacks *callbacks, | |
203 | AuthorizationPluginRef *outPlugin, | |
204 | const AuthorizationPluginInterface **outPluginInterface) | |
205 | { | |
206 | PluginRef *plugin = calloc(1, sizeof(PluginRef)); | |
207 | ||
208 | plugin->callbacks = callbacks; | |
209 | *outPlugin = (AuthorizationPluginRef) plugin; | |
210 | *outPluginInterface = &pluginInterface; | |
211 | return 0; | |
212 | } |