Fix immediate bug where the idmap can't tell the difference between an entry
[ira/wip.git] / source3 / nsswitch / winbind_nss_aix.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    AIX loadable authentication module, providing identification 
5    routines against Samba winbind/Windows NT Domain
6
7    Copyright (C) Tim Potter 2003
8    Copyright (C) Steve Roylance 2003
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Library General Public
12    License as published by the Free Software Foundation; either
13    version 2 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 Library General Public
21    License along with this library; if not, write to the
22    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23    Boston, MA  02111-1307, USA.   
24 */
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <usersec.h>
29 #include <errno.h>
30
31 #include "winbind_client.h"
32
33 #define MAX_GETPWENT_USERS 250
34 #define MAX_GETGRENT_USERS 250
35
36 static struct passwd *fill_pwent(struct winbindd_pw *pw)
37 {
38         struct passwd *result;
39
40         if (!(result = malloc(sizeof(struct passwd))))
41                 goto out;
42                 
43         ZERO_STRUCTP(result);
44
45         /* User name */
46
47         if ((result->pw_name = malloc(strlen(pw->pw_name) + 1)) == NULL)
48                 goto out;
49         
50         strcpy(result->pw_name, pw->pw_name);
51
52         /* Password */
53
54         if ((result->pw_passwd = malloc(strlen(pw->pw_passwd) + 1)) == NULL)
55                 goto out;
56         
57         strcpy(result->pw_passwd, pw->pw_passwd);
58         
59         /* [ug]id */
60
61         result->pw_uid = pw->pw_uid;
62         result->pw_gid = pw->pw_gid;
63
64         /* GECOS */
65
66         if ((result->pw_gecos = malloc(strlen(pw->pw_gecos) + 1)) == NULL)
67                 goto out;
68
69         strcpy(result->pw_gecos, pw->pw_gecos);
70         
71         /* Home directory */
72         
73         if ((result->pw_dir = malloc(strlen(pw->pw_dir) + 1)) == NULL)
74                 goto out;
75
76         strcpy(result->pw_dir, pw->pw_dir);
77
78         /* Logon shell */
79         
80         if ((result->pw_shell = malloc(strlen(pw->pw_shell) + 1)) == NULL)
81                 goto out;
82         
83         strcpy(result->pw_shell, pw->pw_shell);
84         
85         return result;
86         
87         /* A memory allocation failed, undo succesfull allocations and
88            return NULL */
89
90 out:
91         errno = ENOMEM;
92         SAFE_FREE(result->pw_dir);
93         SAFE_FREE(result->pw_gecos);
94         SAFE_FREE(result->pw_passwd);
95         SAFE_FREE(result->pw_name);
96         SAFE_FREE(result);      
97
98         return NULL;
99 }
100
101 static BOOL next_token(char **ptr,char *buff,char *sep, size_t bufsize)
102 {
103         char *s;
104         BOOL quoted;
105         size_t len=1;
106
107         if (!ptr) return(False);
108
109         s = *ptr;
110
111         /* default to simple separators */
112         if (!sep) sep = " \t\n\r";
113
114         /* find the first non sep char */
115         while (*s && strchr(sep,*s)) s++;
116         
117         /* nothing left? */
118         if (! *s) return(False);
119         
120         /* copy over the token */
121         for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) {
122                 if (*s == '\"') {
123                         quoted = !quoted;
124                 } else {
125                         len++;
126                         *buff++ = *s;
127                 }
128         }
129         
130         *ptr = (*s) ? s+1 : s;  
131         *buff = 0;
132         
133         return(True);
134 }
135
136 static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem)
137 {
138         fstring name;
139         int i;
140         char *tst;
141         struct group *result;
142         
143         if (!(result = malloc(sizeof(struct group))))
144                 goto out;
145
146         ZERO_STRUCTP(result);
147
148         /* Group name */
149
150         if ((result->gr_name = malloc(strlen(gr->gr_name) + 1)) == NULL)
151                 goto out;
152
153         strcpy(result->gr_name, gr->gr_name);
154
155         /* Password */
156
157         if ((result->gr_passwd = malloc(strlen(gr->gr_passwd) + 1)) == NULL)
158                 goto out;
159
160         strcpy(result->gr_passwd, gr->gr_passwd);
161
162         /* gid */
163
164         result->gr_gid = gr->gr_gid;
165
166         /* Group membership */
167
168         if ((gr->num_gr_mem < 0) || !gr_mem) {
169                 gr->num_gr_mem = 0;
170         }
171         
172         if (gr->num_gr_mem == 0) {
173
174                 /* Group is empty */
175                 
176                 *(result->gr_mem) = NULL;
177                 return result;
178         }
179         
180         if ((tst = malloc(((gr->num_gr_mem + 1) * sizeof(char *)))) == NULL)
181                 goto out;
182                 
183         result->gr_mem = (char **)tst;
184
185         /* Start looking at extra data */
186
187         i = 0;
188
189         while(next_token((char **)&gr_mem, name, ",", sizeof(fstring))) {
190         
191                 /* Allocate space for member */
192         
193                 if (((result->gr_mem)[i] = 
194                      malloc(strlen(name) + 1)) == NULL) {
195                         for ( i -= 1; i >= 0; i--)
196                                 SAFE_FREE((result->gr_mem)[i]);
197                         goto out;
198
199                 }        
200         
201                 strcpy((result->gr_mem)[i], name);
202                 i++;
203         }
204
205         /* Terminate list */
206         (result->gr_mem)[i] = NULL;
207
208         return result;
209         
210         /* A memory allocation failed, undo succesfull allocations and
211            return NULL */
212
213 out:
214         errno = ENOMEM;
215         SAFE_FREE(tst);
216         SAFE_FREE(result->gr_passwd);
217         SAFE_FREE(result->gr_name);
218         SAFE_FREE(result);
219
220         return NULL;
221 }
222
223
224
225 static struct group *
226 wb_aix_getgrgid (gid_t gid)
227 {
228 /* take a group id and return a filled struct group */
229         
230         struct winbindd_response response;
231         struct winbindd_request request;
232         NSS_STATUS ret;
233
234         ZERO_STRUCT(response);
235         ZERO_STRUCT(request);
236         
237         request.data.gid = gid;
238
239         ret = winbindd_request(WINBINDD_GETGRGID, &request, &response);
240         
241         if (ret == NSS_STATUS_SUCCESS) {
242                 return fill_grent(&response.data.gr, response.extra_data);
243         } else if (ret == NSS_STATUS_NOTFOUND) {
244                 errno = ENOENT;
245         } else {
246                 errno = EIO;
247         }
248         
249         return NULL;    
250 }
251
252 static struct group *
253 wb_aix_getgrnam (const char *name)
254 {
255 /* take a group name and return a filled struct group */
256
257         struct winbindd_response response;
258         struct winbindd_request request;
259         NSS_STATUS ret;
260         
261         ZERO_STRUCT(response);
262         ZERO_STRUCT(request);
263
264         strncpy(request.data.groupname, name, 
265                 sizeof(request.data.groupname));
266         request.data.groupname
267                 [sizeof(request.data.groupname) - 1] = '\0';
268
269         ret = winbindd_request(WINBINDD_GETGRNAM, &request, &response);
270         
271         if (ret == NSS_STATUS_SUCCESS) {
272                 return fill_grent(&response.data.gr, response.extra_data);
273         } else if (ret == NSS_STATUS_NOTFOUND) {
274                 errno = ENOENT;
275         } else {
276                 errno = EIO;
277         }
278         
279         return NULL;
280 }
281
282 static char *
283 wb_aix_getgrset (const char *user)
284 {
285 /*      take a username and return a string containing a comma-separated list of 
286         group id numbers to which the user belongs */
287         
288         struct winbindd_response response;
289         struct winbindd_request request;
290         NSS_STATUS ret;
291
292         strncpy(request.data.username, user, 
293                 sizeof(request.data.username) - 1);
294         request.data.username
295                 [sizeof(request.data.username) - 1] = '\0';
296
297         ret = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
298         if (ret == NSS_STATUS_SUCCESS ) {
299                 int i, idx = 0;
300                 char *tmpbuf, *result;
301                 
302                 int num_gids = response.data.num_entries;
303                 gid_t *gid_list = (gid_t *)response.extra_data;
304
305                 
306                 /* allocate a space large enough to contruct the string */
307                 if (!(tmpbuf = malloc(num_gids*12))) {
308                         errno = ENOMEM;
309                         return NULL;
310                 }
311                 idx += sprintf(tmpbuf, "%d", gid_list[0]);
312                 for (i = 1; i < num_gids; i++) {
313                         tmpbuf[idx++] = ',';
314                         idx += sprintf(tmpbuf+idx, "%d", gid_list[i]);  
315                 }
316                 tmpbuf[idx] = '\0';
317                 if (!(result = malloc(idx+1))) {
318                         /*      allocate a string the right size to return, but
319                                 if that fails may as well return our working buffer
320                                 because it contains the same thing */
321                         return tmpbuf;
322                 }
323                 strcpy(result, tmpbuf);
324                 SAFE_FREE(tmpbuf);
325                 return result;
326         } else if (ret == NSS_STATUS_NOTFOUND) {
327                 errno = ENOENT;
328         } else {
329                 errno = EIO;
330         }
331         
332         return NULL;
333 }
334
335 static struct passwd *
336 wb_aix_getpwuid (uid_t uid)
337 {
338 /* take a uid and return a filled struct passwd */
339         
340         struct winbindd_response response;
341         struct winbindd_request request;
342         NSS_STATUS ret;
343         
344         ZERO_STRUCT(response);
345         ZERO_STRUCT(request);
346                 
347         request.data.uid = uid;
348         
349         ret = winbindd_request(WINBINDD_GETPWUID, &request, &response);
350                 
351         if (ret == NSS_STATUS_SUCCESS) {
352                 return fill_pwent(&response.data.pw);
353         } else if (ret == NSS_STATUS_NOTFOUND ) {
354                 errno = ENOENT;
355         } else {
356                 errno = EIO;
357         }
358         
359         return NULL;
360 }
361
362 static struct passwd *
363 wb_aix_getpwnam (const char *name)
364 {
365 /* take a username and return a filled struct passwd */
366
367         struct winbindd_response response;
368         struct winbindd_request request;
369         NSS_STATUS ret;
370         
371         ZERO_STRUCT(response);
372         ZERO_STRUCT(request);
373
374         strncpy(request.data.username, name, 
375                 sizeof(request.data.username) - 1);
376         request.data.username
377                 [sizeof(request.data.username) - 1] = '\0';
378
379         ret = winbindd_request(WINBINDD_GETPWNAM, &request, &response);
380         
381         if (ret == NSS_STATUS_SUCCESS ) {
382                 return fill_pwent(&response.data.pw);
383         } else if (ret == NSS_STATUS_NOTFOUND) {
384                 errno = ENOENT;
385         } else {
386                 errno = EIO;    
387         }
388         
389         return NULL;
390 }
391
392 int
393 wb_aix_init (struct secmethod_table *methods)
394 {
395         memset(methods, 0, sizeof(*methods));
396
397         /* identification methods, this is the minimum requried for a
398         working module */
399     
400         methods->method_getgrgid = wb_aix_getgrgid;
401         methods->method_getgrnam = wb_aix_getgrnam;
402         methods->method_getgrset = wb_aix_getgrset;
403         methods->method_getpwnam = wb_aix_getpwnam;
404         methods->method_getpwuid = wb_aix_getpwuid;
405
406         return AUTH_SUCCESS;
407 }