libndr: Avoid assigning duplicate versions to symbols
[amitay/samba.git] / nsswitch / winbind_nss_aix.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    AIX loadable authentication module, providing identification and
5    authentication routines against Samba winbind/Windows NT Domain
6
7    Copyright (C) Tim Potter 2003
8    Copyright (C) Steve Roylance 2003
9    Copyright (C) Andrew Tridgell 2003-2004
10
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Lesser General Public
13    License as published by the Free Software Foundation; either
14    version 3 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Library General Public License for more details.
20
21    You should have received a copy of the GNU Lesser General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 /*
26
27   To install this module copy nsswitch/WINBIND to /usr/lib/security and add
28   "WINBIND" in /usr/lib/security/methods.cfg and /etc/security/user
29
30   Note that this module also provides authentication and password
31   changing routines, so you do not need to install the winbind PAM
32   module.
33
34   see
35   http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/kernextc/sec_load_mod.htm
36   for some information in the interface that this module implements
37
38   Many thanks to Julianne Haugh for explaining some of the finer
39   details of this interface.
40
41   To debug this module use uess_test.c (which you can get from tridge)
42   or set "options=debug" in /usr/lib/security/methods.cfg
43
44 */
45
46 #include "winbind_client.h"
47 #include <usersec.h>
48
49 /* enable this to log which entry points have not been
50   completed yet */
51 #define LOG_UNIMPLEMENTED_CALLS 0
52
53
54 #define WB_AIX_ENCODED '_'
55
56 static int debug_enabled;
57
58
59 static void logit(const char *format, ...)
60 {
61         va_list ap;
62         FILE *f;
63         if (!debug_enabled) {
64                 return;
65         }
66         f = fopen("/tmp/WINBIND_DEBUG.log", "a");
67         if (!f) return;
68         va_start(ap, format);
69         vfprintf(f, format, ap);
70         va_end(ap);
71         fclose(f);
72 }
73
74
75 #define HANDLE_ERRORS(ret) do { \
76         if ((ret) == NSS_STATUS_NOTFOUND) { \
77                 errno = ENOENT; \
78                 return NULL; \
79         } else if ((ret) != NSS_STATUS_SUCCESS) { \
80                 errno = EIO; \
81                 return NULL; \
82         } \
83 } while (0)
84
85 #define STRCPY_RET(dest, src) \
86 do { \
87         if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return -1; } \
88         strncpy(dest, src, sizeof(dest)); \
89         dest[sizeof(dest)-1] = '\0'; \
90 } while (0)
91
92 #define STRCPY_RETNULL(dest, src) \
93 do { \
94         if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return NULL; } \
95         strncpy(dest, src, sizeof(dest)); \
96         dest[sizeof(dest)-1] = '\0'; \
97 } while (0)
98
99
100 /* free a passwd structure */
101 static void free_pwd(struct passwd *pwd)
102 {
103         free(pwd->pw_name);
104         free(pwd->pw_passwd);
105         free(pwd->pw_gecos);
106         free(pwd->pw_dir);
107         free(pwd->pw_shell);
108         free(pwd);
109 }
110
111 /* free a group structure */
112 static void free_grp(struct group *grp)
113 {
114         int i;
115
116         free(grp->gr_name);
117         free(grp->gr_passwd);
118
119         if (!grp->gr_mem) {
120                 free(grp);
121                 return;
122         }
123
124         for (i=0; grp->gr_mem[i]; i++) {
125                 free(grp->gr_mem[i]);
126         }
127
128         free(grp->gr_mem);
129         free(grp);
130 }
131
132
133 /* replace commas with nulls, and null terminate */
134 static void replace_commas(char *s)
135 {
136         char *p, *p0=s;
137         for (p=strchr(s, ','); p; p = strchr(p+1, ',')) {
138                 *p=0;
139                 p0 = p+1;
140         }
141
142         p0[strlen(p0)+1] = 0;
143 }
144
145
146 /* the decode_*() routines are used to cope with the fact that AIX 5.2
147    and below cannot handle user or group names longer than 8
148    characters in some interfaces. We use the normalize method to
149    provide a mapping to a username that fits, by using the form '_UID'
150    or '_GID'.
151
152    this only works if you can guarantee that the WB_AIX_ENCODED char
153    is not used as the first char of any other username
154 */
155 static unsigned decode_id(const char *name)
156 {
157         unsigned id;
158         sscanf(name+1, "%u", &id);
159         return id;
160 }
161
162 static struct passwd *wb_aix_getpwuid(uid_t uid);
163
164 static char *decode_user(const char *name)
165 {
166         struct passwd *pwd;
167         unsigned id;
168         char *ret;
169
170         sscanf(name+1, "%u", &id);
171         pwd = wb_aix_getpwuid(id);
172         if (!pwd) {
173                 return NULL;
174         }
175         ret = strdup(pwd->pw_name);
176
177         free_pwd(pwd);
178
179         logit("decoded '%s' -> '%s'\n", name, ret);
180
181         return ret;
182 }
183
184
185 /*
186   fill a struct passwd from a winbindd_pw struct, allocating as a single block
187 */
188 static struct passwd *fill_pwent(struct winbindd_pw *pw)
189 {
190         struct passwd *result;
191
192         result = calloc(1, sizeof(struct passwd));
193         if (!result) {
194                 errno = ENOMEM;
195                 return NULL;
196         }
197
198         result->pw_uid = pw->pw_uid;
199         result->pw_gid = pw->pw_gid;
200         result->pw_name   = strdup(pw->pw_name);
201         result->pw_passwd = strdup(pw->pw_passwd);
202         result->pw_gecos  = strdup(pw->pw_gecos);
203         result->pw_dir    = strdup(pw->pw_dir);
204         result->pw_shell  = strdup(pw->pw_shell);
205
206         return result;
207 }
208
209
210 /*
211   fill a struct group from a winbindd_pw struct, allocating as a single block
212 */
213 static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem)
214 {
215         int i;
216         struct group *result;
217         char *p, *name;
218
219         result = calloc(1, sizeof(struct group));
220         if (!result) {
221                 errno = ENOMEM;
222                 return NULL;
223         }
224
225         result->gr_gid = gr->gr_gid;
226
227         result->gr_name   = strdup(gr->gr_name);
228         result->gr_passwd = strdup(gr->gr_passwd);
229
230         /* Group membership */
231         if ((gr->num_gr_mem < 0) || !gr_mem) {
232                 gr->num_gr_mem = 0;
233         }
234
235         if (gr->num_gr_mem == 0) {
236                 /* Group is empty */
237                 return result;
238         }
239
240         result->gr_mem = (char **)malloc(sizeof(char *) * (gr->num_gr_mem+1));
241         if (!result->gr_mem) {
242                 free(result->gr_name);
243                 free(result->gr_passwd);
244                 free(result);
245                 errno = ENOMEM;
246                 return NULL;
247         }
248
249         /* Start looking at extra data */
250         i=0;
251         for (name = strtok_r(gr_mem, ",", &p);
252              name;
253              name = strtok_r(NULL, ",", &p)) {
254                 if (i == gr->num_gr_mem) {
255                         break;
256                 }
257                 result->gr_mem[i] = strdup(name);
258                 i++;
259         }
260
261         /* Terminate list */
262         result->gr_mem[i] = NULL;
263
264         return result;
265 }
266
267
268
269 /* take a group id and return a filled struct group */
270 static struct group *wb_aix_getgrgid(gid_t gid)
271 {
272         struct winbindd_request request = {
273                 .wb_flags = WBFLAG_FROM_NSS,
274         };
275         struct winbindd_response response = {
276                 .length = 0,
277         };
278         struct group *grp;
279         NSS_STATUS ret;
280
281         logit("getgrgid %d\n", gid);
282
283         request.data.gid = gid;
284
285         ret = winbindd_request_response(NULL, WINBINDD_GETGRGID,
286                                         &request, &response);
287
288         logit("getgrgid ret=%d\n", ret);
289
290         HANDLE_ERRORS(ret);
291
292         grp = fill_grent(&response.data.gr, response.extra_data.data);
293
294         winbindd_free_response(&response);
295
296         return grp;
297 }
298
299 /* take a group name and return a filled struct group */
300 static struct group *wb_aix_getgrnam(const char *name)
301 {
302         struct winbindd_request request = {
303                 .wb_flags = WBFLAG_FROM_NSS,
304         };
305         struct winbindd_response response = {
306                 .length = 0,
307         };
308         NSS_STATUS ret;
309         struct group *grp;
310
311         if (*name == WB_AIX_ENCODED) {
312                 return wb_aix_getgrgid(decode_id(name));
313         }
314
315         logit("getgrnam '%s'\n", name);
316
317         STRCPY_RETNULL(request.data.groupname, name);
318
319         ret = winbindd_request_response(NULL, WINBINDD_GETGRNAM,
320                                         &request, &response);
321
322         HANDLE_ERRORS(ret);
323
324         grp = fill_grent(&response.data.gr, response.extra_data.data);
325
326         winbindd_free_response(&response);
327
328         return grp;
329 }
330
331
332 /* this call doesn't have to fill in the gr_mem, but we do anyway
333    for simplicity */
334 static struct group *wb_aix_getgracct(void *id, int type)
335 {
336         if (type == 1) {
337                 return wb_aix_getgrnam((char *)id);
338         }
339         if (type == 0) {
340                 return wb_aix_getgrgid(*(int *)id);
341         }
342         errno = EINVAL;
343         return NULL;
344 }
345
346
347 /* take a username and return a string containing a comma-separated
348    list of group id numbers to which the user belongs */
349 static char *wb_aix_getgrset(char *user)
350 {
351         struct winbindd_request request = {
352                 .wb_flags = WBFLAG_FROM_NSS,
353         };
354         struct winbindd_response response = {
355                 .length = 0,
356         };
357         NSS_STATUS ret;
358         int i, idx;
359         char *tmpbuf;
360         int num_gids;
361         gid_t *gid_list;
362         char *r_user = user;
363
364         if (*user == WB_AIX_ENCODED) {
365                 r_user = decode_user(r_user);
366                 if (!r_user) {
367                         errno = ENOENT;
368                         return NULL;
369                 }
370         }
371
372         logit("getgrset '%s'\n", r_user);
373
374         STRCPY_RETNULL(request.data.username, r_user);
375
376         if (*user == WB_AIX_ENCODED) {
377                 free(r_user);
378         }
379
380         ret = winbindd_request_response(NULL, WINBINDD_GETGROUPS,
381                                         &request, &response);
382
383         HANDLE_ERRORS(ret);
384
385         num_gids = response.data.num_entries;
386         gid_list = (gid_t *)response.extra_data.data;
387
388         /* allocate a space large enough to contruct the string */
389         tmpbuf = malloc(num_gids*12);
390         if (!tmpbuf) {
391                 return NULL;
392         }
393
394         for (idx=i=0; i < num_gids-1; i++) {
395                 idx += sprintf(tmpbuf+idx, "%u,", gid_list[i]);
396         }
397         idx += sprintf(tmpbuf+idx, "%u", gid_list[i]);
398
399         winbindd_free_response(&response);
400
401         return tmpbuf;
402 }
403
404
405 /* take a uid and return a filled struct passwd */
406 static struct passwd *wb_aix_getpwuid(uid_t uid)
407 {
408         struct winbindd_request request = {
409                 .wb_flags = WBFLAG_FROM_NSS,
410         };
411         struct winbindd_response response = {
412                 .length = 0,
413         };
414         NSS_STATUS ret;
415         struct passwd *pwd;
416
417         logit("getpwuid '%d'\n", uid);
418
419         request.data.uid = uid;
420
421         ret = winbindd_request_response(NULL, WINBINDD_GETPWUID,
422                                         &request, &response);
423
424         HANDLE_ERRORS(ret);
425
426         pwd = fill_pwent(&response.data.pw);
427
428         winbindd_free_response(&response);
429
430         logit("getpwuid gave ptr %p\n", pwd);
431
432         return pwd;
433 }
434
435
436 /* take a username and return a filled struct passwd */
437 static struct passwd *wb_aix_getpwnam(const char *name)
438 {
439         struct winbindd_request request = {
440                 .wb_flags = WBFLAG_FROM_NSS,
441         };
442         struct winbindd_response response = {
443                 .length = 0,
444         };
445         NSS_STATUS ret;
446         struct passwd *pwd;
447
448         if (*name == WB_AIX_ENCODED) {
449                 return wb_aix_getpwuid(decode_id(name));
450         }
451
452         logit("getpwnam '%s'\n", name);
453
454         STRCPY_RETNULL(request.data.username, name);
455
456         ret = winbindd_request_response(NULL, WINBINDD_GETPWNAM,
457                                         &request, &response);
458
459         HANDLE_ERRORS(ret);
460
461         pwd = fill_pwent(&response.data.pw);
462
463         winbindd_free_response(&response);
464
465         logit("getpwnam gave ptr %p\n", pwd);
466
467         return pwd;
468 }
469
470 /*
471   list users
472 */
473 static int wb_aix_lsuser(char *attributes[], attrval_t results[], int size)
474 {
475         NSS_STATUS ret;
476         struct winbindd_request request = {
477                 .wb_flags = WBFLAG_FROM_NSS,
478         };
479         struct winbindd_response response = {
480                 .length = 0,
481         };
482         int len;
483         char *s;
484
485         if (size != 1 || strcmp(attributes[0], S_USERS) != 0) {
486                 logit("invalid lsuser op\n");
487                 errno = EINVAL;
488                 return -1;
489         }
490
491         ret = winbindd_request_response(NULL, WINBINDD_LIST_USERS,
492                                         &request, &response);
493         if (ret != 0) {
494                 errno = EINVAL;
495                 return -1;
496         }
497
498         len = strlen(response.extra_data.data);
499
500         s = malloc(len+2);
501         if (!s) {
502                 winbindd_free_response(&response);
503                 errno = ENOMEM;
504                 return -1;
505         }
506
507         memcpy(s, response.extra_data.data, len+1);
508
509         replace_commas(s);
510
511         results[0].attr_un.au_char = s;
512         results[0].attr_flag = 0;
513
514         winbindd_free_response(&response);
515
516         return 0;
517 }
518
519
520 /*
521   list groups
522 */
523 static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size)
524 {
525         NSS_STATUS ret;
526         struct winbindd_request request = {
527                 .wb_flags = WBFLAG_FROM_NSS,
528         };
529         struct winbindd_response response = {
530                 .length = 0,
531         };
532         int len;
533         char *s;
534
535         if (size != 1 || strcmp(attributes[0], S_GROUPS) != 0) {
536                 logit("invalid lsgroup op\n");
537                 errno = EINVAL;
538                 return -1;
539         }
540
541         ret = winbindd_request_response(NULL, WINBINDD_LIST_GROUPS,
542                                         &request, &response);
543         if (ret != 0) {
544                 errno = EINVAL;
545                 return -1;
546         }
547
548         len = strlen(response.extra_data.data);
549
550         s = malloc(len+2);
551         if (!s) {
552                 winbindd_free_response(&response);
553                 errno = ENOMEM;
554                 return -1;
555         }
556
557         memcpy(s, response.extra_data.data, len+1);
558
559         replace_commas(s);
560
561         results[0].attr_un.au_char = s;
562         results[0].attr_flag = 0;
563
564         winbindd_free_response(&response);
565
566         return 0;
567 }
568
569
570 static attrval_t pwd_to_group(struct passwd *pwd)
571 {
572         attrval_t r = {
573                 .attr_flag = EINVAL,
574         };
575         struct group *grp = wb_aix_getgrgid(pwd->pw_gid);
576
577         if (grp != NULL) {
578                 r.attr_flag = 0;
579                 r.attr_un.au_char = strdup(grp->gr_name);
580                 free_grp(grp);
581         }
582
583         return r;
584 }
585
586 static attrval_t pwd_to_groupsids(struct passwd *pwd)
587 {
588         attrval_t r = {
589                 .attr_flag = EINVAL,
590         };
591         char *s, *p;
592         size_t mlen;
593
594         if ( (s = wb_aix_getgrset(pwd->pw_name)) == NULL ) {
595                 r.attr_flag = EINVAL;
596                 return r;
597         }
598
599         mlen = strlen(s)+2;
600         if ( (p = malloc(mlen)) == NULL ) {
601                 r.attr_flag = ENOMEM;
602                 return r;
603         }
604
605         strncpy(p, s, mlen);
606         p[mlen-1] = '\0';
607         replace_commas(p);
608         free(s);
609
610         r.attr_flag = 0;
611         r.attr_un.au_char = p;
612
613         return r;
614 }
615
616 static attrval_t pwd_to_sid(struct passwd *pwd)
617 {
618         char buf[(1 /* U/G */ + 10 /* 2^32 */ + 1 /* \n */) + 1] = { 0, };
619         int len;
620         struct winbindd_request request;
621         struct winbindd_response response;
622         NSS_STATUS result;
623         attrval_t r = {
624                 .attr_flag = ENOENT,
625         };
626
627         len = snprintf(buf, sizeof(buf),
628                        "U%"PRIu32"\n",
629                        (uint32_t)pwd->pw_uid);
630         if (len >= sizeof(buf)) {
631                 r = (attrval_t) {
632                         .attr_flag = EINVAL,
633                 };
634                 return r;
635         }
636
637         request = (struct winbindd_request) {
638                 .wb_flags = WBFLAG_FROM_NSS,
639                 .extra_data.data = buf,
640                 .extra_len = strlen(buf)+1,
641         };
642         response = (struct winbindd_response) {
643                 .length = 0,
644         };
645
646         result = winbindd_request_response(NULL, WINBINDD_XIDS_TO_SIDS,
647                                            &request, &response);
648         if (result == NSS_STATUS_SUCCESS) {
649                 r.attr_flag = 0;
650                 r.attr_un.au_char = strdup(response.data.sid.sid);
651         }
652
653         return r;
654 }
655
656 static int wb_aix_user_attrib(const char *key, char *attributes[],
657                               attrval_t results[], int size)
658 {
659         struct passwd *pwd;
660         int i;
661
662         pwd = wb_aix_getpwnam(key);
663         if (!pwd) {
664                 errno = ENOENT;
665                 return -1;
666         }
667
668         for (i=0;i<size;i++) {
669                 results[i] = (attrval_t) {
670                         .attr_flag = 0,
671                 };
672
673                 if (strcmp(attributes[i], S_ID) == 0) {
674                         results[i].attr_un.au_int = pwd->pw_uid;
675 #ifdef _AIXVERSION_530
676                 } else if (strcmp(attributes[i], S_PGID) == 0) {
677                         results[i].attr_un.au_int = pwd->pw_gid;
678 #endif
679                 } else if (strcmp(attributes[i], S_PWD) == 0) {
680                         results[i].attr_un.au_char = strdup(pwd->pw_passwd);
681                 } else if (strcmp(attributes[i], S_HOME) == 0) {
682                         results[i].attr_un.au_char = strdup(pwd->pw_dir);
683                 } else if (strcmp(attributes[i], S_SHELL) == 0) {
684                         results[i].attr_un.au_char = strdup(pwd->pw_shell);
685                 } else if (strcmp(attributes[i], S_REGISTRY) == 0) {
686                         results[i].attr_un.au_char = strdup("WINBIND");
687                 } else if (strcmp(attributes[i], S_GECOS) == 0) {
688                         results[i].attr_un.au_char = strdup(pwd->pw_gecos);
689                 } else if (strcmp(attributes[i], S_PGRP) == 0) {
690                         results[i] = pwd_to_group(pwd);
691                 } else if (strcmp(attributes[i], S_GROUPS) == 0) {
692                         results[i] = pwd_to_groupsids(pwd);
693                 } else if (strcmp(attributes[i], S_GROUPSIDS) == 0) {
694                         results[i] = pwd_to_groupsids(pwd);
695                 } else if (strcmp(attributes[i], "SID") == 0) {
696                         results[i] = pwd_to_sid(pwd);
697                 } else {
698                         logit("Unknown user attribute '%s'\n", attributes[i]);
699                         results[i].attr_flag = EINVAL;
700                 }
701         }
702
703         free_pwd(pwd);
704
705         return 0;
706 }
707
708 static int wb_aix_group_attrib(const char *key, char *attributes[],
709                                attrval_t results[], int size)
710 {
711         struct group *grp;
712         int i;
713
714         grp = wb_aix_getgrnam(key);
715         if (!grp) {
716                 errno = ENOENT;
717                 return -1;
718         }
719
720         for (i=0;i<size;i++) {
721                 results[i].attr_flag = 0;
722
723                 if (strcmp(attributes[i], S_PWD) == 0) {
724                         results[i].attr_un.au_char = strdup(grp->gr_passwd);
725                 } else if (strcmp(attributes[i], S_ID) == 0) {
726                         results[i].attr_un.au_int = grp->gr_gid;
727                 } else {
728                         logit("Unknown group attribute '%s'\n", attributes[i]);
729                         results[i].attr_flag = EINVAL;
730                 }
731         }
732
733         free_grp(grp);
734
735         return 0;
736 }
737
738
739 /*
740   called for user/group enumerations
741 */
742 static int wb_aix_getentry(char *key, char *table, char *attributes[],
743                            attrval_t results[], int size)
744 {
745         logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n",
746               key, table, size, attributes[0]);
747
748         if (strcmp(key, "ALL") == 0 &&
749             strcmp(table, "user") == 0) {
750                 return wb_aix_lsuser(attributes, results, size);
751         }
752
753         if (strcmp(key, "ALL") == 0 &&
754             strcmp(table, "group") == 0) {
755                 return wb_aix_lsgroup(attributes, results, size);
756         }
757
758         if (strcmp(table, "user") == 0) {
759                 return wb_aix_user_attrib(key, attributes, results, size);
760         }
761
762         if (strcmp(table, "group") == 0) {
763                 return wb_aix_group_attrib(key, attributes, results, size);
764         }
765
766         logit("Unknown getentry operation key='%s' table='%s'\n", key, table);
767
768         errno = ENOSYS;
769         return -1;
770 }
771
772
773
774 /*
775   called to start the backend
776 */
777 static void *wb_aix_open(const char *name, const char *domain, int mode, char *options)
778 {
779         if (strstr(options, "debug")) {
780                 debug_enabled = 1;
781         }
782         logit("open name='%s' mode=%d domain='%s' options='%s'\n", name, domain,
783               mode, options);
784         return NULL;
785 }
786
787 static void wb_aix_close(void *token)
788 {
789         logit("close\n");
790         return;
791 }
792
793 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
794 /*
795    return a list of additional attributes supported by the backend
796 */
797 static attrlist_t **wb_aix_attrlist(void)
798 {
799         /* pretty confusing but we are allocating the array of pointers
800            and the structures we'll be pointing to all at once.  So
801            you need N+1 pointers and N structures. */
802
803         attrlist_t **ret = NULL;
804         attrlist_t *offset = NULL;
805         int i;
806         int n;
807         size_t size;
808
809         struct attr_types {
810                 const char *name;
811                 int flags;
812                 int type;
813         } attr_list[] = {
814                 /* user attributes */
815                 {S_ID,          AL_USERATTR,    SEC_INT},
816                 {S_PGRP,        AL_USERATTR,    SEC_CHAR},
817                 {S_HOME,        AL_USERATTR,    SEC_CHAR},
818                 {S_SHELL,       AL_USERATTR,    SEC_CHAR},
819 #ifdef _AIXVERSION_530
820                 {S_PGID,        AL_USERATTR,    SEC_INT},
821 #endif
822                 {S_GECOS,       AL_USERATTR,    SEC_CHAR},
823                 {S_SHELL,       AL_USERATTR,    SEC_CHAR},
824                 {S_PGRP,        AL_USERATTR,    SEC_CHAR},
825                 {S_GROUPS,      AL_USERATTR,    SEC_LIST},
826                 {S_GROUPSIDS,   AL_USERATTR,    SEC_LIST},
827                 {"SID",         AL_USERATTR,    SEC_CHAR},
828
829                 /* group attributes */
830                 {S_ID,          AL_GROUPATTR,   SEC_INT}
831         };
832
833         logit("method attrlist called\n");
834
835         n = sizeof(attr_list) / sizeof(struct attr_types);
836         size = (n*sizeof(attrlist_t *));
837
838         if ( (ret = malloc( size )) == NULL ) {
839                 errno = ENOMEM;
840                 return NULL;
841         }
842
843         /* offset to where the structures start in the buffer */
844
845         offset = (attrlist_t *)(ret + n);
846
847         /* now loop over the user_attr_list[] array and add
848            all the members */
849
850         for ( i=0; i<n; i++ ) {
851                 attrlist_t *a = malloc(sizeof(attrlist_t));
852
853                 if ( !a ) {
854                         /* this is bad.  Just bail */
855                         return NULL;
856                 }
857
858                 a->al_name  = strdup(attr_list[i].name);
859                 a->al_flags = attr_list[i].flags;
860                 a->al_type  = attr_list[i].type;
861
862                 ret[i] = a;
863         }
864         ret[n] = NULL;
865
866         return ret;
867 }
868 #endif
869
870
871 /*
872   turn a long username into a short one. Needed to cope with the 8 char
873   username limit in AIX 5.2 and below
874 */
875 static int wb_aix_normalize(char *longname, char *shortname)
876 {
877         struct passwd *pwd;
878
879         logit("normalize '%s'\n", longname);
880
881         /* automatically cope with AIX 5.3 with longer usernames
882            when it comes out */
883         if (S_NAMELEN > strlen(longname)) {
884                 strncpy(shortname, longname, S_NAMELEN);
885                 shortname[S_NAMELEN-1] = '\0';
886                 return 1;
887         }
888
889         pwd = wb_aix_getpwnam(longname);
890         if (!pwd) {
891                 errno = ENOENT;
892                 return 0;
893         }
894
895         sprintf(shortname, "%c%07u", WB_AIX_ENCODED, pwd->pw_uid);
896
897         free_pwd(pwd);
898
899         return 1;
900 }
901
902
903 /*
904   authenticate a user
905  */
906 static int wb_aix_authenticate(char *user, char *pass,
907                                int *reenter, char **message)
908 {
909         struct winbindd_request request = {
910                 .wb_flags = WBFLAG_FROM_NSS,
911         };
912         struct winbindd_response response = {
913                 .length = 0,
914         };
915         NSS_STATUS result;
916         char *r_user = user;
917
918         logit("authenticate '%s' response='%s'\n", user, pass);
919
920         *reenter = 0;
921         *message = NULL;
922
923         /* Send off request */
924         if (*user == WB_AIX_ENCODED) {
925                 r_user = decode_user(r_user);
926                 if (!r_user) {
927                         return AUTH_NOTFOUND;
928                 }
929         }
930
931         STRCPY_RET(request.data.auth.user, r_user);
932         STRCPY_RET(request.data.auth.pass, pass);
933
934         if (*user == WB_AIX_ENCODED) {
935                 free(r_user);
936         }
937
938         result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH,
939                                            &request, &response);
940
941         winbindd_free_response(&response);
942
943         logit("auth result %d for '%s'\n", result, user);
944
945         if (result == NSS_STATUS_SUCCESS) {
946                 errno = 0;
947                 return AUTH_SUCCESS;
948         }
949
950         return AUTH_FAILURE;
951 }
952
953
954 /*
955   change a user password
956 */
957 static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message)
958 {
959         struct winbindd_request request = {
960                 .wb_flags = WBFLAG_FROM_NSS,
961         };
962         struct winbindd_response response = {
963                 .length = 0,
964         };
965         NSS_STATUS result;
966         char *r_user = user;
967
968         if (*user == WB_AIX_ENCODED) {
969                 r_user = decode_user(r_user);
970                 if (!r_user) {
971                         errno = ENOENT;
972                         return -1;
973                 }
974         }
975
976         logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass);
977
978         *message = NULL;
979
980         /* Send off request */
981         STRCPY_RET(request.data.chauthtok.user, r_user);
982         STRCPY_RET(request.data.chauthtok.oldpass, oldpass);
983         STRCPY_RET(request.data.chauthtok.newpass, newpass);
984
985         if (*user == WB_AIX_ENCODED) {
986                 free(r_user);
987         }
988
989         result = winbindd_request_response(NULL, WINBINDD_PAM_CHAUTHTOK,
990                                            &request, &response);
991
992         winbindd_free_response(&response);
993
994         if (result == NSS_STATUS_SUCCESS) {
995                 errno = 0;
996                 return 0;
997         }
998
999         errno = EINVAL;
1000         return -1;
1001 }
1002
1003 /*
1004   don't do any password strength testing for now
1005 */
1006 static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass,
1007                                      char **message)
1008 {
1009         logit("passwdresrictions called for '%s'\n", user);
1010         return 0;
1011 }
1012
1013
1014 static int wb_aix_passwdexpired(char *user, char **message)
1015 {
1016         logit("passwdexpired '%s'\n", user);
1017         /* we should check the account bits here */
1018         return 0;
1019 }
1020
1021
1022 /*
1023   we can't return a crypt() password
1024 */
1025 static char *wb_aix_getpasswd(char *user)
1026 {
1027         logit("getpasswd '%s'\n", user);
1028         errno = ENOSYS;
1029         return NULL;
1030 }
1031
1032 /*
1033   this is called to update things like the last login time. We don't
1034   currently pass this onto the DC
1035 */
1036 static int wb_aix_putentry(char *key, char *table, char *attributes[],
1037                            attrval_t values[], int size)
1038 {
1039         logit("putentry key='%s' table='%s' attrib='%s'\n",
1040               key, table, size>=1?attributes[0]:"<null>");
1041         errno = ENOSYS;
1042         return -1;
1043 }
1044
1045 static int wb_aix_commit(char *key, char *table)
1046 {
1047         logit("commit key='%s' table='%s'\n");
1048         errno = ENOSYS;
1049         return -1;
1050 }
1051
1052 static int wb_aix_getgrusers(char *group, void *result, int type, int *size)
1053 {
1054         logit("getgrusers group='%s'\n", group);
1055         errno = ENOSYS;
1056         return -1;
1057 }
1058
1059
1060 #define DECL_METHOD(x) \
1061 int method_ ## x(void) \
1062 { \
1063         logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
1064         errno = EINVAL; \
1065         return -1; \
1066 }
1067
1068 #if LOG_UNIMPLEMENTED_CALLS
1069 DECL_METHOD(delgroup);
1070 DECL_METHOD(deluser);
1071 DECL_METHOD(newgroup);
1072 DECL_METHOD(newuser);
1073 DECL_METHOD(putgrent);
1074 DECL_METHOD(putgrusers);
1075 DECL_METHOD(putpwent);
1076 DECL_METHOD(lock);
1077 DECL_METHOD(unlock);
1078 DECL_METHOD(getcred);
1079 DECL_METHOD(setcred);
1080 DECL_METHOD(deletecred);
1081 #endif
1082
1083 int wb_aix_init(struct secmethod_table *methods)
1084 {
1085         ZERO_STRUCTP(methods);
1086
1087 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION
1088         methods->method_version = SECMETHOD_VERSION_520;
1089 #endif
1090
1091         methods->method_getgrgid           = wb_aix_getgrgid;
1092         methods->method_getgrnam           = wb_aix_getgrnam;
1093         methods->method_getgrset           = wb_aix_getgrset;
1094         methods->method_getpwnam           = wb_aix_getpwnam;
1095         methods->method_getpwuid           = wb_aix_getpwuid;
1096         methods->method_getentry           = wb_aix_getentry;
1097         methods->method_open               = wb_aix_open;
1098         methods->method_close              = wb_aix_close;
1099         methods->method_normalize          = wb_aix_normalize;
1100         methods->method_passwdexpired      = wb_aix_passwdexpired;
1101         methods->method_putentry           = wb_aix_putentry;
1102         methods->method_getpasswd          = wb_aix_getpasswd;
1103         methods->method_authenticate       = wb_aix_authenticate;
1104         methods->method_commit             = wb_aix_commit;
1105         methods->method_chpass             = wb_aix_chpass;
1106         methods->method_passwdrestrictions = wb_aix_passwdrestrictions;
1107         methods->method_getgracct          = wb_aix_getgracct;
1108         methods->method_getgrusers         = wb_aix_getgrusers;
1109 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
1110         methods->method_attrlist           = wb_aix_attrlist;
1111 #endif
1112
1113 #if LOG_UNIMPLEMENTED_CALLS
1114         methods->method_delgroup      = method_delgroup;
1115         methods->method_deluser       = method_deluser;
1116         methods->method_newgroup      = method_newgroup;
1117         methods->method_newuser       = method_newuser;
1118         methods->method_putgrent      = method_putgrent;
1119         methods->method_putgrusers    = method_putgrusers;
1120         methods->method_putpwent      = method_putpwent;
1121         methods->method_lock          = method_lock;
1122         methods->method_unlock        = method_unlock;
1123         methods->method_getcred       = method_getcred;
1124         methods->method_setcred       = method_setcred;
1125         methods->method_deletecred    = method_deletecred;
1126 #endif
1127
1128         return AUTH_SUCCESS;
1129 }