2 Unix SMB/CIFS implementation.
4 AIX loadable authentication module, providing identification and
5 authentication routines against Samba winbind/Windows NT Domain
7 Copyright (C) Tim Potter 2003
8 Copyright (C) Steve Roylance 2003
9 Copyright (C) Andrew Tridgell 2003-2004
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.
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.
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/>.
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
30 Note that this module also provides authentication and password
31 changing routines, so you do not need to install the winbind PAM
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
38 Many thanks to Julianne Haugh for explaining some of the finer
39 details of this interface.
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
46 #include "winbind_client.h"
49 /* enable this to log which entry points have not been
51 #define LOG_UNIMPLEMENTED_CALLS 0
54 #define WB_AIX_ENCODED '_'
56 static int debug_enabled
;
59 static void logit(const char *format
, ...)
66 f
= fopen("/tmp/WINBIND_DEBUG.log", "a");
69 vfprintf(f
, format
, ap
);
75 #define HANDLE_ERRORS(ret) do { \
76 if ((ret) == NSS_STATUS_NOTFOUND) { \
79 } else if ((ret) != NSS_STATUS_SUCCESS) { \
85 #define STRCPY_RET(dest, src) \
87 if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return -1; } \
91 #define STRCPY_RETNULL(dest, src) \
93 if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return NULL; } \
98 /* free a passwd structure */
99 static void free_pwd(struct passwd
*pwd
)
102 free(pwd
->pw_passwd
);
109 /* free a group structure */
110 static void free_grp(struct group
*grp
)
115 free(grp
->gr_passwd
);
122 for (i
=0; grp
->gr_mem
[i
]; i
++) {
123 free(grp
->gr_mem
[i
]);
131 /* replace commas with nulls, and null terminate */
132 static void replace_commas(char *s
)
135 for (p
=strchr(s
, ','); p
; p
= strchr(p
+1, ',')) {
140 p0
[strlen(p0
)+1] = 0;
144 /* the decode_*() routines are used to cope with the fact that AIX 5.2
145 and below cannot handle user or group names longer than 8
146 characters in some interfaces. We use the normalize method to
147 provide a mapping to a username that fits, by using the form '_UID'
150 this only works if you can guarantee that the WB_AIX_ENCODED char
151 is not used as the first char of any other username
153 static unsigned decode_id(const char *name
)
156 sscanf(name
+1, "%u", &id
);
160 static struct passwd
*wb_aix_getpwuid(uid_t uid
);
162 static char *decode_user(const char *name
)
168 sscanf(name
+1, "%u", &id
);
169 pwd
= wb_aix_getpwuid(id
);
173 ret
= strdup(pwd
->pw_name
);
177 logit("decoded '%s' -> '%s'\n", name
, ret
);
184 fill a struct passwd from a winbindd_pw struct, allocating as a single block
186 static struct passwd
*fill_pwent(struct winbindd_pw
*pw
)
188 struct passwd
*result
;
190 result
= calloc(1, sizeof(struct passwd
));
196 result
->pw_uid
= pw
->pw_uid
;
197 result
->pw_gid
= pw
->pw_gid
;
198 result
->pw_name
= strdup(pw
->pw_name
);
199 result
->pw_passwd
= strdup(pw
->pw_passwd
);
200 result
->pw_gecos
= strdup(pw
->pw_gecos
);
201 result
->pw_dir
= strdup(pw
->pw_dir
);
202 result
->pw_shell
= strdup(pw
->pw_shell
);
209 fill a struct group from a winbindd_pw struct, allocating as a single block
211 static struct group
*fill_grent(struct winbindd_gr
*gr
, char *gr_mem
)
214 struct group
*result
;
217 result
= calloc(1, sizeof(struct group
));
223 result
->gr_gid
= gr
->gr_gid
;
225 result
->gr_name
= strdup(gr
->gr_name
);
226 result
->gr_passwd
= strdup(gr
->gr_passwd
);
228 /* Group membership */
229 if ((gr
->num_gr_mem
< 0) || !gr_mem
) {
233 if (gr
->num_gr_mem
== 0) {
238 result
->gr_mem
= (char **)malloc(sizeof(char *) * (gr
->num_gr_mem
+1));
239 if (!result
->gr_mem
) {
240 free(result
->gr_name
);
241 free(result
->gr_passwd
);
247 /* Start looking at extra data */
249 for (name
= strtok_r(gr_mem
, ",", &p
);
251 name
= strtok_r(NULL
, ",", &p
)) {
252 if (i
== gr
->num_gr_mem
) {
255 result
->gr_mem
[i
] = strdup(name
);
260 result
->gr_mem
[i
] = NULL
;
267 /* take a group id and return a filled struct group */
268 static struct group
*wb_aix_getgrgid(gid_t gid
)
270 struct winbindd_response response
;
271 struct winbindd_request request
;
275 logit("getgrgid %d\n", gid
);
277 ZERO_STRUCT(response
);
278 ZERO_STRUCT(request
);
280 request
.data
.gid
= gid
;
282 ret
= winbindd_request_response(WINBINDD_GETGRGID
, &request
, &response
);
284 logit("getgrgid ret=%d\n", ret
);
288 grp
= fill_grent(&response
.data
.gr
, response
.extra_data
.data
);
290 winbindd_free_response(&response
);
295 /* take a group name and return a filled struct group */
296 static struct group
*wb_aix_getgrnam(const char *name
)
298 struct winbindd_response response
;
299 struct winbindd_request request
;
303 if (*name
== WB_AIX_ENCODED
) {
304 return wb_aix_getgrgid(decode_id(name
));
307 logit("getgrnam '%s'\n", name
);
309 ZERO_STRUCT(response
);
310 ZERO_STRUCT(request
);
312 STRCPY_RETNULL(request
.data
.groupname
, name
);
314 ret
= winbindd_request_response(WINBINDD_GETGRNAM
, &request
, &response
);
318 grp
= fill_grent(&response
.data
.gr
, response
.extra_data
.data
);
320 winbindd_free_response(&response
);
326 /* this call doesn't have to fill in the gr_mem, but we do anyway
328 static struct group
*wb_aix_getgracct(void *id
, int type
)
331 return wb_aix_getgrnam((char *)id
);
334 return wb_aix_getgrgid(*(int *)id
);
341 /* take a username and return a string containing a comma-separated
342 list of group id numbers to which the user belongs */
343 static char *wb_aix_getgrset(char *user
)
345 struct winbindd_response response
;
346 struct winbindd_request request
;
354 if (*user
== WB_AIX_ENCODED
) {
355 r_user
= decode_user(r_user
);
362 logit("getgrset '%s'\n", r_user
);
364 ZERO_STRUCT(response
);
365 ZERO_STRUCT(request
);
367 STRCPY_RETNULL(request
.data
.username
, r_user
);
369 if (*user
== WB_AIX_ENCODED
) {
373 ret
= winbindd_request_response(WINBINDD_GETGROUPS
, &request
, &response
);
377 num_gids
= response
.data
.num_entries
;
378 gid_list
= (gid_t
*)response
.extra_data
.data
;
380 /* allocate a space large enough to contruct the string */
381 tmpbuf
= malloc(num_gids
*12);
386 for (idx
=i
=0; i
< num_gids
-1; i
++) {
387 idx
+= sprintf(tmpbuf
+idx
, "%u,", gid_list
[i
]);
389 idx
+= sprintf(tmpbuf
+idx
, "%u", gid_list
[i
]);
391 winbindd_free_response(&response
);
397 /* take a uid and return a filled struct passwd */
398 static struct passwd
*wb_aix_getpwuid(uid_t uid
)
400 struct winbindd_response response
;
401 struct winbindd_request request
;
405 logit("getpwuid '%d'\n", uid
);
407 ZERO_STRUCT(response
);
408 ZERO_STRUCT(request
);
410 request
.data
.uid
= uid
;
412 ret
= winbindd_request_response(WINBINDD_GETPWUID
, &request
, &response
);
416 pwd
= fill_pwent(&response
.data
.pw
);
418 winbindd_free_response(&response
);
420 logit("getpwuid gave ptr %p\n", pwd
);
426 /* take a username and return a filled struct passwd */
427 static struct passwd
*wb_aix_getpwnam(const char *name
)
429 struct winbindd_response response
;
430 struct winbindd_request request
;
434 if (*name
== WB_AIX_ENCODED
) {
435 return wb_aix_getpwuid(decode_id(name
));
438 logit("getpwnam '%s'\n", name
);
440 ZERO_STRUCT(response
);
441 ZERO_STRUCT(request
);
443 STRCPY_RETNULL(request
.data
.username
, name
);
445 ret
= winbindd_request_response(WINBINDD_GETPWNAM
, &request
, &response
);
449 pwd
= fill_pwent(&response
.data
.pw
);
451 winbindd_free_response(&response
);
453 logit("getpwnam gave ptr %p\n", pwd
);
461 static int wb_aix_lsuser(char *attributes
[], attrval_t results
[], int size
)
464 struct winbindd_request request
;
465 struct winbindd_response response
;
469 if (size
!= 1 || strcmp(attributes
[0], S_USERS
) != 0) {
470 logit("invalid lsuser op\n");
475 ZERO_STRUCT(request
);
476 ZERO_STRUCT(response
);
478 ret
= winbindd_request_response(WINBINDD_LIST_USERS
, &request
, &response
);
484 len
= strlen(response
.extra_data
.data
);
488 winbindd_free_response(&response
);
493 memcpy(s
, response
.extra_data
.data
, len
+1);
497 results
[0].attr_un
.au_char
= s
;
498 results
[0].attr_flag
= 0;
500 winbindd_free_response(&response
);
509 static int wb_aix_lsgroup(char *attributes
[], attrval_t results
[], int size
)
512 struct winbindd_request request
;
513 struct winbindd_response response
;
517 if (size
!= 1 || strcmp(attributes
[0], S_GROUPS
) != 0) {
518 logit("invalid lsgroup op\n");
523 ZERO_STRUCT(request
);
524 ZERO_STRUCT(response
);
526 ret
= winbindd_request_response(WINBINDD_LIST_GROUPS
, &request
, &response
);
532 len
= strlen(response
.extra_data
.data
);
536 winbindd_free_response(&response
);
541 memcpy(s
, response
.extra_data
.data
, len
+1);
545 results
[0].attr_un
.au_char
= s
;
546 results
[0].attr_flag
= 0;
548 winbindd_free_response(&response
);
554 static attrval_t
pwd_to_group(struct passwd
*pwd
)
557 struct group
*grp
= wb_aix_getgrgid(pwd
->pw_gid
);
560 r
.attr_flag
= EINVAL
;
563 r
.attr_un
.au_char
= strdup(grp
->gr_name
);
570 static attrval_t
pwd_to_groupsids(struct passwd
*pwd
)
575 if ( (s
= wb_aix_getgrset(pwd
->pw_name
)) == NULL
) {
576 r
.attr_flag
= EINVAL
;
580 if ( (p
= malloc(strlen(s
)+2)) == NULL
) {
581 r
.attr_flag
= ENOMEM
;
589 r
.attr_un
.au_char
= p
;
594 static attrval_t
pwd_to_sid(struct passwd
*pwd
)
596 struct winbindd_request request
;
597 struct winbindd_response response
;
600 ZERO_STRUCT(request
);
601 ZERO_STRUCT(response
);
603 request
.data
.uid
= pwd
->pw_uid
;
605 if (winbindd_request_response(WINBINDD_UID_TO_SID
, &request
, &response
) !=
606 NSS_STATUS_SUCCESS
) {
607 r
.attr_flag
= ENOENT
;
610 r
.attr_un
.au_char
= strdup(response
.data
.sid
.sid
);
616 static int wb_aix_user_attrib(const char *key
, char *attributes
[],
617 attrval_t results
[], int size
)
622 pwd
= wb_aix_getpwnam(key
);
628 for (i
=0;i
<size
;i
++) {
629 results
[i
].attr_flag
= 0;
631 if (strcmp(attributes
[i
], S_ID
) == 0) {
632 results
[i
].attr_un
.au_int
= pwd
->pw_uid
;
633 #ifdef _AIXVERSION_530
634 } else if (strcmp(attributes
[i
], S_PGID
) == 0) {
635 results
[i
].attr_un
.au_int
= pwd
->pw_gid
;
637 } else if (strcmp(attributes
[i
], S_PWD
) == 0) {
638 results
[i
].attr_un
.au_char
= strdup(pwd
->pw_passwd
);
639 } else if (strcmp(attributes
[i
], S_HOME
) == 0) {
640 results
[i
].attr_un
.au_char
= strdup(pwd
->pw_dir
);
641 } else if (strcmp(attributes
[i
], S_SHELL
) == 0) {
642 results
[i
].attr_un
.au_char
= strdup(pwd
->pw_shell
);
643 } else if (strcmp(attributes
[i
], S_REGISTRY
) == 0) {
644 results
[i
].attr_un
.au_char
= strdup("WINBIND");
645 } else if (strcmp(attributes
[i
], S_GECOS
) == 0) {
646 results
[i
].attr_un
.au_char
= strdup(pwd
->pw_gecos
);
647 } else if (strcmp(attributes
[i
], S_PGRP
) == 0) {
648 results
[i
] = pwd_to_group(pwd
);
649 } else if (strcmp(attributes
[i
], S_GROUPS
) == 0) {
650 results
[i
] = pwd_to_groupsids(pwd
);
651 } else if (strcmp(attributes
[i
], "SID") == 0) {
652 results
[i
] = pwd_to_sid(pwd
);
654 logit("Unknown user attribute '%s'\n", attributes
[i
]);
655 results
[i
].attr_flag
= EINVAL
;
664 static int wb_aix_group_attrib(const char *key
, char *attributes
[],
665 attrval_t results
[], int size
)
670 grp
= wb_aix_getgrnam(key
);
676 for (i
=0;i
<size
;i
++) {
677 results
[i
].attr_flag
= 0;
679 if (strcmp(attributes
[i
], S_PWD
) == 0) {
680 results
[i
].attr_un
.au_char
= strdup(grp
->gr_passwd
);
681 } else if (strcmp(attributes
[i
], S_ID
) == 0) {
682 results
[i
].attr_un
.au_int
= grp
->gr_gid
;
684 logit("Unknown group attribute '%s'\n", attributes
[i
]);
685 results
[i
].attr_flag
= EINVAL
;
696 called for user/group enumerations
698 static int wb_aix_getentry(char *key
, char *table
, char *attributes
[],
699 attrval_t results
[], int size
)
701 logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n",
702 key
, table
, size
, attributes
[0]);
704 if (strcmp(key
, "ALL") == 0 &&
705 strcmp(table
, "user") == 0) {
706 return wb_aix_lsuser(attributes
, results
, size
);
709 if (strcmp(key
, "ALL") == 0 &&
710 strcmp(table
, "group") == 0) {
711 return wb_aix_lsgroup(attributes
, results
, size
);
714 if (strcmp(table
, "user") == 0) {
715 return wb_aix_user_attrib(key
, attributes
, results
, size
);
718 if (strcmp(table
, "group") == 0) {
719 return wb_aix_group_attrib(key
, attributes
, results
, size
);
722 logit("Unknown getentry operation key='%s' table='%s'\n", key
, table
);
731 called to start the backend
733 static void *wb_aix_open(const char *name
, const char *domain
, int mode
, char *options
)
735 if (strstr(options
, "debug")) {
738 logit("open name='%s' mode=%d domain='%s' options='%s'\n", name
, domain
,
743 static void wb_aix_close(void *token
)
749 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
751 return a list of additional attributes supported by the backend
753 static attrlist_t
**wb_aix_attrlist(void)
755 /* pretty confusing but we are allocating the array of pointers
756 and the structures we'll be pointing to all at once. So
757 you need N+1 pointers and N structures. */
759 attrlist_t
**ret
= NULL
;
760 attrlist_t
*offset
= NULL
;
770 /* user attributes */
771 {S_ID
, AL_USERATTR
, SEC_INT
},
772 {S_PGRP
, AL_USERATTR
, SEC_CHAR
},
773 {S_HOME
, AL_USERATTR
, SEC_CHAR
},
774 {S_SHELL
, AL_USERATTR
, SEC_CHAR
},
775 #ifdef _AIXVERSION_530
776 {S_PGID
, AL_USERATTR
, SEC_INT
},
778 {S_GECOS
, AL_USERATTR
, SEC_CHAR
},
779 {S_SHELL
, AL_USERATTR
, SEC_CHAR
},
780 {S_PGRP
, AL_USERATTR
, SEC_CHAR
},
781 {S_GROUPS
, AL_USERATTR
, SEC_LIST
},
782 {"SID", AL_USERATTR
, SEC_CHAR
},
784 /* group attributes */
785 {S_ID
, AL_GROUPATTR
, SEC_INT
}
788 logit("method attrlist called\n");
790 n
= sizeof(attr_list
) / sizeof(struct attr_types
);
791 size
= (n
*sizeof(attrlist_t
*));
793 if ( (ret
= malloc( size
)) == NULL
) {
798 /* offset to where the structures start in the buffer */
800 offset
= (attrlist_t
*)(ret
+ n
);
802 /* now loop over the user_attr_list[] array and add
805 for ( i
=0; i
<n
; i
++ ) {
806 attrlist_t
*a
= malloc(sizeof(attrlist_t
));
809 /* this is bad. Just bail */
813 a
->al_name
= strdup(attr_list
[i
].name
);
814 a
->al_flags
= attr_list
[i
].flags
;
815 a
->al_type
= attr_list
[i
].type
;
827 turn a long username into a short one. Needed to cope with the 8 char
828 username limit in AIX 5.2 and below
830 static int wb_aix_normalize(char *longname
, char *shortname
)
834 logit("normalize '%s'\n", longname
);
836 /* automatically cope with AIX 5.3 with longer usernames
838 if (S_NAMELEN
> strlen(longname
)) {
839 strcpy(shortname
, longname
);
843 pwd
= wb_aix_getpwnam(longname
);
849 sprintf(shortname
, "%c%07u", WB_AIX_ENCODED
, pwd
->pw_uid
);
860 static int wb_aix_authenticate(char *user
, char *pass
,
861 int *reenter
, char **message
)
863 struct winbindd_request request
;
864 struct winbindd_response response
;
868 logit("authenticate '%s' response='%s'\n", user
, pass
);
873 /* Send off request */
874 ZERO_STRUCT(request
);
875 ZERO_STRUCT(response
);
877 if (*user
== WB_AIX_ENCODED
) {
878 r_user
= decode_user(r_user
);
880 return AUTH_NOTFOUND
;
884 STRCPY_RET(request
.data
.auth
.user
, r_user
);
885 STRCPY_RET(request
.data
.auth
.pass
, pass
);
887 if (*user
== WB_AIX_ENCODED
) {
891 result
= winbindd_request_response(WINBINDD_PAM_AUTH
, &request
, &response
);
893 winbindd_free_response(&response
);
895 logit("auth result %d for '%s'\n", result
, user
);
897 if (result
== NSS_STATUS_SUCCESS
) {
907 change a user password
909 static int wb_aix_chpass(char *user
, char *oldpass
, char *newpass
, char **message
)
911 struct winbindd_request request
;
912 struct winbindd_response response
;
916 if (*user
== WB_AIX_ENCODED
) {
917 r_user
= decode_user(r_user
);
924 logit("chpass '%s' old='%s' new='%s'\n", r_user
, oldpass
, newpass
);
928 /* Send off request */
929 ZERO_STRUCT(request
);
930 ZERO_STRUCT(response
);
932 STRCPY_RET(request
.data
.chauthtok
.user
, r_user
);
933 STRCPY_RET(request
.data
.chauthtok
.oldpass
, oldpass
);
934 STRCPY_RET(request
.data
.chauthtok
.newpass
, newpass
);
936 if (*user
== WB_AIX_ENCODED
) {
940 result
= winbindd_request_response(WINBINDD_PAM_CHAUTHTOK
, &request
, &response
);
942 winbindd_free_response(&response
);
944 if (result
== NSS_STATUS_SUCCESS
) {
954 don't do any password strength testing for now
956 static int wb_aix_passwdrestrictions(char *user
, char *newpass
, char *oldpass
,
959 logit("passwdresrictions called for '%s'\n", user
);
964 static int wb_aix_passwdexpired(char *user
, char **message
)
966 logit("passwdexpired '%s'\n", user
);
967 /* we should check the account bits here */
973 we can't return a crypt() password
975 static char *wb_aix_getpasswd(char *user
)
977 logit("getpasswd '%s'\n", user
);
983 this is called to update things like the last login time. We don't
984 currently pass this onto the DC
986 static int wb_aix_putentry(char *key
, char *table
, char *attributes
[],
987 attrval_t values
[], int size
)
989 logit("putentry key='%s' table='%s' attrib='%s'\n",
990 key
, table
, size
>=1?attributes
[0]:"<null>");
995 static int wb_aix_commit(char *key
, char *table
)
997 logit("commit key='%s' table='%s'\n");
1002 static int wb_aix_getgrusers(char *group
, void *result
, int type
, int *size
)
1004 logit("getgrusers group='%s'\n", group
);
1010 #define DECL_METHOD(x) \
1011 int method_ ## x(void) \
1013 logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
1018 #if LOG_UNIMPLEMENTED_CALLS
1019 DECL_METHOD(delgroup
);
1020 DECL_METHOD(deluser
);
1021 DECL_METHOD(newgroup
);
1022 DECL_METHOD(newuser
);
1023 DECL_METHOD(putgrent
);
1024 DECL_METHOD(putgrusers
);
1025 DECL_METHOD(putpwent
);
1027 DECL_METHOD(unlock
);
1028 DECL_METHOD(getcred
);
1029 DECL_METHOD(setcred
);
1030 DECL_METHOD(deletecred
);
1033 int wb_aix_init(struct secmethod_table
*methods
)
1035 ZERO_STRUCTP(methods
);
1037 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION
1038 methods
->method_version
= SECMETHOD_VERSION_520
;
1041 methods
->method_getgrgid
= wb_aix_getgrgid
;
1042 methods
->method_getgrnam
= wb_aix_getgrnam
;
1043 methods
->method_getgrset
= wb_aix_getgrset
;
1044 methods
->method_getpwnam
= wb_aix_getpwnam
;
1045 methods
->method_getpwuid
= wb_aix_getpwuid
;
1046 methods
->method_getentry
= wb_aix_getentry
;
1047 methods
->method_open
= wb_aix_open
;
1048 methods
->method_close
= wb_aix_close
;
1049 methods
->method_normalize
= wb_aix_normalize
;
1050 methods
->method_passwdexpired
= wb_aix_passwdexpired
;
1051 methods
->method_putentry
= wb_aix_putentry
;
1052 methods
->method_getpasswd
= wb_aix_getpasswd
;
1053 methods
->method_authenticate
= wb_aix_authenticate
;
1054 methods
->method_commit
= wb_aix_commit
;
1055 methods
->method_chpass
= wb_aix_chpass
;
1056 methods
->method_passwdrestrictions
= wb_aix_passwdrestrictions
;
1057 methods
->method_getgracct
= wb_aix_getgracct
;
1058 methods
->method_getgrusers
= wb_aix_getgrusers
;
1059 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
1060 methods
->method_attrlist
= wb_aix_attrlist
;
1063 #if LOG_UNIMPLEMENTED_CALLS
1064 methods
->method_delgroup
= method_delgroup
;
1065 methods
->method_deluser
= method_deluser
;
1066 methods
->method_newgroup
= method_newgroup
;
1067 methods
->method_newuser
= method_newuser
;
1068 methods
->method_putgrent
= method_putgrent
;
1069 methods
->method_putgrusers
= method_putgrusers
;
1070 methods
->method_putpwent
= method_putpwent
;
1071 methods
->method_lock
= method_lock
;
1072 methods
->method_unlock
= method_unlock
;
1073 methods
->method_getcred
= method_getcred
;
1074 methods
->method_setcred
= method_setcred
;
1075 methods
->method_deletecred
= method_deletecred
;
1078 return AUTH_SUCCESS
;