1.\" $NetBSD: nsdispatch.3,v 1.28 2008/05/08 13:01:42 lukem Exp $ 2.\" 3.\" Copyright (c) 1997, 1998, 1999, 2004, 2005, 2008 4.\" The NetBSD Foundation, Inc. 5.\" All rights reserved. 6.\" 7.\" This code is derived from software contributed to The NetBSD Foundation 8.\" by Luke Mewburn; and by Jason R. Thorpe. 9.\" 10.\" Redistribution and use in source and binary forms, with or without 11.\" modification, are permitted provided that the following conditions 12.\" are met: 13.\" 1. Redistributions of source code must retain the above copyright 14.\" notice, this list of conditions and the following disclaimer. 15.\" 2. Redistributions in binary form must reproduce the above copyright 16.\" notice, this list of conditions and the following disclaimer in the 17.\" documentation and/or other materials provided with the distribution. 18.\" 19.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29.\" POSSIBILITY OF SUCH DAMAGE. 30.\" 31.Dd May 8, 2008 32.Dt NSDISPATCH 3 33.Os 34.Sh NAME 35.Nm nsdispatch 36.Nd name-service switch dispatcher routine 37.Sh LIBRARY 38.Lb libc 39.Sh SYNOPSIS 40.In nsswitch.h 41.Ft int 42.Fo nsdispatch 43.Fa "void *nsdrv" 44.Fa "const ns_dtab dtab[]" 45.Fa "const char *database" 46.Fa "const char *name" 47.Fa "const ns_src defaults[]" 48.Fa "..." 49.Fc 50.Sh DESCRIPTION 51The 52.Fn nsdispatch 53function invokes the callback functions specified in 54.Fa dtab 55in the order given in 56.Pa /etc/nsswitch.conf 57for the database 58.Fa database 59until the action criteria for a source of that database is fulfilled. 60.Pp 61.Fa nsdrv 62is passed to each callback function to use as necessary 63(to pass back to the caller of 64.Fn nsdispatch ) . 65.Pp 66.Fa dtab 67is an array of 68.Fa ns_dtab 69structures, which have the following format: 70.Bd -ragged -offset indent 71.Bd -literal 72typedef struct { 73 const char *src; 74 nss_method cb; 75 void *cb_data; 76} ns_dtab; 77.Ed 78.Pp 79The 80.Fa dtab 81array should consist of one entry for each source type that has a 82static implementation, 83with 84.Fa src 85as the name of the source, 86.Fa cb 87as a callback function which handles that source, and 88.Fa cb_data 89as a pointer to arbitrary data to be passed to the callback function. 90The last entry in 91.Fa dtab 92should contain 93.Dv NULL 94values for 95.Fa src , 96.Fa cb , 97and 98.Fa cb_data . 99.Pp 100The callback function signature is described by the typedef: 101.Pp 102.Bd -ragged -offset indent 103.Ft typedef int 104.Fo \*(lp*nss_method\*(rp 105.Fa "void *cbrv" 106.Fa "void *cbdata" 107.Fa "va_list ap" 108.Fc ; 109.Pp 110.Bl -tag -width cbdata 111.It Fa cbrv 112The 113.Fa nsdrv 114that 115.Fn nsdispatch 116was invoked with. 117.It Fa cbdata 118The 119.Fa cb_data 120member of the array entry for the source that this 121callback function implements in the 122.Fa dtab 123argument of 124.Fn nsdispatch . 125.It Fa ap 126The 127.Fa ... 128arguments to 129.Fn nsdispatch , 130converted to a 131.Ft va_list . 132.El 133.Ed 134.Ed 135.Pp 136.Fa database 137and 138.Fa name 139are used to select methods from optional per-source 140dynamically-loaded modules. 141.Fa name 142is usually the name of the function calling 143.Fn nsdispatch . 144Note that the callback functions provided by 145.Fa dtab 146take priority over those implemented in dynamically-loaded modules in the 147event of a conflict. 148.Pp 149.Fa defaults 150contains a list of default sources to try in the case of 151a missing or corrupt 152.Xr nsswitch.conf 5 , 153or if there isn't a relevant entry for 154.Fa database . 155It is an array of 156.Fa ns_src 157structures, which have the following format: 158.Bd -ragged -offset indent 159.Bd -literal 160typedef struct { 161 const char *src; 162 uint32_t flags; 163} ns_src; 164.Ed 165.Pp 166The 167.Fa defaults 168array should consist of one entry for each source to consult by default 169indicated by 170.Fa src , 171and 172.Fa flags 173set to the desired behavior 174(usually 175.Dv NS_SUCCESS ; 176refer to 177.Sx Callback function return values 178for more information). 179The last entry in 180.Fa defaults 181should have 182.Fa src 183set to 184.Dv NULL 185and 186.Fa flags 187set to 0. 188.Pp 189Some invokers of 190.Fn nsdispatch 191(such as 192.Xr setgrent 3 ) 193need to force all callback functions to be invoked, 194irrespective of the action criteria listed in 195.Xr nsswitch.conf 5 . 196This can be achieved by adding 197.Dv NS_FORCEALL 198to 199.Fa defaults[0].flags 200before invoking 201.Fn nsdispatch . 202The return value of 203.Fn nsdispatch 204will be the result of the final callback function invoked. 205.Pp 206For convenience, a global variable defined as: 207.Dl extern const ns_src __nsdefaultsrc[]; 208exists which contains a single default entry for 209.Sq files 210for use by callers which don't require complicated default rules. 211.Ed 212.Pp 213.Fa ... 214are optional extra arguments, which 215are passed to the appropriate callback function as a 216.Xr stdarg 3 217variable argument 218list of the type 219.Fa va_list . 220.Pp 221.Nm 222returns the value of the callback function that caused the dispatcher 223to finish, or 224.Dv NS_NOTFOUND 225otherwise. 226.\" 227.Ss Dynamically-loaded module interface 228The 229.Fn nsdispatch 230function loads callback functions from the run-time link-editor's search 231path using the following naming convention: 232.Bd -ragged -offset indent 233.Bd -literal 234nss_\*[Lt]source\*[Gt].so.\*[Lt]version\*[Gt] 235.Ed 236.Bl -tag -width XversionX 237.It Aq source 238The source that the module implements. 239.It Aq version 240The 241.Nm nsdispatch 242module interface version, which is defined by the integer 243.Dv NSS_MODULE_INTERFACE_VERSION , 244which has the value 0. 245.El 246.Ed 247.Pp 248When a module is loaded, 249.Fn nsdispatch 250looks for and calls the following function in the module: 251.Pp 252.Bd -ragged -offset indent 253.Ft ns_mtab * 254.Fo nss_module_register 255.Fa "const char *source" 256.Fa "u_int *nelems" 257.Fa "nss_module_unregister_fn *unreg" 258.Fc ; 259.Pp 260.Bl -tag -width source 261.It Fa source 262The name of the source that the module implements, as used by 263.Fn nsdispatch 264to construct the module's name. 265.It Fa nelems 266A pointer to an unsigned integer that 267.Fn nss_module_register 268should set to the number of elements in the 269.Ft ns_mtab 270array returned by 271.Fn nss_module_register , 272or 273.Dv 0 274if there was a failure. 275.It Fa unreg 276A pointer to a function pointer that 277.Fn nss_module_register 278can optionally set to an unregister function to be invoked when the module is 279unloaded, or 280.Dv NULL 281if there isn't one. 282.El 283.Ed 284.Pp 285The unregister function signature is described by the typedef: 286.Pp 287.Bd -ragged -offset indent 288.Ft typedef void 289.Fo \*(lp*nss_module_unregister_fn\*(rp 290.Fa "ns_mtab *mtab" 291.Fa "u_int nelems" 292.Fc ; 293.Pp 294.Bl -tag -width nelems 295.It Fa mtab 296The array of 297.Ft ns_mtab 298structures returned by 299.Fn nss_module_register . 300.It Fa nelems 301The 302.Fa *nelems 303value set by 304.Fn nss_module_register . 305.El 306.Ed 307.Pp 308.Fn nss_module_register 309returns an array of 310.Ft ns_mtab 311structures 312(with 313.Fa *nelems 314entries), or 315.Dv NULL 316if there was a failure. 317The 318.Ft ns_mtab 319structures have the following format: 320.Bd -ragged -offset indent 321.Bd -literal 322typedef struct { 323 const char *database; 324 const char *name; 325 nss_method method; 326 void *mdata; 327} ns_mtab; 328.Ed 329.Pp 330The 331.Fa mtab 332array should consist of one entry for each callback function (method) 333that is implemented, 334with 335.Fa database 336as the name of the database, 337.Fa name 338as the name of the callback function, 339.Fa method 340as the 341.Ft nss_method 342callback function that implements the method, and 343.Fa mdata 344as a pointer to arbitrary data to be passed to the callback function as its 345.Fa cbdata 346argument. 347.Ed 348.\" 349.Ss Valid source types 350While there is support for arbitrary sources, the following 351#defines for commonly implemented sources are provided: 352.Bl -column NSSRC_COMPAT COMPAT -offset indent 353.Sy #define Value 354.It NSSRC_FILES "files" 355.It NSSRC_DNS "dns" 356.It NSSRC_NIS "nis" 357.It NSSRC_COMPAT "compat" 358.El 359.Pp 360Refer to 361.Xr nsswitch.conf 5 362for a complete description of what each source type is. 363.\" 364.Ss Valid database types 365While there is support for arbitrary databases, the following 366#defines for currently implemented system databases are provided: 367.Bl -column NSDB_PASSWD_COMPAT PASSWD_COMPAT -offset indent 368.Sy #define Value 369.It NSDB_HOSTS "hosts" 370.It NSDB_GROUP "group" 371.It NSDB_GROUP_COMPAT "group_compat" 372.It NSDB_NETGROUP "netgroup" 373.It NSDB_NETWORKS "networks" 374.It NSDB_PASSWD "passwd" 375.It NSDB_PASSWD_COMPAT "passwd_compat" 376.It NSDB_SHELLS "shells" 377.El 378.Pp 379Refer to 380.Xr nsswitch.conf 5 381for a complete description of what each database is. 382.\" 383.Ss Callback function return values 384The callback functions should return one of the following values 385depending upon status of the lookup: 386.Bl -column NS_NOTFOUND -offset indent 387.Sy "Return value" Status code 388.It NS_SUCCESS The requested entry was found. 389.It NS_NOTFOUND The entry is not present at this source. 390.It NS_TRYAGAIN The source is busy, and may respond to retries. 391.It NS_UNAVAIL The source is not responding, or entry is corrupt. 392.El 393.\" 394.Sh CALLBACK FUNCTION API FOR STANDARD DATABASES 395The organization of the 396.Fa ap 397argument for an 398.Fn nss_method 399callback function for a standard method in a standard database is: 400.Bl -enum -offset indent -compact 401.It 402Pointer to return value of the standard function. 403.It 404First argument of the standard function. 405.It 406(etc.) 407.El 408.Pp 409For example, given the standard function 410.Xr getgrnam 3 : 411.Bd -ragged -offset indent -compact 412.Ft struct group * 413.Fn getgrnam "const char *name" 414.Ed 415the 416.Fa ap 417organization used by the callback functions is: 418.Bl -enum -offset indent -compact 419.It 420.Ft "struct group **" 421.It 422.Ft "const char *" 423.El 424.Pp 425.Sy NOTE: 426Not all standard databases are using this calling convention yet; 427those that aren't are noted below. 428These will be changed in the future. 429.Pp 430The callback function names and 431.Ft va_list 432organization for various standard database callback functions are: 433.\" 434.Ss Methods for hosts database 435.Sy NOTE: 436The method APIs for this database will be changing in the near future. 437.Bl -tag -width 3n 438.It Sy getaddrinfo 439.Ft "char *name" , 440.Ft "const struct addrinfo *pai" 441.Pp 442Returns 443.Ft "struct addrinfo *" 444via 445.Ft "void *cbrv" . 446.It Sy gethostbyaddr 447.Ft "unsigned char *addr" , 448.Ft "int addrlen" , 449.Ft "int af" 450.Pp 451Returns 452.Ft "struct hostent *" 453via 454.Ft "void *cbrv" . 455.It Sy gethostbyname 456.Ft "char *name" , 457.Ft "int namelen" , 458.Ft "int af" 459.Pp 460Returns 461.Ft "struct hostent *" 462via 463.Ft "void *cbrv" . 464.El 465.\" 466.Ss Methods for group and group_compat databases 467.Bl -tag -width 3n 468.It Sy endgrent 469Empty 470.Fa ap . 471.Pp 472All methods for all sources are invoked for this method name. 473.It Sy getgrent 474.Ft "struct group **retval" 475.Pp 476.Fa *retval 477should be set to a pointer to an internal static 478.Ft "struct group" 479on success, 480.Dv NULL otherwise. 481.Pp 482.Xr getgrent 3 483returns 484.Fa *retval 485if 486.Fn nsdispatch 487returns 488.Dv NS_SUCCESS , 489.Dv NULL 490otherwise. 491.It Sy getgrent_r 492.Ft "int *retval" , 493.Ft "struct group *grp" , 494.Ft "char *buffer" , 495.Ft "size_t buflen" , 496.Ft "struct group **result" 497.Pp 498.Fa *retval 499should be set to an appropriate 500.Xr errno 2 501on failure. 502.Pp 503.Xr getgrent_r 3 504returns 0 505if 506.Fn nsdispatch 507returns 508.Dv NS_SUCCESS 509or 510.Dv NS_NOTFOUND , 511and 512.Fa *retval 513otherwise. 514.It Sy getgrgid 515.Ft "struct group **retval" , 516.Ft "gid_t gid" 517.Pp 518.Fa *retval 519should be set to a pointer to an internal static 520.Ft "struct group" 521on success, 522.Dv NULL otherwise. 523.Pp 524.Xr getgrgid 3 525returns 526.Fa *retval 527if 528.Fn nsdispatch 529returns 530.Dv NS_SUCCESS , 531.Dv NULL 532otherwise. 533.It Sy getgrgid_r 534.Ft "int *retval" , 535.Ft "gid_t gid" , 536.Ft "struct group *grp" , 537.Ft "char *buffer" , 538.Ft "size_t buflen" , 539.Ft "struct group **result" 540.Pp 541.Fa *retval 542should be set to an appropriate 543.Xr errno 2 544on failure. 545.Pp 546.Xr getgrgid_r 3 547returns 0 548if 549.Fn nsdispatch 550returns 551.Dv NS_SUCCESS 552or 553.Dv NS_NOTFOUND , 554and 555.Fa *retval 556otherwise. 557.It Sy getgrnam 558.Ft "struct group **retval" , 559.Ft "const char *name" 560.Pp 561.Fa *retval 562should be set to a pointer to an internal static 563.Ft "struct group" 564on success, 565.Dv NULL otherwise. 566.Pp 567.Xr getgrnam 3 568returns 569.Fa *retval 570if 571.Fn nsdispatch 572returns 573.Dv NS_SUCCESS , 574.Dv NULL 575otherwise. 576.It Sy getgrnam_r 577.Ft "int *retval" , 578.Ft "const char *name" , 579.Ft "struct group *grp" , 580.Ft "char *buffer" , 581.Ft "size_t buflen" , 582.Ft "struct group **result" 583.Pp 584.Fa *retval 585should be set to an appropriate 586.Xr errno 2 587on failure. 588.Pp 589.Xr getgrnam_r 3 590returns 0 591if 592.Fn nsdispatch 593returns 594.Dv NS_SUCCESS 595or 596.Dv NS_NOTFOUND , 597and 598.Fa *retval 599otherwise. 600.It Sy getgroupmembership 601.Ft "int *retval" , 602.Ft "const char *name" , 603.Ft "gid_t basegid" , 604.Ft "gid_t *groups" , 605.Ft "int maxgrp" , 606.Ft "int *groupc" 607.Pp 608.Fa retval 609is unused. 610.Pp 611Lookups for 612.Sy group_compat 613are also stopped if 614.Dv NS_SUCCESS 615was returned to prevent multiple 616.Dq "+:" 617compat entries from being expanded. 618.Pp 619.Xr getgroupmembership 3 620returns 621is -1 if 622.Fa *groupc 623is greater than to 624.Fa maxgrp , 625and 0 otherwise. 626.It Sy setgroupent 627.Ft "int *retval" , 628.Ft "int stayopen" 629.Pp 630.Fa retval 631should be set to 0 on failure and 1 on success. 632.Pp 633All methods for all sources are invoked for this method name. 634.It Sy setgrent 635Empty 636.Fa ap . 637.Pp 638All methods for all sources are invoked for this method name. 639.El 640.\" 641.Ss Methods for netgroup database 642.Sy NOTE: 643The method APIs for this database will be changing in the near future. 644.Bl -tag -width 3n 645.It Sy endnetgrent 646Empty 647.Fa ap . 648.It Sy lookup 649.Ft "char *name" , 650.Ft "char **line" , 651.Ft "int bywhat" 652.Pp 653Find the given 654.Fa name 655and return its value in 656.Fa line . 657.Fa bywhat 658is one of 659.Dv _NG_KEYBYNAME , 660.Dv _NG_KEYBYUSER , 661or 662.Dv _NG_KEYBYHOST . 663.It Sy getnetgrent 664.Ft "int *retval" , 665.Ft "const char **host" , 666.Ft "const char **user" , 667.Ft "const char **domain" 668.Pp 669.Fa *retval 670should be set to 0 for no more netgroup members and 1 otherwise. 671.Pp 672.Xr getnetgrent 3 673returns 674.Fa *retval 675if 676.Fn nsdispatch 677returns 678.Dv NS_SUCCESS , 6790 otherwise. 680.It Sy innetgr 681.Ft "int *retval" , 682.Ft "const char *grp" , 683.Ft "const char *host" , 684.Ft "const char *user" , 685.Ft "const char *domain" 686.Pp 687.Fa *retval 688should be set to 1 for a successful match and 0 otherwise. 689.It Sy setnetgrent 690.Ft "const char *netgroup" 691.El 692.\" 693.Ss Methods for networks database 694.Bl -tag -width 3n 695.It Sy getnetbyaddr 696.Ft "struct netent **retval" , 697.Ft "uint32_t net" , 698.Ft "int type" 699.Pp 700.Fa *retval 701should be set to a pointer to an internal static 702.Ft "struct netent" 703on success, 704.Dv NULL otherwise. 705.Pp 706.Xr getnetbyaddr 3 707returns 708.Fa *retval 709if 710.Fn nsdispatch 711returns 712.Dv NS_SUCCESS , 713.Dv NULL 714otherwise. 715.It Sy getnetbyname 716.Ft "struct netent **retval" , 717.Ft "const char *name" 718.Pp 719.Fa *retval 720should be set to a pointer to an internal static 721.Ft "struct netent" 722on success, 723.Dv NULL otherwise. 724.Pp 725.Xr getnetbyname 3 726returns 727.Fa *retval 728if 729.Fn nsdispatch 730returns 731.Dv NS_SUCCESS , 732.Dv NULL 733otherwise. 734.El 735.\" 736.Ss Methods for passwd and passwd_compat databases 737.Bl -tag -width 3n 738.It Sy endpwent 739Empty 740.Fa ap . 741.Pp 742All methods for all sources are invoked for this method name. 743.It Sy getpwent 744.Ft "struct passwd **retval" 745.Pp 746.Fa *retval 747should be set to a pointer to an internal static 748.Ft "struct passwd" 749on success, 750.Dv NULL otherwise. 751.Pp 752.Xr getpwent 3 753returns 754.Fa *retval 755if 756.Fn nsdispatch 757returns 758.Dv NS_SUCCESS , 759.Dv NULL 760otherwise. 761.It Sy getpwent_r 762.Ft "int *retval" , 763.Ft "struct passwd *pw" , 764.Ft "char *buffer" , 765.Ft "size_t buflen" , 766.Ft "struct passwd **result" 767.Pp 768.Fa *retval 769should be set to an appropriate 770.Xr errno 2 771on failure. 772.Pp 773.Xr getpwent_r 3 774returns 0 775if 776.Fn nsdispatch 777returns 778.Dv NS_SUCCESS 779or 780.Dv NS_NOTFOUND , 781and 782.Fa *retval 783otherwise. 784.It Sy getpwnam 785.Ft "struct passwd **retval" , 786.Ft "const char *name" 787.Pp 788.Fa *retval 789should be set to a pointer to an internal static 790.Ft "struct passwd" 791on success, 792.Dv NULL otherwise. 793.Pp 794.Xr getpwnam 3 795returns 796.Fa *retval 797if 798.Fn nsdispatch 799returns 800.Dv NS_SUCCESS , 801.Dv NULL 802otherwise. 803.It Sy getpwnam_r 804.Ft "int *retval" , 805.Ft "const char *name" , 806.Ft "struct passwd *pw" , 807.Ft "char *buffer" , 808.Ft "size_t buflen" , 809.Ft "struct passwd **result" 810.Pp 811.Fa *retval 812should be set to an appropriate 813.Xr errno 2 814on failure. 815.Pp 816.Xr getpwnam_r 3 817returns 0 818if 819.Fn nsdispatch 820returns 821.Dv NS_SUCCESS 822or 823.Dv NS_NOTFOUND , 824and 825.Fa *retval 826otherwise. 827.It Sy getpwuid 828.Ft "struct passwd **retval" , 829.Ft "uid_t uid" 830.Pp 831.Fa *retval 832should be set to a pointer to an internal static 833.Ft "struct passwd" 834on success, 835.Dv NULL otherwise. 836.Pp 837.Xr getpwuid 3 838returns 839.Fa *retval 840if 841.Fn nsdispatch 842returns 843.Dv NS_SUCCESS , 844.Dv NULL 845otherwise. 846.It Sy getpwuid_r 847.Ft "int *retval" , 848.Ft "uid_t uid" , 849.Ft "struct passwd *pw" , 850.Ft "char *buffer" , 851.Ft "size_t buflen" , 852.Ft "struct passwd **result" 853.Pp 854.Fa *retval 855should be set to an appropriate 856.Xr errno 2 857on failure. 858.Pp 859.Xr getpwuid_r 860returns 0 861if 862.Fn nsdispatch 863returns 864.Dv NS_SUCCESS 865or 866.Dv NS_NOTFOUND , 867and 868.Fa *retval 869otherwise. 870.It Sy setpassent 871.Ft "int *retval" , 872.Ft "int stayopen" 873.Pp 874.Fa retval 875should be set to 0 on failure and 1 on success. 876.Pp 877All methods for all sources are invoked for this method name. 878.It Sy setpwent 879Empty 880.Fa ap . 881.Pp 882All methods for all sources are invoked for this method name. 883.El 884.\" 885.Ss Methods for shells database 886.Bl -tag -width 3n 887.It Sy endusershell 888Empty 889.Fa ap . 890.Pp 891All methods for all sources are invoked for this method name. 892.It Sy getusershell 893.Ft "char **retval" 894.Pp 895.Xr getusershell 3 896returns 897.Fa *retval 898if 899.Fn nsdispatch 900returns 901.Dv NS_SUCCESS , 902and 0 otherwise. 903.It Sy setusershell 904Empty 905.Fa ap . 906.Pp 907All methods for all sources are invoked for this method name. 908.El 909.\" 910.Sh SEE ALSO 911.Xr ld.elf_so 1 , 912.Xr hesiod 3 , 913.Xr stdarg 3 , 914.Xr ypclnt 3 , 915.Xr nsswitch.conf 5 916.Sh HISTORY 917The 918.Nm 919routines first appeared in 920.Nx 1.4 . 921Support for dynamically-loaded modules first appeared in 922.Nx 3.0 . 923.Sh AUTHORS 924Luke Mewburn 925.Aq lukem@NetBSD.org 926wrote this freely distributable name-service switch implementation, 927using ideas from the 928.Tn ULTRIX 929.Xr svc.conf 5 930and 931.Tn Solaris 932.Xr nsswitch.conf 4 933manual pages. 934Support for dynamically-loaded modules was added by Jason Thorpe 935.Aq thorpej@NetBSD.org , 936based on code developed by the 937.Fx 938Project. 939