MacOS: aklog auth plugin
[openafs.git] / src / platform / DARWIN / AklogAuthPlugin / aklog.c
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         asprintf(&aklogCmd, "/usr/bin/aklog %s", cell);
61         if (aklogCmd)
62             return system(aklogCmd);
63         else
64             return -1;
65     }
66
67     return system("/usr/bin/aklog");
68 }
69
70 static OSStatus invokeAklog(MechanismRef *mechanism)
71 {
72     AuthorizationContextFlags contextFlags;
73     const AuthorizationValue *value;
74     OSStatus status;
75     uid_t uid = 0;
76     gid_t gid = 0;
77
78     /* a list of context values appears in the Null sample plugin */
79     status = mechanism->plugin->callbacks->GetContextValue(mechanism->engine,
80                                                            kDS1AttrUniqueID,
81                                                            &contextFlags,
82                                                            &value);
83
84     /* This and the group are strings. I don't know why. */
85     if (!status)
86         uid = atoi(value->data);
87     else
88         goto failed;
89
90     status = mechanism->plugin->callbacks->GetContextValue(mechanism->engine,
91                                                            kDS1AttrPrimaryGroupID,
92                                                            &contextFlags,
93                                                            &value);
94     if (!status)
95         gid = atoi(value->data);
96     else
97         goto failed;
98
99     /* in a PAGless universe, this trick works */
100     status = pthread_setugid_np(uid, gid);
101     if (status == 0) {
102         status = do_aklog(mechanism->mechanismArg);
103         pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE);
104         if (status)
105             goto failed;
106     }
107
108     status = 
109         mechanism->plugin->callbacks->SetResult(mechanism->engine,
110                                                 kAuthorizationResultAllow);
111
112     if (!status)
113         return errAuthorizationSuccess;
114
115 failed:
116     return errAuthorizationInternal;
117 }
118
119 static OSStatus pluginDestroy(AuthorizationPluginRef inPlugin)
120 {
121     /* seems to not be called. can't do cleanup? */
122     PluginRef *plugin = (PluginRef *)inPlugin;
123     free(plugin);
124     return 0;
125 }
126
127 static OSStatus mechanismCreate(AuthorizationPluginRef inPlugin,
128         AuthorizationEngineRef inEngine,
129         AuthorizationMechanismId mechanismId,
130         AuthorizationMechanismRef *outMechanism)
131 {
132     const PluginRef *plugin = (const PluginRef *)inPlugin;
133
134     MechanismRef *mechanism = calloc(1, sizeof(MechanismRef));
135
136     mechanism->plugin = plugin;
137     mechanism->engine = inEngine;
138     /*
139      * consider supporting a variant which backgrounds aklog and returns
140      * success where tokens are desired but not critical.
141      */
142     mechanism->mechanismArg = strdup(mechanismId);
143
144     *outMechanism = mechanism;
145
146     return 0;
147 }
148
149
150 static OSStatus mechanismInvoke(AuthorizationMechanismRef inMechanism)
151 {
152     MechanismRef *mechanism = (MechanismRef *)inMechanism;
153     OSStatus status;
154
155     status = invokeAklog(mechanism);
156     if (status)
157         return errAuthorizationInternal;
158
159     /* mark success */
160     return mechanism->plugin->callbacks->SetResult(mechanism->engine, kAuthorizationResultAllow);
161 }
162
163
164 /**
165  *   Since a authorization result is provided within invoke, we don't have to 
166  *   cancel a long(er) term operation that might have been spawned.
167  *   A timeout could be done here.
168  */
169 static OSStatus mechanismDeactivate(AuthorizationMechanismRef inMechanism)
170 {
171     return 0;
172 }
173
174
175 static OSStatus mechanismDestroy(AuthorizationMechanismRef inMechanism)
176 {
177     MechanismRef *mechanism = (MechanismRef *)inMechanism;
178     free(mechanism->mechanismArg);
179     free(mechanism);
180
181     return 0;
182 }
183
184
185 AuthorizationPluginInterface pluginInterface =
186 {
187     kAuthorizationPluginInterfaceVersion, /* UInt32 version; */
188     pluginDestroy,
189     mechanismCreate,
190     mechanismInvoke,
191     mechanismDeactivate,
192     mechanismDestroy
193 };
194
195
196 /**
197  *  Entry point for all plugins.  Plugin and the host loading it exchange interfaces.
198  *  Normally you'd allocate resources shared amongst all mechanisms here.
199  *  When a plugin is created it may not necessarily be used, so be conservative
200  */
201 OSStatus AuthorizationPluginCreate(const AuthorizationCallbacks *callbacks,
202     AuthorizationPluginRef *outPlugin,
203     const AuthorizationPluginInterface **outPluginInterface)
204 {
205     PluginRef *plugin = calloc(1, sizeof(PluginRef));
206
207     plugin->callbacks = callbacks;
208     *outPlugin = (AuthorizationPluginRef) plugin;
209     *outPluginInterface = &pluginInterface;
210     return 0;
211 }