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 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.
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 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.
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
32 Note that this module also provides authentication and password
33 changing routines, so you do not need to install the winbind PAM
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
40 Many thanks to Julianne Haugh for explaining some of the finer
41 details of this interface.
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
48 #include "winbind_client.h"
51 /* enable this to log which entry points have not been
53 #define LOG_UNIMPLEMENTED_CALLS 0
56 #define WB_AIX_ENCODED '_'
58 static int debug_enabled
;
61 static void logit(const char *format
, ...)
68 f
= fopen("/tmp/WINBIND_DEBUG.log", "a");
71 vfprintf(f
, format
, ap
);
77 #define HANDLE_ERRORS(ret) do { \
78 if ((ret) == NSS_STATUS_NOTFOUND) { \
81 } else if ((ret) != NSS_STATUS_SUCCESS) { \
87 #define STRCPY_RET(dest, src) \
89 if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return -1; } \
93 #define STRCPY_RETNULL(dest, src) \
95 if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return NULL; } \
100 /* free a passwd structure */
101 static void free_pwd(struct passwd
*pwd
)
104 free(pwd
->pw_passwd
);
111 /* free a group structure */
112 static void free_grp(struct group
*grp
)
117 free(grp
->gr_passwd
);
124 for (i
=0; grp
->gr_mem
[i
]; i
++) {
125 free(grp
->gr_mem
[i
]);
133 /* replace commas with nulls, and null terminate */
134 static void replace_commas(char *s
)
137 for (p
=strchr(s
, ','); p
; p
= strchr(p
+1, ',')) {
142 p0
[strlen(p0
)+1] = 0;
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'
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
155 static unsigned decode_id(const char *name
)
158 sscanf(name
+1, "%u", &id
);
162 static struct passwd
*wb_aix_getpwuid(uid_t uid
);
164 static char *decode_user(const char *name
)
170 sscanf(name
+1, "%u", &id
);
171 pwd
= wb_aix_getpwuid(id
);
175 ret
= strdup(pwd
->pw_name
);
179 logit("decoded '%s' -> '%s'\n", name
, ret
);
186 fill a struct passwd from a winbindd_pw struct, allocating as a single block
188 static struct passwd
*fill_pwent(struct winbindd_pw
*pw
)
190 struct passwd
*result
;
192 result
= calloc(1, sizeof(struct passwd
));
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
);
211 fill a struct group from a winbindd_pw struct, allocating as a single block
213 static struct group
*fill_grent(struct winbindd_gr
*gr
, char *gr_mem
)
216 struct group
*result
;
219 result
= calloc(1, sizeof(struct group
));
225 result
->gr_gid
= gr
->gr_gid
;
227 result
->gr_name
= strdup(gr
->gr_name
);
228 result
->gr_passwd
= strdup(gr
->gr_passwd
);
230 /* Group membership */
231 if ((gr
->num_gr_mem
< 0) || !gr_mem
) {
235 if (gr
->num_gr_mem
== 0) {
240 result
->gr_mem
= (char **)malloc(sizeof(char *) * (gr
->num_gr_mem
+1));
241 if (!result
->gr_mem
) {
246 /* Start looking at extra data */
248 for (name
= strtok_r(gr_mem
, ",", &p
);
250 name
= strtok_r(NULL
, ",", &p
)) {
251 if (i
== gr
->num_gr_mem
) {
254 result
->gr_mem
[i
] = strdup(name
);
259 result
->gr_mem
[i
] = NULL
;
266 /* take a group id and return a filled struct group */
267 static struct group
*wb_aix_getgrgid(gid_t gid
)
269 struct winbindd_response response
;
270 struct winbindd_request request
;
274 logit("getgrgid %d\n", gid
);
276 ZERO_STRUCT(response
);
277 ZERO_STRUCT(request
);
279 request
.data
.gid
= gid
;
281 ret
= winbindd_request_response(WINBINDD_GETGRGID
, &request
, &response
);
283 logit("getgrgid ret=%d\n", ret
);
287 grp
= fill_grent(&response
.data
.gr
, response
.extra_data
.data
);
289 free_response(&response
);
294 /* take a group name and return a filled struct group */
295 static struct group
*wb_aix_getgrnam(const char *name
)
297 struct winbindd_response response
;
298 struct winbindd_request request
;
302 if (*name
== WB_AIX_ENCODED
) {
303 return wb_aix_getgrgid(decode_id(name
));
306 logit("getgrnam '%s'\n", name
);
308 ZERO_STRUCT(response
);
309 ZERO_STRUCT(request
);
311 STRCPY_RETNULL(request
.data
.groupname
, name
);
313 ret
= winbindd_request_response(WINBINDD_GETGRNAM
, &request
, &response
);
317 grp
= fill_grent(&response
.data
.gr
, response
.extra_data
.data
);
319 free_response(&response
);
325 /* this call doesn't have to fill in the gr_mem, but we do anyway
327 static struct group
*wb_aix_getgracct(void *id
, int type
)
330 return wb_aix_getgrnam((char *)id
);
333 return wb_aix_getgrgid(*(int *)id
);
340 /* take a username and return a string containing a comma-separated
341 list of group id numbers to which the user belongs */
342 static char *wb_aix_getgrset(char *user
)
344 struct winbindd_response response
;
345 struct winbindd_request request
;
353 if (*user
== WB_AIX_ENCODED
) {
354 r_user
= decode_user(r_user
);
361 logit("getgrset '%s'\n", r_user
);
363 ZERO_STRUCT(response
);
364 ZERO_STRUCT(request
);
366 STRCPY_RETNULL(request
.data
.username
, r_user
);
368 if (*user
== WB_AIX_ENCODED
) {
372 ret
= winbindd_request_response(WINBINDD_GETGROUPS
, &request
, &response
);
376 num_gids
= response
.data
.num_entries
;
377 gid_list
= (gid_t
*)response
.extra_data
.data
;
379 /* allocate a space large enough to contruct the string */
380 tmpbuf
= malloc(num_gids
*12);
385 for (idx
=i
=0; i
< num_gids
-1; i
++) {
386 idx
+= sprintf(tmpbuf
+idx
, "%u,", gid_list
[i
]);
388 idx
+= sprintf(tmpbuf
+idx
, "%u", gid_list
[i
]);
390 free_response(&response
);
396 /* take a uid and return a filled struct passwd */
397 static struct passwd
*wb_aix_getpwuid(uid_t uid
)
399 struct winbindd_response response
;
400 struct winbindd_request request
;
404 logit("getpwuid '%d'\n", uid
);
406 ZERO_STRUCT(response
);
407 ZERO_STRUCT(request
);
409 request
.data
.uid
= uid
;
411 ret
= winbindd_request_response(WINBINDD_GETPWUID
, &request
, &response
);
415 pwd
= fill_pwent(&response
.data
.pw
);
417 free_response(&response
);
419 logit("getpwuid gave ptr %p\n", pwd
);
425 /* take a username and return a filled struct passwd */
426 static struct passwd
*wb_aix_getpwnam(const char *name
)
428 struct winbindd_response response
;
429 struct winbindd_request request
;
433 if (*name
== WB_AIX_ENCODED
) {
434 return wb_aix_getpwuid(decode_id(name
));
437 logit("getpwnam '%s'\n", name
);
439 ZERO_STRUCT(response
);
440 ZERO_STRUCT(request
);
442 STRCPY_RETNULL(request
.data
.username
, name
);
444 ret
= winbindd_request_response(WINBINDD_GETPWNAM
, &request
, &response
);
448 pwd
= fill_pwent(&response
.data
.pw
);
450 free_response(&response
);
452 logit("getpwnam gave ptr %p\n", pwd
);
460 static int wb_aix_lsuser(char *attributes
[], attrval_t results
[], int size
)
463 struct winbindd_request request
;
464 struct winbindd_response response
;
468 if (size
!= 1 || strcmp(attributes
[0], S_USERS
) != 0) {
469 logit("invalid lsuser op\n");
474 ZERO_STRUCT(request
);
475 ZERO_STRUCT(response
);
477 ret
= winbindd_request_response(WINBINDD_LIST_USERS
, &request
, &response
);
483 len
= strlen(response
.extra_data
.data
);
487 free_response(&response
);
492 memcpy(s
, response
.extra_data
.data
, len
+1);
496 results
[0].attr_un
.au_char
= s
;
497 results
[0].attr_flag
= 0;
499 free_response(&response
);
508 static int wb_aix_lsgroup(char *attributes
[], attrval_t results
[], int size
)
511 struct winbindd_request request
;
512 struct winbindd_response response
;
516 if (size
!= 1 || strcmp(attributes
[0], S_GROUPS
) != 0) {
517 logit("invalid lsgroup op\n");
522 ZERO_STRUCT(request
);
523 ZERO_STRUCT(response
);
525 ret
= winbindd_request_response(WINBINDD_LIST_GROUPS
, &request
, &response
);
531 len
= strlen(response
.extra_data
.data
);
535 free_response(&response
);
540 memcpy(s
, response
.extra_data
.data
, len
+1);
544 results
[0].attr_un
.au_char
= s
;
545 results
[0].attr_flag
= 0;
547 free_response(&response
);
553 static attrval_t
pwd_to_group(struct passwd
*pwd
)
556 struct group
*grp
= wb_aix_getgrgid(pwd
->pw_gid
);
559 r
.attr_flag
= EINVAL
;
562 r
.attr_un
.au_char
= strdup(grp
->gr_name
);
569 static attrval_t
pwd_to_groupsids(struct passwd
*pwd
)
574 if ( (s
= wb_aix_getgrset(pwd
->pw_name
)) == NULL
) {
575 r
.attr_flag
= EINVAL
;
579 if ( (p
= malloc(strlen(s
)+2)) == NULL
) {
580 r
.attr_flag
= ENOMEM
;
588 r
.attr_un
.au_char
= p
;
593 static attrval_t
pwd_to_sid(struct passwd
*pwd
)
595 struct winbindd_request request
;
596 struct winbindd_response response
;
599 ZERO_STRUCT(request
);
600 ZERO_STRUCT(response
);
602 request
.data
.uid
= pwd
->pw_uid
;
604 if (winbindd_request_response(WINBINDD_UID_TO_SID
, &request
, &response
) !=
605 NSS_STATUS_SUCCESS
) {
606 r
.attr_flag
= ENOENT
;
609 r
.attr_un
.au_char
= strdup(response
.data
.sid
.sid
);
615 static int wb_aix_user_attrib(const char *key
, char *attributes
[],
616 attrval_t results
[], int size
)
621 pwd
= wb_aix_getpwnam(key
);
627 for (i
=0;i
<size
;i
++) {
628 results
[i
].attr_flag
= 0;
630 if (strcmp(attributes
[i
], S_ID
) == 0) {
631 results
[i
].attr_un
.au_int
= pwd
->pw_uid
;
632 #ifdef _AIXVERSION_530
633 } else if (strcmp(attributes
[i
], S_PGID
) == 0) {
634 results
[i
].attr_un
.au_int
= pwd
->pw_gid
;
636 } else if (strcmp(attributes
[i
], S_PWD
) == 0) {
637 results
[i
].attr_un
.au_char
= strdup(pwd
->pw_passwd
);
638 } else if (strcmp(attributes
[i
], S_HOME
) == 0) {
639 results
[i
].attr_un
.au_char
= strdup(pwd
->pw_dir
);
640 } else if (strcmp(attributes
[i
], S_SHELL
) == 0) {
641 results
[i
].attr_un
.au_char
= strdup(pwd
->pw_shell
);
642 } else if (strcmp(attributes
[i
], S_REGISTRY
) == 0) {
643 results
[i
].attr_un
.au_char
= strdup("WINBIND");
644 } else if (strcmp(attributes
[i
], S_GECOS
) == 0) {
645 results
[i
].attr_un
.au_char
= strdup(pwd
->pw_gecos
);
646 } else if (strcmp(attributes
[i
], S_PGRP
) == 0) {
647 results
[i
] = pwd_to_group(pwd
);
648 } else if (strcmp(attributes
[i
], S_GROUPS
) == 0) {
649 results
[i
] = pwd_to_groupsids(pwd
);
650 } else if (strcmp(attributes
[i
], "SID") == 0) {
651 results
[i
] = pwd_to_sid(pwd
);
653 logit("Unknown user attribute '%s'\n", attributes
[i
]);
654 results
[i
].attr_flag
= EINVAL
;
663 static int wb_aix_group_attrib(const char *key
, char *attributes
[],
664 attrval_t results
[], int size
)
669 grp
= wb_aix_getgrnam(key
);
675 for (i
=0;i
<size
;i
++) {
676 results
[i
].attr_flag
= 0;
678 if (strcmp(attributes
[i
], S_PWD
) == 0) {
679 results
[i
].attr_un
.au_char
= strdup(grp
->gr_passwd
);
680 } else if (strcmp(attributes
[i
], S_ID
) == 0) {
681 results
[i
].attr_un
.au_int
= grp
->gr_gid
;
683 logit("Unknown group attribute '%s'\n", attributes
[i
]);
684 results
[i
].attr_flag
= EINVAL
;
695 called for user/group enumerations
697 static int wb_aix_getentry(char *key
, char *table
, char *attributes
[],
698 attrval_t results
[], int size
)
700 logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n",
701 key
, table
, size
, attributes
[0]);
703 if (strcmp(key
, "ALL") == 0 &&
704 strcmp(table
, "user") == 0) {
705 return wb_aix_lsuser(attributes
, results
, size
);
708 if (strcmp(key
, "ALL") == 0 &&
709 strcmp(table
, "group") == 0) {
710 return wb_aix_lsgroup(attributes
, results
, size
);
713 if (strcmp(table
, "user") == 0) {
714 return wb_aix_user_attrib(key
, attributes
, results
, size
);
717 if (strcmp(table
, "group") == 0) {
718 return wb_aix_group_attrib(key
, attributes
, results
, size
);
721 logit("Unknown getentry operation key='%s' table='%s'\n", key
, table
);
730 called to start the backend
732 static void *wb_aix_open(const char *name
, const char *domain
, int mode
, char *options
)
734 if (strstr(options
, "debug")) {
737 logit("open name='%s' mode=%d domain='%s' options='%s'\n", name
, domain
,
742 static void wb_aix_close(void *token
)
748 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
750 return a list of additional attributes supported by the backend
752 static attrlist_t
**wb_aix_attrlist(void)
754 /* pretty confusing but we are allocating the array of pointers
755 and the structures we'll be pointing to all at once. So
756 you need N+1 pointers and N structures. */
758 attrlist_t
**ret
= NULL
;
759 attrlist_t
*offset
= NULL
;
769 /* user attributes */
770 {S_ID
, AL_USERATTR
, SEC_INT
},
771 {S_PGRP
, AL_USERATTR
, SEC_CHAR
},
772 {S_HOME
, AL_USERATTR
, SEC_CHAR
},
773 {S_SHELL
, AL_USERATTR
, SEC_CHAR
},
774 #ifdef _AIXVERSION_530
775 {S_PGID
, AL_USERATTR
, SEC_INT
},
777 {S_GECOS
, AL_USERATTR
, SEC_CHAR
},
778 {S_SHELL
, AL_USERATTR
, SEC_CHAR
},
779 {S_PGRP
, AL_USERATTR
, SEC_CHAR
},
780 {S_GROUPS
, AL_USERATTR
, SEC_LIST
},
781 {"SID", AL_USERATTR
, SEC_CHAR
},
783 /* group attributes */
784 {S_ID
, AL_GROUPATTR
, SEC_INT
}
787 logit("method attrlist called\n");
789 n
= sizeof(attr_list
) / sizeof(struct attr_types
);
790 size
= (n
*sizeof(attrlist_t
*));
792 if ( (ret
= malloc( size
)) == NULL
) {
797 /* offset to where the structures start in the buffer */
799 offset
= (attrlist_t
*)(ret
+ n
);
801 /* now loop over the user_attr_list[] array and add
804 for ( i
=0; i
<n
; i
++ ) {
805 attrlist_t
*a
= malloc(sizeof(attrlist_t
));
808 /* this is bad. Just bail */
812 a
->al_name
= strdup(attr_list
[i
].name
);
813 a
->al_flags
= attr_list
[i
].flags
;
814 a
->al_type
= attr_list
[i
].type
;
826 turn a long username into a short one. Needed to cope with the 8 char
827 username limit in AIX 5.2 and below
829 static int wb_aix_normalize(char *longname
, char *shortname
)
833 logit("normalize '%s'\n", longname
);
835 /* automatically cope with AIX 5.3 with longer usernames
837 if (S_NAMELEN
> strlen(longname
)) {
838 strcpy(shortname
, longname
);
842 pwd
= wb_aix_getpwnam(longname
);
848 sprintf(shortname
, "%c%07u", WB_AIX_ENCODED
, pwd
->pw_uid
);
859 static int wb_aix_authenticate(char *user
, char *pass
,
860 int *reenter
, char **message
)
862 struct winbindd_request request
;
863 struct winbindd_response response
;
867 logit("authenticate '%s' response='%s'\n", user
, pass
);
872 /* Send off request */
873 ZERO_STRUCT(request
);
874 ZERO_STRUCT(response
);
876 if (*user
== WB_AIX_ENCODED
) {
877 r_user
= decode_user(r_user
);
879 return AUTH_NOTFOUND
;
883 STRCPY_RET(request
.data
.auth
.user
, r_user
);
884 STRCPY_RET(request
.data
.auth
.pass
, pass
);
886 if (*user
== WB_AIX_ENCODED
) {
890 result
= winbindd_request_response(WINBINDD_PAM_AUTH
, &request
, &response
);
892 free_response(&response
);
894 logit("auth result %d for '%s'\n", result
, user
);
896 if (result
== NSS_STATUS_SUCCESS
) {
906 change a user password
908 static int wb_aix_chpass(char *user
, char *oldpass
, char *newpass
, char **message
)
910 struct winbindd_request request
;
911 struct winbindd_response response
;
915 if (*user
== WB_AIX_ENCODED
) {
916 r_user
= decode_user(r_user
);
923 logit("chpass '%s' old='%s' new='%s'\n", r_user
, oldpass
, newpass
);
927 /* Send off request */
928 ZERO_STRUCT(request
);
929 ZERO_STRUCT(response
);
931 STRCPY_RET(request
.data
.chauthtok
.user
, r_user
);
932 STRCPY_RET(request
.data
.chauthtok
.oldpass
, oldpass
);
933 STRCPY_RET(request
.data
.chauthtok
.newpass
, newpass
);
935 if (*user
== WB_AIX_ENCODED
) {
939 result
= winbindd_request_response(WINBINDD_PAM_CHAUTHTOK
, &request
, &response
);
941 free_response(&response
);
943 if (result
== NSS_STATUS_SUCCESS
) {
953 don't do any password strength testing for now
955 static int wb_aix_passwdrestrictions(char *user
, char *newpass
, char *oldpass
,
958 logit("passwdresrictions called for '%s'\n", user
);
963 static int wb_aix_passwdexpired(char *user
, char **message
)
965 logit("passwdexpired '%s'\n", user
);
966 /* we should check the account bits here */
972 we can't return a crypt() password
974 static char *wb_aix_getpasswd(char *user
)
976 logit("getpasswd '%s'\n", user
);
982 this is called to update things like the last login time. We don't
983 currently pass this onto the DC
985 static int wb_aix_putentry(char *key
, char *table
, char *attributes
[],
986 attrval_t values
[], int size
)
988 logit("putentry key='%s' table='%s' attrib='%s'\n",
989 key
, table
, size
>=1?attributes
[0]:"<null>");
994 static int wb_aix_commit(char *key
, char *table
)
996 logit("commit key='%s' table='%s'\n");
1001 static int wb_aix_getgrusers(char *group
, void *result
, int type
, int *size
)
1003 logit("getgrusers group='%s'\n", group
);
1009 #define DECL_METHOD(x) \
1010 int method_ ## x(void) \
1012 logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
1017 #if LOG_UNIMPLEMENTED_CALLS
1018 DECL_METHOD(delgroup
);
1019 DECL_METHOD(deluser
);
1020 DECL_METHOD(newgroup
);
1021 DECL_METHOD(newuser
);
1022 DECL_METHOD(putgrent
);
1023 DECL_METHOD(putgrusers
);
1024 DECL_METHOD(putpwent
);
1026 DECL_METHOD(unlock
);
1027 DECL_METHOD(getcred
);
1028 DECL_METHOD(setcred
);
1029 DECL_METHOD(deletecred
);
1032 int wb_aix_init(struct secmethod_table
*methods
)
1034 ZERO_STRUCTP(methods
);
1036 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION
1037 methods
->method_version
= SECMETHOD_VERSION_520
;
1040 methods
->method_getgrgid
= wb_aix_getgrgid
;
1041 methods
->method_getgrnam
= wb_aix_getgrnam
;
1042 methods
->method_getgrset
= wb_aix_getgrset
;
1043 methods
->method_getpwnam
= wb_aix_getpwnam
;
1044 methods
->method_getpwuid
= wb_aix_getpwuid
;
1045 methods
->method_getentry
= wb_aix_getentry
;
1046 methods
->method_open
= wb_aix_open
;
1047 methods
->method_close
= wb_aix_close
;
1048 methods
->method_normalize
= wb_aix_normalize
;
1049 methods
->method_passwdexpired
= wb_aix_passwdexpired
;
1050 methods
->method_putentry
= wb_aix_putentry
;
1051 methods
->method_getpasswd
= wb_aix_getpasswd
;
1052 methods
->method_authenticate
= wb_aix_authenticate
;
1053 methods
->method_commit
= wb_aix_commit
;
1054 methods
->method_chpass
= wb_aix_chpass
;
1055 methods
->method_passwdrestrictions
= wb_aix_passwdrestrictions
;
1056 methods
->method_getgracct
= wb_aix_getgracct
;
1057 methods
->method_getgrusers
= wb_aix_getgrusers
;
1058 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
1059 methods
->method_attrlist
= wb_aix_attrlist
;
1062 #if LOG_UNIMPLEMENTED_CALLS
1063 methods
->method_delgroup
= method_delgroup
;
1064 methods
->method_deluser
= method_deluser
;
1065 methods
->method_newgroup
= method_newgroup
;
1066 methods
->method_newuser
= method_newuser
;
1067 methods
->method_putgrent
= method_putgrent
;
1068 methods
->method_putgrusers
= method_putgrusers
;
1069 methods
->method_putpwent
= method_putpwent
;
1070 methods
->method_lock
= method_lock
;
1071 methods
->method_unlock
= method_unlock
;
1072 methods
->method_getcred
= method_getcred
;
1073 methods
->method_setcred
= method_setcred
;
1074 methods
->method_deletecred
= method_deletecred
;
1077 return AUTH_SUCCESS
;