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 Library General Public
13   License as published by the Free Software Foundation; either
14   version 2 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 Library General Public
22   License along with this library; if not, write to the
23   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24   Boston, MA  02111-1307, USA.
25*/
26
27/*
28
29  To install this module copy nsswitch/WINBIND to /usr/lib/security and add
30  "WINBIND" in /usr/lib/security/methods.cfg and /etc/security/user
31
32  Note that this module also provides authentication and password
33  changing routines, so you do not need to install the winbind PAM
34  module.
35
36  see
37  http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/kernextc/sec_load_mod.htm
38  for some information in the interface that this module implements
39
40  Many thanks to Julianne Haugh for explaining some of the finer
41  details of this interface.
42
43  To debug this module use uess_test.c (which you can get from tridge)
44  or set "options=debug" in /usr/lib/security/methods.cfg
45
46*/
47
48#include <stdlib.h>
49#include <string.h>
50#include <usersec.h>
51#include <errno.h>
52#include <stdarg.h>
53
54#include "winbind_client.h"
55
56#define WB_AIX_ENCODED '_'
57
58static int debug_enabled;
59
60
61static void logit(const char *format, ...)
62{
63	va_list ap;
64	FILE *f;
65	if (!debug_enabled) {
66		return;
67	}
68	f = fopen("/tmp/WINBIND_DEBUG.log", "a");
69	if (!f) return;
70	va_start(ap, format);
71	vfprintf(f, format, ap);
72	va_end(ap);
73	fclose(f);
74}
75
76
77#define HANDLE_ERRORS(ret) do { \
78	if ((ret) == NSS_STATUS_NOTFOUND) { \
79		errno = ENOENT; \
80		return NULL; \
81	} else if ((ret) != NSS_STATUS_SUCCESS) { \
82		errno = EIO; \
83		return NULL; \
84	} \
85} while (0)
86
87#define STRCPY_RET(dest, src) \
88do { \
89	if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return -1; } \
90	strcpy(dest, src); \
91} while (0)
92
93#define STRCPY_RETNULL(dest, src) \
94do { \
95	if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return NULL; } \
96	strcpy(dest, src); \
97} while (0)
98
99
100/* free a passwd structure */
101static 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 */
112static 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 */
134static 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*/
155static unsigned decode_id(const char *name)
156{
157	unsigned id;
158	sscanf(name+1, "%u", &id);
159	return id;
160}
161
162static struct passwd *wb_aix_getpwuid(uid_t uid);
163
164static 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*/
188static 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*/
213static 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		errno = ENOMEM;
243		return NULL;
244	}
245
246	/* Start looking at extra data */
247	i=0;
248	for (name = strtok_r(gr_mem, ",", &p);
249	     name;
250	     name = strtok_r(NULL, ",", &p)) {
251		if (i == gr->num_gr_mem) {
252			break;
253		}
254		result->gr_mem[i] = strdup(name);
255		i++;
256	}
257
258	/* Terminate list */
259	result->gr_mem[i] = NULL;
260
261	return result;
262}
263
264
265
266/* take a group id and return a filled struct group */
267static struct group *wb_aix_getgrgid(gid_t gid)
268{
269	struct winbindd_response response;
270	struct winbindd_request request;
271	struct group *grp;
272	NSS_STATUS ret;
273
274	logit("getgrgid %d\n", gid);
275
276	ZERO_STRUCT(response);
277	ZERO_STRUCT(request);
278
279	request.data.gid = gid;
280
281	ret = winbindd_request(WINBINDD_GETGRGID, &request, &response);
282
283	logit("getgrgid ret=%d\n", ret);
284
285	HANDLE_ERRORS(ret);
286
287	grp = fill_grent(&response.data.gr, response.extra_data);
288
289	free_response(&response);
290
291	return grp;
292}
293
294/* take a group name and return a filled struct group */
295static struct group *wb_aix_getgrnam(const char *name)
296{
297	struct winbindd_response response;
298	struct winbindd_request request;
299	NSS_STATUS ret;
300	struct group *grp;
301
302	if (*name == WB_AIX_ENCODED) {
303		return wb_aix_getgrgid(decode_id(name));
304	}
305
306	logit("getgrnam '%s'\n", name);
307
308	ZERO_STRUCT(response);
309	ZERO_STRUCT(request);
310
311	STRCPY_RETNULL(request.data.groupname, name);
312
313	ret = winbindd_request(WINBINDD_GETGRNAM, &request, &response);
314
315	HANDLE_ERRORS(ret);
316
317	grp = fill_grent(&response.data.gr, response.extra_data);
318
319	free_response(&response);
320
321	return grp;
322}
323
324
325/* this call doesn't have to fill in the gr_mem, but we do anyway
326   for simplicity */
327static struct group *wb_aix_getgracct(void *id, int type)
328{
329	if (type == 1) {
330		return wb_aix_getgrnam((char *)id);
331	}
332	if (type == 0) {
333		return wb_aix_getgrgid(*(int *)id);
334	}
335	errno = EINVAL;
336	return NULL;
337}
338
339
340/* take a username and return a string containing a comma-separated
341   list of group id numbers to which the user belongs */
342static char *wb_aix_getgrset(char *user)
343{
344	struct winbindd_response response;
345	struct winbindd_request request;
346	NSS_STATUS ret;
347	int i, idx;
348	char *tmpbuf;
349	int num_gids;
350	gid_t *gid_list;
351	char *r_user = user;
352
353	if (*user == WB_AIX_ENCODED) {
354		r_user = decode_user(r_user);
355		if (!r_user) {
356			errno = ENOENT;
357			return NULL;
358		}
359	}
360
361	logit("getgrset '%s'\n", r_user);
362
363	STRCPY_RETNULL(request.data.username, r_user);
364
365	if (*user == WB_AIX_ENCODED) {
366		free(r_user);
367	}
368
369	ret = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
370
371	HANDLE_ERRORS(ret);
372
373	num_gids = response.data.num_entries;
374	gid_list = (gid_t *)response.extra_data;
375
376	/* allocate a space large enough to contruct the string */
377	tmpbuf = malloc(num_gids*12);
378	if (!tmpbuf) {
379		return NULL;
380	}
381
382	for (idx=i=0; i < num_gids-1; i++) {
383		idx += sprintf(tmpbuf+idx, "%u,", gid_list[i]);
384	}
385	idx += sprintf(tmpbuf+idx, "%u", gid_list[i]);
386
387	free_response(&response);
388
389	return tmpbuf;
390}
391
392
393/* take a uid and return a filled struct passwd */
394static struct passwd *wb_aix_getpwuid(uid_t uid)
395{
396	struct winbindd_response response;
397	struct winbindd_request request;
398	NSS_STATUS ret;
399	struct passwd *pwd;
400
401	logit("getpwuid '%d'\n", uid);
402
403	ZERO_STRUCT(response);
404	ZERO_STRUCT(request);
405
406	request.data.uid = uid;
407
408	ret = winbindd_request(WINBINDD_GETPWUID, &request, &response);
409
410	HANDLE_ERRORS(ret);
411
412	pwd = fill_pwent(&response.data.pw);
413
414	free_response(&response);
415
416	logit("getpwuid gave ptr %p\n", pwd);
417
418	return pwd;
419}
420
421
422/* take a username and return a filled struct passwd */
423static struct passwd *wb_aix_getpwnam(const char *name)
424{
425	struct winbindd_response response;
426	struct winbindd_request request;
427	NSS_STATUS ret;
428	struct passwd *pwd;
429
430	if (*name == WB_AIX_ENCODED) {
431		return wb_aix_getpwuid(decode_id(name));
432	}
433
434	logit("getpwnam '%s'\n", name);
435
436	ZERO_STRUCT(response);
437	ZERO_STRUCT(request);
438
439	STRCPY_RETNULL(request.data.username, name);
440
441	ret = winbindd_request(WINBINDD_GETPWNAM, &request, &response);
442
443	HANDLE_ERRORS(ret);
444
445	pwd = fill_pwent(&response.data.pw);
446
447	free_response(&response);
448
449	logit("getpwnam gave ptr %p\n", pwd);
450
451	return pwd;
452}
453
454/*
455  list users
456*/
457static int wb_aix_lsuser(char *attributes[], attrval_t results[], int size)
458{
459	NSS_STATUS ret;
460	struct winbindd_request request;
461	struct winbindd_response response;
462	int len;
463	char *s;
464
465	if (size != 1 || strcmp(attributes[0], S_USERS) != 0) {
466		logit("invalid lsuser op\n");
467		errno = EINVAL;
468		return -1;
469	}
470
471	ZERO_STRUCT(request);
472	ZERO_STRUCT(response);
473
474	ret = winbindd_request(WINBINDD_LIST_USERS, &request, &response);
475	if (ret != 0) {
476		errno = EINVAL;
477		return -1;
478	}
479
480	len = strlen(response.extra_data);
481
482	s = malloc(len+2);
483	if (!s) {
484		free_response(&response);
485		errno = ENOMEM;
486		return -1;
487	}
488
489	memcpy(s, response.extra_data, len+1);
490
491	replace_commas(s);
492
493	results[0].attr_un.au_char = s;
494	results[0].attr_flag = 0;
495
496	free_response(&response);
497
498	return 0;
499}
500
501
502/*
503  list groups
504*/
505static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size)
506{
507	NSS_STATUS ret;
508	struct winbindd_request request;
509	struct winbindd_response response;
510	int len;
511	char *s;
512
513	if (size != 1 || strcmp(attributes[0], S_GROUPS) != 0) {
514		logit("invalid lsgroup op\n");
515		errno = EINVAL;
516		return -1;
517	}
518
519	ZERO_STRUCT(request);
520	ZERO_STRUCT(response);
521
522	ret = winbindd_request(WINBINDD_LIST_GROUPS, &request, &response);
523	if (ret != 0) {
524		errno = EINVAL;
525		return -1;
526	}
527
528	len = strlen(response.extra_data);
529
530	s = malloc(len+2);
531	if (!s) {
532		free_response(&response);
533		errno = ENOMEM;
534		return -1;
535	}
536
537	memcpy(s, response.extra_data, len+1);
538
539	replace_commas(s);
540
541	results[0].attr_un.au_char = s;
542	results[0].attr_flag = 0;
543
544	free_response(&response);
545
546	return 0;
547}
548
549
550static attrval_t pwd_to_group(struct passwd *pwd)
551{
552	attrval_t r;
553	struct group *grp = wb_aix_getgrgid(pwd->pw_gid);
554
555	if (!grp) {
556		r.attr_flag = EINVAL;
557	} else {
558		r.attr_flag = 0;
559		r.attr_un.au_char = strdup(grp->gr_name);
560		free_grp(grp);
561	}
562
563	return r;
564}
565
566static attrval_t pwd_to_groupsids(struct passwd *pwd)
567{
568	attrval_t r;
569	char *s, *p;
570
571	s = wb_aix_getgrset(pwd->pw_name);
572	if (!s) {
573		r.attr_flag = EINVAL;
574		return r;
575	}
576
577	p = malloc(strlen(s)+2);
578	if (!p) {
579		r.attr_flag = ENOMEM;
580		return r;
581	}
582
583	strcpy(p, s);
584	replace_commas(p);
585	free(s);
586
587	r.attr_un.au_char = p;
588
589	return r;
590}
591
592static attrval_t pwd_to_sid(struct passwd *pwd)
593{
594	struct winbindd_request request;
595	struct winbindd_response response;
596	attrval_t r;
597
598	ZERO_STRUCT(request);
599	ZERO_STRUCT(response);
600
601	request.data.uid = pwd->pw_uid;
602
603	if (winbindd_request(WINBINDD_UID_TO_SID, &request, &response) !=
604	    NSS_STATUS_SUCCESS) {
605		r.attr_flag = ENOENT;
606	} else {
607		r.attr_flag = 0;
608		r.attr_un.au_char = strdup(response.data.sid.sid);
609	}
610
611	return r;
612}
613
614static int wb_aix_user_attrib(const char *key, char *attributes[],
615			      attrval_t results[], int size)
616{
617	struct passwd *pwd;
618	int i;
619
620	pwd = wb_aix_getpwnam(key);
621	if (!pwd) {
622		errno = ENOENT;
623		return -1;
624	}
625
626	for (i=0;i<size;i++) {
627		results[i].attr_flag = 0;
628
629		if (strcmp(attributes[i], S_ID) == 0) {
630			results[i].attr_un.au_int = pwd->pw_uid;
631		} else if (strcmp(attributes[i], S_PWD) == 0) {
632			results[i].attr_un.au_char = strdup(pwd->pw_passwd);
633		} else if (strcmp(attributes[i], S_HOME) == 0) {
634			results[i].attr_un.au_char = strdup(pwd->pw_dir);
635		} else if (strcmp(attributes[0], S_SHELL) == 0) {
636			results[i].attr_un.au_char = strdup(pwd->pw_shell);
637		} else if (strcmp(attributes[0], S_REGISTRY) == 0) {
638			results[i].attr_un.au_char = strdup("WINBIND");
639		} else if (strcmp(attributes[0], S_GECOS) == 0) {
640			results[i].attr_un.au_char = strdup(pwd->pw_gecos);
641		} else if (strcmp(attributes[0], S_PGRP) == 0) {
642			results[i] = pwd_to_group(pwd);
643		} else if (strcmp(attributes[0], S_GECOS) == 0) {
644			results[i].attr_un.au_char = strdup(pwd->pw_gecos);
645		} else if (strcmp(attributes[0], S_GROUPSIDS) == 0) {
646			results[i] = pwd_to_groupsids(pwd);
647		} else if (strcmp(attributes[0], "SID") == 0) {
648			results[i] = pwd_to_sid(pwd);
649		} else {
650			logit("Unknown user attribute '%s'\n", attributes[i]);
651			results[i].attr_flag = EINVAL;
652		}
653	}
654
655	free_pwd(pwd);
656
657	return 0;
658}
659
660static int wb_aix_group_attrib(const char *key, char *attributes[],
661			       attrval_t results[], int size)
662{
663	struct group *grp;
664	int i;
665
666	grp = wb_aix_getgrnam(key);
667	if (!grp) {
668		errno = ENOENT;
669		return -1;
670	}
671
672	for (i=0;i<size;i++) {
673		results[i].attr_flag = 0;
674
675		if (strcmp(attributes[i], S_PWD) == 0) {
676			results[i].attr_un.au_char = strdup(grp->gr_passwd);
677		} else if (strcmp(attributes[i], S_ID) == 0) {
678			results[i].attr_un.au_int = grp->gr_gid;
679		} else {
680			logit("Unknown group attribute '%s'\n", attributes[i]);
681			results[i].attr_flag = EINVAL;
682		}
683	}
684
685	free_grp(grp);
686
687	return 0;
688}
689
690
691/*
692  called for user/group enumerations
693*/
694static int wb_aix_getentry(char *key, char *table, char *attributes[],
695			   attrval_t results[], int size)
696{
697	logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n",
698	      key, table, size, attributes[0]);
699
700	if (strcmp(key, "ALL") == 0 &&
701	    strcmp(table, "user") == 0) {
702		return wb_aix_lsuser(attributes, results, size);
703	}
704
705	if (strcmp(key, "ALL") == 0 &&
706	    strcmp(table, "group") == 0) {
707		return wb_aix_lsgroup(attributes, results, size);
708	}
709
710	if (strcmp(table, "user") == 0) {
711		return wb_aix_user_attrib(key, attributes, results, size);
712	}
713
714	if (strcmp(table, "group") == 0) {
715		return wb_aix_group_attrib(key, attributes, results, size);
716	}
717
718	logit("Unknown getentry operation key='%s' table='%s'\n", key, table);
719
720	errno = ENOSYS;
721	return -1;
722}
723
724
725
726/*
727  called to start the backend
728*/
729static void *wb_aix_open(const char *name, const char *domain, int mode, char *options)
730{
731	if (strstr(options, "debug")) {
732		debug_enabled = 1;
733	}
734	logit("open name='%s' mode=%d domain='%s' options='%s'\n", name, domain,
735	      mode, options);
736	return NULL;
737}
738
739static void wb_aix_close(void *token)
740{
741	logit("close\n");
742	return;
743}
744
745#ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
746/*
747   return a list of additional attributes supported by the backend
748*/
749static attrlist_t **wb_aix_attrlist(void)
750{
751	attrlist_t **ret;
752	logit("method attrlist called\n");
753	ret = malloc(2*sizeof(attrlist_t *) + sizeof(attrlist_t));
754	if (!ret) {
755		errno = ENOMEM;
756		return NULL;
757	}
758
759	ret[0] = (attrlist_t *)(ret+2);
760
761	/* just one extra attribute - the windows SID */
762	ret[0]->al_name = strdup("SID");
763	ret[0]->al_flags = AL_USERATTR;
764	ret[0]->al_type = SEC_CHAR;
765	ret[1] = NULL;
766
767	return ret;
768}
769#endif
770
771
772/*
773  turn a long username into a short one. Needed to cope with the 8 char
774  username limit in AIX 5.2 and below
775*/
776static int wb_aix_normalize(char *longname, char *shortname)
777{
778	struct passwd *pwd;
779
780	logit("normalize '%s'\n", longname);
781
782	/* automatically cope with AIX 5.3 with longer usernames
783	   when it comes out */
784	if (S_NAMELEN > strlen(longname)) {
785		strcpy(shortname, longname);
786		return 1;
787	}
788
789	pwd = wb_aix_getpwnam(longname);
790	if (!pwd) {
791		errno = ENOENT;
792		return 0;
793	}
794
795	sprintf(shortname, "%c%07u", WB_AIX_ENCODED, pwd->pw_uid);
796
797	free_pwd(pwd);
798
799	return 1;
800}
801
802
803/*
804  authenticate a user
805 */
806static int wb_aix_authenticate(char *user, char *pass,
807			       int *reenter, char **message)
808{
809	struct winbindd_request request;
810	struct winbindd_response response;
811        NSS_STATUS result;
812	char *r_user = user;
813
814	logit("authenticate '%s' response='%s'\n", user, pass);
815
816	*reenter = 0;
817	*message = NULL;
818
819	/* Send off request */
820	ZERO_STRUCT(request);
821	ZERO_STRUCT(response);
822
823	if (*user == WB_AIX_ENCODED) {
824		r_user = decode_user(r_user);
825		if (!r_user) {
826			return AUTH_NOTFOUND;
827		}
828	}
829
830	STRCPY_RET(request.data.auth.user, r_user);
831	STRCPY_RET(request.data.auth.pass, pass);
832
833	if (*user == WB_AIX_ENCODED) {
834		free(r_user);
835	}
836
837	result = winbindd_request(WINBINDD_PAM_AUTH, &request, &response);
838
839	free_response(&response);
840
841	logit("auth result %d for '%s'\n", result, user);
842
843	if (result == NSS_STATUS_SUCCESS) {
844		errno = 0;
845		return AUTH_SUCCESS;
846	}
847
848	return AUTH_FAILURE;
849}
850
851
852/*
853  change a user password
854*/
855static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message)
856{
857	struct winbindd_request request;
858	struct winbindd_response response;
859        NSS_STATUS result;
860	char *r_user = user;
861
862	if (*user == WB_AIX_ENCODED) {
863		r_user = decode_user(r_user);
864		if (!r_user) {
865			errno = ENOENT;
866			return -1;
867		}
868	}
869
870	logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass);
871
872	*message = NULL;
873
874	/* Send off request */
875	ZERO_STRUCT(request);
876	ZERO_STRUCT(response);
877
878	STRCPY_RET(request.data.chauthtok.user, r_user);
879	STRCPY_RET(request.data.chauthtok.oldpass, oldpass);
880	STRCPY_RET(request.data.chauthtok.newpass, newpass);
881
882	if (*user == WB_AIX_ENCODED) {
883		free(r_user);
884	}
885
886	result = winbindd_request(WINBINDD_PAM_CHAUTHTOK, &request, &response);
887
888	free_response(&response);
889
890	if (result == NSS_STATUS_SUCCESS) {
891		errno = 0;
892		return 0;
893	}
894
895	errno = EINVAL;
896	return -1;
897}
898
899/*
900  don't do any password strength testing for now
901*/
902static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass,
903				     char **message)
904{
905	logit("passwdresrictions called for '%s'\n", user);
906	return 0;
907}
908
909
910static int wb_aix_passwdexpired(char *user, char **message)
911{
912	logit("passwdexpired '%s'\n", user);
913	/* we should check the account bits here */
914	return 0;
915}
916
917
918/*
919  we can't return a crypt() password
920*/
921static char *wb_aix_getpasswd(char *user)
922{
923	logit("getpasswd '%s'\n", user);
924	errno = ENOSYS;
925	return NULL;
926}
927
928/*
929  this is called to update things like the last login time. We don't
930  currently pass this onto the DC
931*/
932static int wb_aix_putentry(char *key, char *table, char *attributes[],
933			   attrval_t values[], int size)
934{
935	logit("putentry key='%s' table='%s' attrib='%s'\n",
936	      key, table, size>=1?attributes[0]:"<null>");
937	errno = ENOSYS;
938	return -1;
939}
940
941static int wb_aix_commit(char *key, char *table)
942{
943	logit("commit key='%s' table='%s'\n");
944	errno = ENOSYS;
945	return -1;
946}
947
948static int wb_aix_getgrusers(char *group, void *result, int type, int *size)
949{
950	logit("getgrusers group='%s'\n", group);
951	errno = ENOSYS;
952	return -1;
953}
954
955
956#define DECL_METHOD(x) \
957int method_ ## x(void) \
958{ \
959	logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
960	errno = EINVAL; \
961	return -1; \
962}
963
964#if LOG_UNIMPLEMENTED_CALLS
965DECL_METHOD(delgroup);
966DECL_METHOD(deluser);
967DECL_METHOD(newgroup);
968DECL_METHOD(newuser);
969DECL_METHOD(putgrent);
970DECL_METHOD(putgrusers);
971DECL_METHOD(putpwent);
972DECL_METHOD(lock);
973DECL_METHOD(unlock);
974DECL_METHOD(getcred);
975DECL_METHOD(setcred);
976DECL_METHOD(deletecred);
977#endif
978
979int wb_aix_init(struct secmethod_table *methods)
980{
981	ZERO_STRUCTP(methods);
982
983#ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION
984	methods->method_version = SECMETHOD_VERSION_520;
985#endif
986
987	methods->method_getgrgid           = wb_aix_getgrgid;
988	methods->method_getgrnam           = wb_aix_getgrnam;
989	methods->method_getgrset           = wb_aix_getgrset;
990	methods->method_getpwnam           = wb_aix_getpwnam;
991	methods->method_getpwuid           = wb_aix_getpwuid;
992	methods->method_getentry           = wb_aix_getentry;
993	methods->method_open               = wb_aix_open;
994	methods->method_close              = wb_aix_close;
995	methods->method_normalize          = wb_aix_normalize;
996	methods->method_passwdexpired      = wb_aix_passwdexpired;
997	methods->method_putentry           = wb_aix_putentry;
998	methods->method_getpasswd          = wb_aix_getpasswd;
999	methods->method_authenticate       = wb_aix_authenticate;
1000	methods->method_commit             = wb_aix_commit;
1001	methods->method_chpass             = wb_aix_chpass;
1002	methods->method_passwdrestrictions = wb_aix_passwdrestrictions;
1003	methods->method_getgracct          = wb_aix_getgracct;
1004	methods->method_getgrusers         = wb_aix_getgrusers;
1005#ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
1006	methods->method_attrlist           = wb_aix_attrlist;
1007#endif
1008
1009#if LOG_UNIMPLEMENTED_CALLS
1010	methods->method_delgroup      = method_delgroup;
1011	methods->method_deluser       = method_deluser;
1012	methods->method_newgroup      = method_newgroup;
1013	methods->method_newuser       = method_newuser;
1014	methods->method_putgrent      = method_putgrent;
1015	methods->method_putgrusers    = method_putgrusers;
1016	methods->method_putpwent      = method_putpwent;
1017	methods->method_lock          = method_lock;
1018	methods->method_unlock        = method_unlock;
1019	methods->method_getcred       = method_getcred;
1020	methods->method_setcred       = method_setcred;
1021	methods->method_deletecred    = method_deletecred;
1022#endif
1023
1024	return AUTH_SUCCESS;
1025}
1026
1027