libreplace: Fix the build on Solaris
[sfrench/samba-autobuild/.git] / nsswitch / libwbclient / wbclient.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind client API
5
6    Copyright (C) Gerald (Jerry) Carter 2007
7    Copyright (C) Matthew Newton 2015
8
9
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 3 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Library General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /* Required Headers */
25
26 #include "replace.h"
27 #include "libwbclient.h"
28
29 /* From wb_common.c */
30
31 struct winbindd_context;
32
33 NSS_STATUS winbindd_request_response(struct winbindd_context *wbctx,
34                                      int req_type,
35                                      struct winbindd_request *request,
36                                      struct winbindd_response *response);
37 NSS_STATUS winbindd_priv_request_response(struct winbindd_context *wbctx,
38                                           int req_type,
39                                           struct winbindd_request *request,
40                                           struct winbindd_response *response);
41 struct winbindd_context *winbindd_ctx_create(void);
42 void winbindd_ctx_free(struct winbindd_context *ctx);
43
44 /* Global context used for non-Ctx functions */
45
46 static struct wbcContext wbcGlobalCtx = {
47         .winbindd_ctx = NULL,
48         .pw_cache_size = 0,
49         .pw_cache_idx = 0,
50         .gr_cache_size = 0,
51         .gr_cache_idx = 0
52 };
53
54 /*
55  result == NSS_STATUS_UNAVAIL: winbind not around
56  result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
57
58  Due to a bad API NSS_STATUS_NOTFOUND is returned both when winbind_off
59  and when winbind return WINBINDD_ERROR. So the semantics of this
60  routine depends on winbind_on. Grepping for winbind_off I just
61  found 3 places where winbind is turned off, and this does not conflict
62  (as far as I have seen) with the callers of is_trusted_domains.
63
64  --Volker
65 */
66
67 static wbcErr wbcRequestResponseInt(
68         struct winbindd_context *wbctx,
69         int cmd,
70         struct winbindd_request *request,
71         struct winbindd_response *response,
72         NSS_STATUS (*fn)(struct winbindd_context *wbctx, int req_type,
73                          struct winbindd_request *request,
74                          struct winbindd_response *response))
75 {
76         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
77         NSS_STATUS nss_status;
78
79         /* for some calls the request and/or response can be NULL */
80
81         nss_status = fn(wbctx, cmd, request, response);
82
83         switch (nss_status) {
84         case NSS_STATUS_SUCCESS:
85                 wbc_status = WBC_ERR_SUCCESS;
86                 break;
87         case NSS_STATUS_UNAVAIL:
88                 wbc_status = WBC_ERR_WINBIND_NOT_AVAILABLE;
89                 break;
90         case NSS_STATUS_NOTFOUND:
91                 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
92                 break;
93         default:
94                 wbc_status = WBC_ERR_NSS_ERROR;
95                 break;
96         }
97
98         return wbc_status;
99 }
100
101 /**
102  * @brief Wrapper around Winbind's send/receive API call
103  *
104  * @param ctx       Context
105  * @param cmd       Winbind command operation to perform
106  * @param request   Send structure
107  * @param response  Receive structure
108  *
109  * @return #wbcErr
110  */
111 wbcErr wbcRequestResponse(struct wbcContext *ctx, int cmd,
112                           struct winbindd_request *request,
113                           struct winbindd_response *response)
114 {
115         struct winbindd_context *wbctx = NULL;
116
117         if (ctx) {
118                 wbctx = ctx->winbindd_ctx;
119         }
120
121         return wbcRequestResponseInt(wbctx, cmd, request, response,
122                                      winbindd_request_response);
123 }
124
125 wbcErr wbcRequestResponsePriv(struct wbcContext *ctx, int cmd,
126                               struct winbindd_request *request,
127                               struct winbindd_response *response)
128 {
129         struct winbindd_context *wbctx = NULL;
130
131         if (ctx) {
132                 wbctx = ctx->winbindd_ctx;
133         }
134
135         return wbcRequestResponseInt(wbctx, cmd, request, response,
136                                      winbindd_priv_request_response);
137 }
138
139 /** @brief Translate an error value into a string
140  *
141  * @param error
142  *
143  * @return a pointer to a static string
144  **/
145 const char *wbcErrorString(wbcErr error)
146 {
147         switch (error) {
148         case WBC_ERR_SUCCESS:
149                 return "WBC_ERR_SUCCESS";
150         case WBC_ERR_NOT_IMPLEMENTED:
151                 return "WBC_ERR_NOT_IMPLEMENTED";
152         case WBC_ERR_UNKNOWN_FAILURE:
153                 return "WBC_ERR_UNKNOWN_FAILURE";
154         case WBC_ERR_NO_MEMORY:
155                 return "WBC_ERR_NO_MEMORY";
156         case WBC_ERR_INVALID_SID:
157                 return "WBC_ERR_INVALID_SID";
158         case WBC_ERR_INVALID_PARAM:
159                 return "WBC_ERR_INVALID_PARAM";
160         case WBC_ERR_WINBIND_NOT_AVAILABLE:
161                 return "WBC_ERR_WINBIND_NOT_AVAILABLE";
162         case WBC_ERR_DOMAIN_NOT_FOUND:
163                 return "WBC_ERR_DOMAIN_NOT_FOUND";
164         case WBC_ERR_INVALID_RESPONSE:
165                 return "WBC_ERR_INVALID_RESPONSE";
166         case WBC_ERR_NSS_ERROR:
167                 return "WBC_ERR_NSS_ERROR";
168         case WBC_ERR_UNKNOWN_USER:
169                 return "WBC_ERR_UNKNOWN_USER";
170         case WBC_ERR_UNKNOWN_GROUP:
171                 return "WBC_ERR_UNKNOWN_GROUP";
172         case WBC_ERR_AUTH_ERROR:
173                 return "WBC_ERR_AUTH_ERROR";
174         case WBC_ERR_PWD_CHANGE_FAILED:
175                 return "WBC_ERR_PWD_CHANGE_FAILED";
176         }
177
178         return "unknown wbcErr value";
179 }
180
181 #define WBC_MAGIC (0x7a2b0e1e)
182 #define WBC_MAGIC_FREE (0x875634fe)
183
184 struct wbcMemPrefix {
185         uint32_t magic;
186         void (*destructor)(void *ptr);
187 };
188
189 static size_t wbcPrefixLen(void)
190 {
191         size_t result = sizeof(struct wbcMemPrefix);
192         return (result + 15) & ~15;
193 }
194
195 static struct wbcMemPrefix *wbcMemToPrefix(void *ptr)
196 {
197         return (struct wbcMemPrefix *)(((char *)ptr) - wbcPrefixLen());
198 }
199
200 void *wbcAllocateMemory(size_t nelem, size_t elsize,
201                         void (*destructor)(void *ptr))
202 {
203         struct wbcMemPrefix *result;
204
205         if (nelem >= (2<<24)/elsize) {
206                 /* basic protection against integer wrap */
207                 return NULL;
208         }
209
210         result = (struct wbcMemPrefix *)calloc(
211                 1, nelem*elsize + wbcPrefixLen());
212         if (result == NULL) {
213                 return NULL;
214         }
215         result->magic = WBC_MAGIC;
216         result->destructor = destructor;
217         return ((char *)result) + wbcPrefixLen();
218 }
219
220 /* Free library allocated memory */
221 void wbcFreeMemory(void *p)
222 {
223         struct wbcMemPrefix *wbcMem;
224
225         if (p == NULL) {
226                 return;
227         }
228         wbcMem = wbcMemToPrefix(p);
229         if (wbcMem->magic != WBC_MAGIC) {
230                 return;
231         }
232
233         /* paranoid check to ensure we don't double free */
234         wbcMem->magic = WBC_MAGIC_FREE;
235
236         if (wbcMem->destructor != NULL) {
237                 wbcMem->destructor(p);
238         }
239         free(wbcMem);
240         return;
241 }
242
243 char *wbcStrDup(const char *str)
244 {
245         char *result;
246         size_t len;
247
248         len = strlen(str);
249         result = (char *)wbcAllocateMemory(len+1, sizeof(char), NULL);
250         if (result == NULL) {
251                 return NULL;
252         }
253         memcpy(result, str, len+1);
254         return result;
255 }
256
257 static void wbcStringArrayDestructor(void *ptr)
258 {
259         char **p = (char **)ptr;
260         while (*p != NULL) {
261                 free(*p);
262                 p += 1;
263         }
264 }
265
266 const char **wbcAllocateStringArray(int num_strings)
267 {
268         return (const char **)wbcAllocateMemory(
269                 num_strings + 1, sizeof(const char *),
270                 wbcStringArrayDestructor);
271 }
272
273 wbcErr wbcLibraryDetails(struct wbcLibraryDetails **_details)
274 {
275         struct wbcLibraryDetails *info;
276
277         info = (struct wbcLibraryDetails *)wbcAllocateMemory(
278                 1, sizeof(struct wbcLibraryDetails), NULL);
279
280         if (info == NULL) {
281                 return WBC_ERR_NO_MEMORY;
282         }
283
284         info->major_version = WBCLIENT_MAJOR_VERSION;
285         info->minor_version = WBCLIENT_MINOR_VERSION;
286         info->vendor_version = WBCLIENT_VENDOR_VERSION;
287
288         *_details = info;
289         return WBC_ERR_SUCCESS;
290 }
291
292 /* Context handling functions */
293
294 static void wbcContextDestructor(void *ptr)
295 {
296         struct wbcContext *ctx = (struct wbcContext *)ptr;
297
298         winbindd_ctx_free(ctx->winbindd_ctx);
299 }
300
301 struct wbcContext *wbcCtxCreate(void)
302 {
303         struct wbcContext *ctx;
304         struct winbindd_context *wbctx;
305
306         ctx = (struct wbcContext *)wbcAllocateMemory(
307                 1, sizeof(struct wbcContext), wbcContextDestructor);
308
309         if (!ctx) {
310                 return NULL;
311         }
312
313         wbctx = winbindd_ctx_create();
314
315         if (!wbctx) {
316                 wbcFreeMemory(ctx);
317                 return NULL;
318         }
319
320         ctx->winbindd_ctx = wbctx;
321
322         return ctx;
323 }
324
325 void wbcCtxFree(struct wbcContext *ctx)
326 {
327         wbcFreeMemory(ctx);
328 }
329
330 struct wbcContext *wbcGetGlobalCtx(void)
331 {
332         return &wbcGlobalCtx;
333 }