source: trunk/debathena/debathena/libnss-nonlocal/nonlocal-shadow.c @ 24585

Revision 24585, 4.9 KB checked in by andersk, 15 years ago (diff)
Line 
1/*
2 * nonlocal-shadow.c
3 * shadow database for nss_nonlocal proxy.
4 *
5 * Copyright © 2007–2010 Anders Kaseorg <andersk@mit.edu>
6 *
7 * This file is part of nss_nonlocal.
8 *
9 * nss_nonlocal is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * nss_nonlocal is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with nss_nonlocal; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02110-1301  USA
23 */
24
25#define _GNU_SOURCE
26#include <sys/types.h>
27#include <unistd.h>
28#include <stdlib.h>
29#include <stdint.h>
30#include <string.h>
31#include <dlfcn.h>
32#include <stdio.h>
33#include <syslog.h>
34#include <errno.h>
35#include <shadow.h>
36#include <nss.h>
37
38#include "nsswitch-internal.h"
39#include "nonlocal.h"
40
41
42static service_user *
43nss_shadow_nonlocal_database(void)
44{
45    static service_user *nip = NULL;
46    if (nip == NULL)
47        __nss_database_lookup("shadow_nonlocal", NULL, "", &nip);
48
49    return nip;
50}
51
52
53static service_user *spent_nip = NULL;
54static void *spent_fct_start;
55static union {
56    enum nss_status (*l)(struct spwd *pwd, char *buffer, size_t buflen,
57                         int *errnop);
58    void *ptr;
59} spent_fct;
60static const char *spent_fct_name = "getspent_r";
61
62enum nss_status
63_nss_nonlocal_setspent(int stayopen)
64{
65    static const char *fct_name = "setspent";
66    static void *fct_start = NULL;
67    enum nss_status status;
68    service_user *nip;
69    union {
70        enum nss_status (*l)(int stayopen);
71        void *ptr;
72    } fct;
73
74    nip = nss_shadow_nonlocal_database();
75    if (nip == NULL)
76        return NSS_STATUS_UNAVAIL;
77    if (fct_start == NULL)
78        fct_start = __nss_lookup_function(nip, fct_name);
79    fct.ptr = fct_start;
80    do {
81        if (fct.ptr == NULL)
82            status = NSS_STATUS_UNAVAIL;
83        else
84            status = DL_CALL_FCT(fct.l, (stayopen));
85    } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
86    if (status != NSS_STATUS_SUCCESS)
87        return status;
88
89    spent_nip = nip;
90    if (spent_fct_start == NULL)
91        spent_fct_start = __nss_lookup_function(nip, spent_fct_name);
92    spent_fct.ptr = spent_fct_start;
93    return NSS_STATUS_SUCCESS;
94}
95
96enum nss_status
97_nss_nonlocal_endspent(void)
98{
99    static const char *fct_name = "endspent";
100    static void *fct_start = NULL;
101    enum nss_status status;
102    service_user *nip;
103    union {
104        enum nss_status (*l)(void);
105        void *ptr;
106    } fct;
107
108    spent_nip = NULL;
109
110    nip = nss_shadow_nonlocal_database();
111    if (nip == NULL)
112        return NSS_STATUS_UNAVAIL;
113    if (fct_start == NULL)
114        fct_start = __nss_lookup_function(nip, fct_name);
115    fct.ptr = fct_start;
116    do {
117        if (fct.ptr == NULL)
118            status = NSS_STATUS_UNAVAIL;
119        else
120            status = DL_CALL_FCT(fct.l, ());
121    } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
122    return status;
123}
124
125enum nss_status
126_nss_nonlocal_getspent_r(struct spwd *pwd, char *buffer, size_t buflen,
127                         int *errnop)
128{
129    enum nss_status status;
130    if (spent_nip == NULL) {
131        status = _nss_nonlocal_setspent(0);
132        if (status != NSS_STATUS_SUCCESS)
133            return status;
134    }
135    do {
136        if (spent_fct.ptr == NULL)
137            status = NSS_STATUS_UNAVAIL;
138        else
139            status = DL_CALL_FCT(spent_fct.l, (pwd, buffer, buflen, errnop));   
140        if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
141            return status;
142
143        if (status == NSS_STATUS_SUCCESS)
144            return NSS_STATUS_SUCCESS;
145    } while (__nss_next(&spent_nip, spent_fct_name, &spent_fct.ptr, status, 0) == 0);
146
147    spent_nip = NULL;
148    return NSS_STATUS_NOTFOUND;
149}
150
151
152enum nss_status
153_nss_nonlocal_getspnam_r(const char *name, struct spwd *pwd,
154                         char *buffer, size_t buflen, int *errnop)
155{
156    static const char *fct_name = "getspnam_r";
157    static void *fct_start = NULL;
158    enum nss_status status;
159    service_user *nip;
160    union {
161        enum nss_status (*l)(const char *name, struct spwd *pwd,
162                             char *buffer, size_t buflen, int *errnop);
163        void *ptr;
164    } fct;
165
166    nip = nss_shadow_nonlocal_database();
167    if (nip == NULL)
168        return NSS_STATUS_UNAVAIL;
169    if (fct_start == NULL)
170        fct_start = __nss_lookup_function(nip, fct_name);
171    fct.ptr = fct_start;
172    do {
173        if (fct.ptr == NULL)
174            status = NSS_STATUS_UNAVAIL;
175        else
176            status = DL_CALL_FCT(fct.l, (name, pwd, buffer, buflen, errnop));
177        if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
178            break;
179    } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
180    if (status != NSS_STATUS_SUCCESS)
181        return status;
182
183    if (strcmp(name, pwd->sp_namp) != 0) {
184        syslog(LOG_ERR, "nss_nonlocal: discarding shadow %s from lookup for shadow %s\n", pwd->sp_namp, name);
185        return NSS_STATUS_NOTFOUND;
186    }
187
188    return NSS_STATUS_SUCCESS;
189}
Note: See TracBrowser for help on using the repository browser.