xref: /freebsd/lib/nss_tacplus/nss_tacplus.c (revision 56b74a2d856c4d65a4b5c72d1352067b6b469d3b)
16c5cdba1SDag-Erling Smørgrav /*-
26c5cdba1SDag-Erling Smørgrav  * Copyright (c) 2023 Klara, Inc.
36c5cdba1SDag-Erling Smørgrav  *
46c5cdba1SDag-Erling Smørgrav  * SPDX-License-Identifier: BSD-2-Clause
56c5cdba1SDag-Erling Smørgrav  */
66c5cdba1SDag-Erling Smørgrav 
76c5cdba1SDag-Erling Smørgrav #include <sys/param.h>
86c5cdba1SDag-Erling Smørgrav #include <sys/limits.h>
96c5cdba1SDag-Erling Smørgrav 
106c5cdba1SDag-Erling Smørgrav #include <errno.h>
116c5cdba1SDag-Erling Smørgrav #include <inttypes.h>
126c5cdba1SDag-Erling Smørgrav #include <pthread.h>
136c5cdba1SDag-Erling Smørgrav #include <pthread_np.h>
146c5cdba1SDag-Erling Smørgrav #include <stdarg.h>
156c5cdba1SDag-Erling Smørgrav #include <stdlib.h>
166c5cdba1SDag-Erling Smørgrav #include <string.h>
176c5cdba1SDag-Erling Smørgrav #include <syslog.h>
186c5cdba1SDag-Erling Smørgrav 
196c5cdba1SDag-Erling Smørgrav #include <nsswitch.h>
206c5cdba1SDag-Erling Smørgrav #include <pwd.h>
216c5cdba1SDag-Erling Smørgrav #include <taclib.h>
226c5cdba1SDag-Erling Smørgrav 
236c5cdba1SDag-Erling Smørgrav extern int __isthreaded;
246c5cdba1SDag-Erling Smørgrav 
256c5cdba1SDag-Erling Smørgrav #define	DEF_UID		65534
266c5cdba1SDag-Erling Smørgrav #define	DEF_GID		65534
27246aec9aSDag-Erling Smørgrav #define	DEF_CLASS	""
286c5cdba1SDag-Erling Smørgrav #define	DEF_DIR		"/"
296c5cdba1SDag-Erling Smørgrav #define	DEF_SHELL	"/bin/sh"
306c5cdba1SDag-Erling Smørgrav 
316c5cdba1SDag-Erling Smørgrav ns_mtab *nss_module_register(const char *, unsigned int *,
326c5cdba1SDag-Erling Smørgrav     nss_module_unregister_fn *);
336c5cdba1SDag-Erling Smørgrav 
346c5cdba1SDag-Erling Smørgrav static void
tacplus_error(struct tac_handle * h,const char * func)356c5cdba1SDag-Erling Smørgrav tacplus_error(struct tac_handle *h, const char *func)
366c5cdba1SDag-Erling Smørgrav {
376c5cdba1SDag-Erling Smørgrav 	if (h == NULL)
386c5cdba1SDag-Erling Smørgrav 		syslog(LOG_ERR, "%s(): %m", func);
396c5cdba1SDag-Erling Smørgrav 	else
406c5cdba1SDag-Erling Smørgrav 		syslog(LOG_ERR, "%s(): %s", func, tac_strerror(h));
416c5cdba1SDag-Erling Smørgrav }
426c5cdba1SDag-Erling Smørgrav 
436c5cdba1SDag-Erling Smørgrav static pthread_key_t tacplus_key;
446c5cdba1SDag-Erling Smørgrav 
456c5cdba1SDag-Erling Smørgrav static void
tacplus_fini(void * p)466c5cdba1SDag-Erling Smørgrav tacplus_fini(void *p)
476c5cdba1SDag-Erling Smørgrav {
486c5cdba1SDag-Erling Smørgrav 	struct tac_handle **h = p;
496c5cdba1SDag-Erling Smørgrav 
506c5cdba1SDag-Erling Smørgrav 	tac_close(*h);
516c5cdba1SDag-Erling Smørgrav 	free(h);
526c5cdba1SDag-Erling Smørgrav }
536c5cdba1SDag-Erling Smørgrav 
546c5cdba1SDag-Erling Smørgrav static void
tacplus_keyinit(void)556c5cdba1SDag-Erling Smørgrav tacplus_keyinit(void)
566c5cdba1SDag-Erling Smørgrav {
576c5cdba1SDag-Erling Smørgrav 	(void)pthread_key_create(&tacplus_key, tacplus_fini);
586c5cdba1SDag-Erling Smørgrav }
596c5cdba1SDag-Erling Smørgrav 
606c5cdba1SDag-Erling Smørgrav static struct tac_handle *
tacplus_get_handle(void)616c5cdba1SDag-Erling Smørgrav tacplus_get_handle(void)
626c5cdba1SDag-Erling Smørgrav {
636c5cdba1SDag-Erling Smørgrav 	static pthread_once_t keyinit = PTHREAD_ONCE_INIT;
646c5cdba1SDag-Erling Smørgrav 	static struct tac_handle *sth;
656c5cdba1SDag-Erling Smørgrav 	struct tac_handle **h = &sth;
666c5cdba1SDag-Erling Smørgrav 	int ret;
676c5cdba1SDag-Erling Smørgrav 
686c5cdba1SDag-Erling Smørgrav 	if (__isthreaded && !pthread_main_np()) {
696c5cdba1SDag-Erling Smørgrav 		if ((ret = pthread_once(&keyinit, tacplus_keyinit)) != 0)
706c5cdba1SDag-Erling Smørgrav 			return (NULL);
716c5cdba1SDag-Erling Smørgrav 		if ((h = pthread_getspecific(tacplus_key)) == NULL) {
726c5cdba1SDag-Erling Smørgrav 			if ((h = calloc(1, sizeof(*h))) == NULL)
736c5cdba1SDag-Erling Smørgrav 				return (NULL);
746c5cdba1SDag-Erling Smørgrav 			if ((pthread_setspecific(tacplus_key, h)) != 0) {
756c5cdba1SDag-Erling Smørgrav 				free(h);
766c5cdba1SDag-Erling Smørgrav 				return (NULL);
776c5cdba1SDag-Erling Smørgrav 			}
786c5cdba1SDag-Erling Smørgrav 		}
796c5cdba1SDag-Erling Smørgrav 	}
806c5cdba1SDag-Erling Smørgrav 	if (*h == NULL) {
816c5cdba1SDag-Erling Smørgrav 		if ((*h = tac_open()) == NULL) {
826c5cdba1SDag-Erling Smørgrav 			tacplus_error(*h, "tac_open");
836c5cdba1SDag-Erling Smørgrav 			return (NULL);
846c5cdba1SDag-Erling Smørgrav 		}
856c5cdba1SDag-Erling Smørgrav 		if (tac_config(*h, NULL) != 0) {
866c5cdba1SDag-Erling Smørgrav 			tacplus_error(*h, "tac_config");
876c5cdba1SDag-Erling Smørgrav 			tac_close(*h);
886c5cdba1SDag-Erling Smørgrav 			*h = NULL;
896c5cdba1SDag-Erling Smørgrav 			return (NULL);
906c5cdba1SDag-Erling Smørgrav 		}
916c5cdba1SDag-Erling Smørgrav 	}
926c5cdba1SDag-Erling Smørgrav 	return (*h);
936c5cdba1SDag-Erling Smørgrav }
946c5cdba1SDag-Erling Smørgrav 
956c5cdba1SDag-Erling Smørgrav static char *
tacplus_copystr(const char * str,char ** buffer,size_t * bufsize)966c5cdba1SDag-Erling Smørgrav tacplus_copystr(const char *str, char **buffer, size_t *bufsize)
976c5cdba1SDag-Erling Smørgrav {
986c5cdba1SDag-Erling Smørgrav 	char *copy = *buffer;
996c5cdba1SDag-Erling Smørgrav 	size_t len = strlen(str) + 1;
1006c5cdba1SDag-Erling Smørgrav 
1016c5cdba1SDag-Erling Smørgrav 	if (len > *bufsize) {
1026c5cdba1SDag-Erling Smørgrav 		errno = ERANGE;
1036c5cdba1SDag-Erling Smørgrav 		return (NULL);
1046c5cdba1SDag-Erling Smørgrav 	}
1056c5cdba1SDag-Erling Smørgrav 	memcpy(copy, str, len);
1066c5cdba1SDag-Erling Smørgrav 	*buffer += len;
1076c5cdba1SDag-Erling Smørgrav 	*bufsize -= len;
1086c5cdba1SDag-Erling Smørgrav 	return (copy);
1096c5cdba1SDag-Erling Smørgrav }
1106c5cdba1SDag-Erling Smørgrav 
1116c5cdba1SDag-Erling Smørgrav static int
tacplus_getpwnam_r(const char * name,struct passwd * pwd,char * buffer,size_t bufsize)1126c5cdba1SDag-Erling Smørgrav tacplus_getpwnam_r(const char *name, struct passwd *pwd, char *buffer,
1136c5cdba1SDag-Erling Smørgrav     size_t bufsize)
1146c5cdba1SDag-Erling Smørgrav {
1156c5cdba1SDag-Erling Smørgrav 	struct tac_handle *h;
1166c5cdba1SDag-Erling Smørgrav 	char *av, *key, *value, *end;
1176c5cdba1SDag-Erling Smørgrav 	intmax_t num;
1186c5cdba1SDag-Erling Smørgrav 	int i, ret;
1196c5cdba1SDag-Erling Smørgrav 
1206c5cdba1SDag-Erling Smørgrav 	if ((h = tacplus_get_handle()) == NULL)
1216c5cdba1SDag-Erling Smørgrav 		return (NS_UNAVAIL);
1226c5cdba1SDag-Erling Smørgrav 	ret = tac_create_author(h, TAC_AUTHEN_METH_NOT_SET,
1236c5cdba1SDag-Erling Smørgrav 	    TAC_AUTHEN_TYPE_NOT_SET, TAC_AUTHEN_SVC_LOGIN);
1246c5cdba1SDag-Erling Smørgrav 	if (ret < 0) {
1256c5cdba1SDag-Erling Smørgrav 		tacplus_error(h, "tac_create_author");
1266c5cdba1SDag-Erling Smørgrav 		return (NS_TRYAGAIN);
1276c5cdba1SDag-Erling Smørgrav 	}
1286c5cdba1SDag-Erling Smørgrav 	if (tac_set_user(h, name) < 0) {
1296c5cdba1SDag-Erling Smørgrav 		tacplus_error(h, "tac_set_user");
1306c5cdba1SDag-Erling Smørgrav 		return (NS_TRYAGAIN);
1316c5cdba1SDag-Erling Smørgrav 	}
1326c5cdba1SDag-Erling Smørgrav 	if (tac_set_av(h, 0, "service=shell") < 0) {
1336c5cdba1SDag-Erling Smørgrav 		tacplus_error(h, "tac_set_av");
1346c5cdba1SDag-Erling Smørgrav 		return (NS_TRYAGAIN);
1356c5cdba1SDag-Erling Smørgrav 	}
1366c5cdba1SDag-Erling Smørgrav 	ret = tac_send_author(h);
1376c5cdba1SDag-Erling Smørgrav 	switch (TAC_AUTHOR_STATUS(ret)) {
1386c5cdba1SDag-Erling Smørgrav 	case TAC_AUTHOR_STATUS_PASS_ADD:
1396c5cdba1SDag-Erling Smørgrav 	case TAC_AUTHOR_STATUS_PASS_REPL:
1406c5cdba1SDag-Erling Smørgrav 		/* found */
1416c5cdba1SDag-Erling Smørgrav 		break;
1426c5cdba1SDag-Erling Smørgrav 	case TAC_AUTHOR_STATUS_FAIL:
1436c5cdba1SDag-Erling Smørgrav 		return (NS_NOTFOUND);
1446c5cdba1SDag-Erling Smørgrav 	case TAC_AUTHOR_STATUS_ERROR:
1456c5cdba1SDag-Erling Smørgrav 		return (NS_UNAVAIL);
1466c5cdba1SDag-Erling Smørgrav 	default:
1476c5cdba1SDag-Erling Smørgrav 		tacplus_error(h, "tac_send_author");
1486c5cdba1SDag-Erling Smørgrav 		return (NS_UNAVAIL);
1496c5cdba1SDag-Erling Smørgrav 	}
1506c5cdba1SDag-Erling Smørgrav 	memset(pwd, 0, sizeof(*pwd));
1516c5cdba1SDag-Erling Smørgrav 
1526c5cdba1SDag-Erling Smørgrav 	/* copy name */
1536c5cdba1SDag-Erling Smørgrav 	pwd->pw_name = tacplus_copystr(name, &buffer, &bufsize);
1546c5cdba1SDag-Erling Smørgrav 	if (pwd->pw_name == NULL)
1556c5cdba1SDag-Erling Smørgrav 		return (NS_RETURN);
1566c5cdba1SDag-Erling Smørgrav 
1576c5cdba1SDag-Erling Smørgrav 	/* no password */
1586c5cdba1SDag-Erling Smørgrav 	pwd->pw_passwd = tacplus_copystr("*", &buffer, &bufsize);
1596c5cdba1SDag-Erling Smørgrav 	if (2 > bufsize)
1606c5cdba1SDag-Erling Smørgrav 		return (NS_RETURN);
1616c5cdba1SDag-Erling Smørgrav 
1626c5cdba1SDag-Erling Smørgrav 	/* default uid and gid */
1636c5cdba1SDag-Erling Smørgrav 	pwd->pw_uid = DEF_UID;
1646c5cdba1SDag-Erling Smørgrav 	pwd->pw_gid = DEF_GID;
1656c5cdba1SDag-Erling Smørgrav 
1666c5cdba1SDag-Erling Smørgrav 	/* get attribute-value pairs from TACACS+ response */
1676c5cdba1SDag-Erling Smørgrav 	for (i = 0; i < TAC_AUTHEN_AV_COUNT(ret); i++) {
1686c5cdba1SDag-Erling Smørgrav 		if ((av = tac_get_av(h, i)) == NULL) {
1696c5cdba1SDag-Erling Smørgrav 			tacplus_error(h, "tac_get_av");
1706c5cdba1SDag-Erling Smørgrav 			return (NS_UNAVAIL);
1716c5cdba1SDag-Erling Smørgrav 		}
1726c5cdba1SDag-Erling Smørgrav 		key = av;
1736c5cdba1SDag-Erling Smørgrav 		if ((value = strchr(av, '=')) == NULL) {
1746c5cdba1SDag-Erling Smørgrav 			free(av);
1756c5cdba1SDag-Erling Smørgrav 			return (NS_RETURN);
1766c5cdba1SDag-Erling Smørgrav 		}
1776c5cdba1SDag-Erling Smørgrav 		*value++ = '\0';
1786c5cdba1SDag-Erling Smørgrav 		if (strcasecmp(key, "uid") == 0) {
1796c5cdba1SDag-Erling Smørgrav 			num = strtoimax(value, &end, 10);
1806c5cdba1SDag-Erling Smørgrav 			if (end == value || *end != '\0' ||
1816c5cdba1SDag-Erling Smørgrav 			    num < 0 || num > (intmax_t)UID_MAX) {
1826c5cdba1SDag-Erling Smørgrav 				errno = EINVAL;
1836c5cdba1SDag-Erling Smørgrav 				free(av);
1846c5cdba1SDag-Erling Smørgrav 				return (NS_RETURN);
1856c5cdba1SDag-Erling Smørgrav 			}
1866c5cdba1SDag-Erling Smørgrav 			pwd->pw_uid = num;
1876c5cdba1SDag-Erling Smørgrav 		} else if (strcasecmp(key, "gid") == 0) {
1886c5cdba1SDag-Erling Smørgrav 			num = strtoimax(value, &end, 10);
1896c5cdba1SDag-Erling Smørgrav 			if (end == value || *end != '\0' ||
1906c5cdba1SDag-Erling Smørgrav 			    num < 0 || num > (intmax_t)GID_MAX) {
1916c5cdba1SDag-Erling Smørgrav 				errno = EINVAL;
1926c5cdba1SDag-Erling Smørgrav 				free(av);
1936c5cdba1SDag-Erling Smørgrav 				return (NS_RETURN);
1946c5cdba1SDag-Erling Smørgrav 			}
1956c5cdba1SDag-Erling Smørgrav 			pwd->pw_gid = num;
196246aec9aSDag-Erling Smørgrav 		} else if (strcasecmp(av, "class") == 0) {
197246aec9aSDag-Erling Smørgrav 			pwd->pw_class = tacplus_copystr(value, &buffer,
198246aec9aSDag-Erling Smørgrav 			    &bufsize);
199246aec9aSDag-Erling Smørgrav 			if (pwd->pw_class == NULL) {
200246aec9aSDag-Erling Smørgrav 				free(av);
201246aec9aSDag-Erling Smørgrav 				return (NS_RETURN);
202246aec9aSDag-Erling Smørgrav 			}
2036c5cdba1SDag-Erling Smørgrav 		} else if (strcasecmp(av, "gecos") == 0) {
2046c5cdba1SDag-Erling Smørgrav 			pwd->pw_gecos = tacplus_copystr(value, &buffer,
2056c5cdba1SDag-Erling Smørgrav 			    &bufsize);
2066c5cdba1SDag-Erling Smørgrav 			if (pwd->pw_gecos == NULL) {
2076c5cdba1SDag-Erling Smørgrav 				free(av);
2086c5cdba1SDag-Erling Smørgrav 				return (NS_RETURN);
2096c5cdba1SDag-Erling Smørgrav 			}
2106c5cdba1SDag-Erling Smørgrav 		} else if (strcasecmp(av, "home") == 0) {
2116c5cdba1SDag-Erling Smørgrav 			pwd->pw_dir = tacplus_copystr(value, &buffer,
2126c5cdba1SDag-Erling Smørgrav 			    &bufsize);
2136c5cdba1SDag-Erling Smørgrav 			if (pwd->pw_dir == NULL) {
2146c5cdba1SDag-Erling Smørgrav 				free(av);
2156c5cdba1SDag-Erling Smørgrav 				return (NS_RETURN);
2166c5cdba1SDag-Erling Smørgrav 			}
2176c5cdba1SDag-Erling Smørgrav 		} else if (strcasecmp(av, "shell") == 0) {
2186c5cdba1SDag-Erling Smørgrav 			pwd->pw_shell = tacplus_copystr(value, &buffer,
2196c5cdba1SDag-Erling Smørgrav 			    &bufsize);
2206c5cdba1SDag-Erling Smørgrav 			if (pwd->pw_shell == NULL) {
2216c5cdba1SDag-Erling Smørgrav 				free(av);
2226c5cdba1SDag-Erling Smørgrav 				return (NS_RETURN);
2236c5cdba1SDag-Erling Smørgrav 			}
2246c5cdba1SDag-Erling Smørgrav 		}
2256c5cdba1SDag-Erling Smørgrav 		free(av);
2266c5cdba1SDag-Erling Smørgrav 	}
2276c5cdba1SDag-Erling Smørgrav 
228246aec9aSDag-Erling Smørgrav 	/* default class if none was provided */
229246aec9aSDag-Erling Smørgrav 	if (pwd->pw_class == NULL)
230246aec9aSDag-Erling Smørgrav 		pwd->pw_class = tacplus_copystr(DEF_CLASS, &buffer, &bufsize);
231246aec9aSDag-Erling Smørgrav 
2326c5cdba1SDag-Erling Smørgrav 	/* gecos equal to name if none was provided */
2336c5cdba1SDag-Erling Smørgrav 	if (pwd->pw_gecos == NULL)
2346c5cdba1SDag-Erling Smørgrav 		pwd->pw_gecos = pwd->pw_name;
2356c5cdba1SDag-Erling Smørgrav 
2366c5cdba1SDag-Erling Smørgrav 	/* default home directory if none was provided */
2376c5cdba1SDag-Erling Smørgrav 	if (pwd->pw_dir == NULL)
2386c5cdba1SDag-Erling Smørgrav 		pwd->pw_dir = tacplus_copystr(DEF_DIR, &buffer, &bufsize);
2396c5cdba1SDag-Erling Smørgrav 	if (pwd->pw_dir == NULL)
2406c5cdba1SDag-Erling Smørgrav 		return (NS_RETURN);
2416c5cdba1SDag-Erling Smørgrav 
2426c5cdba1SDag-Erling Smørgrav 	/* default shell if none was provided */
2436c5cdba1SDag-Erling Smørgrav 	if (pwd->pw_shell == NULL)
2446c5cdba1SDag-Erling Smørgrav 		pwd->pw_shell = tacplus_copystr(DEF_SHELL, &buffer, &bufsize);
2456c5cdba1SDag-Erling Smørgrav 	if (pwd->pw_shell == NULL)
2466c5cdba1SDag-Erling Smørgrav 		return (NS_RETURN);
2476c5cdba1SDag-Erling Smørgrav 
2486c5cdba1SDag-Erling Smørgrav 	/* done! */
2496c5cdba1SDag-Erling Smørgrav 	return (NS_SUCCESS);
2506c5cdba1SDag-Erling Smørgrav }
2516c5cdba1SDag-Erling Smørgrav 
2526c5cdba1SDag-Erling Smørgrav static int
nss_tacplus_getpwnam_r(void * retval,void * mdata __unused,va_list ap)2536c5cdba1SDag-Erling Smørgrav nss_tacplus_getpwnam_r(void *retval, void *mdata __unused, va_list ap)
2546c5cdba1SDag-Erling Smørgrav {
2556c5cdba1SDag-Erling Smørgrav 	char *name = va_arg(ap, char *);
2566c5cdba1SDag-Erling Smørgrav 	struct passwd *pwd = va_arg(ap, struct passwd *);
2576c5cdba1SDag-Erling Smørgrav 	char *buffer = va_arg(ap, char *);
2586c5cdba1SDag-Erling Smørgrav 	size_t bufsize = va_arg(ap, size_t);
2596c5cdba1SDag-Erling Smørgrav 	int *result = va_arg(ap, int *);
2606c5cdba1SDag-Erling Smørgrav 	int ret;
2616c5cdba1SDag-Erling Smørgrav 
2626c5cdba1SDag-Erling Smørgrav 	errno = 0;
2636c5cdba1SDag-Erling Smørgrav 	ret = tacplus_getpwnam_r(name, pwd, buffer, bufsize);
2646c5cdba1SDag-Erling Smørgrav 	if (ret == NS_SUCCESS) {
2656c5cdba1SDag-Erling Smørgrav 		*(void **)retval = pwd;
2666c5cdba1SDag-Erling Smørgrav 		*result = 0;
2676c5cdba1SDag-Erling Smørgrav 	} else {
2686c5cdba1SDag-Erling Smørgrav 		*(void **)retval = NULL;
2696c5cdba1SDag-Erling Smørgrav 		*result = errno;
2706c5cdba1SDag-Erling Smørgrav 	}
2716c5cdba1SDag-Erling Smørgrav 	return (ret);
2726c5cdba1SDag-Erling Smørgrav }
2736c5cdba1SDag-Erling Smørgrav 
274*56b74a2dSDag-Erling Smørgrav static int
nss_tacplus_setpwent(void * retval __unused,void * mdata __unused,va_list ap __unused)275*56b74a2dSDag-Erling Smørgrav nss_tacplus_setpwent(void *retval __unused, void *mdata __unused,
276*56b74a2dSDag-Erling Smørgrav     va_list ap __unused)
277*56b74a2dSDag-Erling Smørgrav {
278*56b74a2dSDag-Erling Smørgrav 	return (NS_SUCCESS);
279*56b74a2dSDag-Erling Smørgrav }
280*56b74a2dSDag-Erling Smørgrav 
281*56b74a2dSDag-Erling Smørgrav static int
nss_tacplus_getpwent_r(void * retval,void * mdata __unused,va_list ap)282*56b74a2dSDag-Erling Smørgrav nss_tacplus_getpwent_r(void *retval, void *mdata __unused, va_list ap)
283*56b74a2dSDag-Erling Smørgrav {
284*56b74a2dSDag-Erling Smørgrav 	struct passwd *pwd __unused = va_arg(ap, struct passwd *);
285*56b74a2dSDag-Erling Smørgrav 	char *buffer __unused = va_arg(ap, char *);
286*56b74a2dSDag-Erling Smørgrav 	size_t bufsize __unused = va_arg(ap, size_t);
287*56b74a2dSDag-Erling Smørgrav 	int *result = va_arg(ap, int *);
288*56b74a2dSDag-Erling Smørgrav 
289*56b74a2dSDag-Erling Smørgrav 	*(void **)retval = NULL;
290*56b74a2dSDag-Erling Smørgrav 	*result = 0;
291*56b74a2dSDag-Erling Smørgrav 	return (NS_SUCCESS);
292*56b74a2dSDag-Erling Smørgrav 
293*56b74a2dSDag-Erling Smørgrav }
294*56b74a2dSDag-Erling Smørgrav 
295*56b74a2dSDag-Erling Smørgrav static int
nss_tacplus_endpwent(void * retval __unused,void * mdata __unused,va_list ap __unused)296*56b74a2dSDag-Erling Smørgrav nss_tacplus_endpwent(void *retval __unused, void *mdata __unused,
297*56b74a2dSDag-Erling Smørgrav     va_list ap __unused)
298*56b74a2dSDag-Erling Smørgrav {
299*56b74a2dSDag-Erling Smørgrav 	return (NS_SUCCESS);
300*56b74a2dSDag-Erling Smørgrav }
301*56b74a2dSDag-Erling Smørgrav 
3026c5cdba1SDag-Erling Smørgrav ns_mtab *
nss_module_register(const char * name __unused,unsigned int * plen,nss_module_unregister_fn * unreg)3036c5cdba1SDag-Erling Smørgrav nss_module_register(const char *name __unused, unsigned int *plen,
3046c5cdba1SDag-Erling Smørgrav     nss_module_unregister_fn *unreg)
3056c5cdba1SDag-Erling Smørgrav {
3066c5cdba1SDag-Erling Smørgrav 	static ns_mtab mtab[] = {
3076c5cdba1SDag-Erling Smørgrav 		{ "passwd", "getpwnam_r", &nss_tacplus_getpwnam_r, NULL },
308*56b74a2dSDag-Erling Smørgrav 		{ "passwd", "setpwent", &nss_tacplus_setpwent, NULL },
309*56b74a2dSDag-Erling Smørgrav 		{ "passwd", "getpwent_r", &nss_tacplus_getpwent_r, NULL },
310*56b74a2dSDag-Erling Smørgrav 		{ "passwd", "endpwent", &nss_tacplus_endpwent, NULL },
3116c5cdba1SDag-Erling Smørgrav 	};
3126c5cdba1SDag-Erling Smørgrav 
3136c5cdba1SDag-Erling Smørgrav 	*plen = nitems(mtab);
3146c5cdba1SDag-Erling Smørgrav 	*unreg = NULL;
3156c5cdba1SDag-Erling Smørgrav 	return (mtab);
3166c5cdba1SDag-Erling Smørgrav }
317