3cfe5588626b0d9cf9a2511f340dc877f84ed48d
[kopensolaris-gnu/glibc.git] / nscd / nscd_getpw_r.c
1 /* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <errno.h>
21 #include <pwd.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/socket.h>
28 #include <sys/uio.h>
29 #include <sys/un.h>
30
31 #include "nscd-client.h"
32 #include "nscd_proto.h"
33
34 int __nss_not_use_nscd_passwd;
35
36 static int nscd_getpw_r (const char *key, request_type type,
37                          struct passwd *resultbuf, char *buffer,
38                          size_t buflen);
39
40 int
41 __nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer,
42                    size_t buflen)
43 {
44   if (name == NULL)
45     return 1;
46
47   return nscd_getpw_r (name, GETPWBYNAME, resultbuf, buffer, buflen);
48 }
49
50 int
51 __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer,
52                    size_t buflen)
53 {
54   char *p = buffer;
55   int plen;
56
57   plen = __snprintf (buffer, buflen, "%d", uid);
58   if (plen == -1)
59     {
60       __set_errno (ERANGE);
61       return -1;
62     }
63   p = buffer + plen + 1;
64
65   return nscd_getpw_r (buffer, GETPWBYUID, resultbuf, p, buflen - plen - 1);
66 }
67
68 /* Create a socket connected to a name. */
69 static int
70 open_socket (void)
71 {
72   struct sockaddr_un addr;
73   int sock;
74   int saved_errno = errno;
75
76   sock = __socket (PF_UNIX, SOCK_STREAM, 0);
77   if (sock < 0)
78     {
79       __set_errno (saved_errno);
80       return -1;
81     }
82
83   addr.sun_family = AF_UNIX;
84   strcpy (addr.sun_path, _PATH_NSCDSOCKET);
85   if (__connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
86     {
87       __close (sock);
88       __set_errno (saved_errno);
89       return -1;
90     }
91
92   return sock;
93 }
94
95 static int
96 nscd_getpw_r (const char *key, request_type type, struct passwd *resultbuf,
97               char *buffer, size_t buflen)
98 {
99   int sock = open_socket ();
100   request_header req;
101   pw_response_header pw_resp;
102   ssize_t nbytes;
103
104   if (sock == -1)
105     {
106       __nss_not_use_nscd_passwd = 1;
107       return 1;
108     }
109
110   req.version = NSCD_VERSION;
111   req.type = type;
112   req.key_len = strlen (key) + 1;
113   nbytes = __write (sock, &req, sizeof (request_header));
114   if (nbytes != sizeof (request_header))
115     {
116       __close (sock);
117       return 1;
118     }
119
120   nbytes = __write (sock, key, req.key_len);
121   if (nbytes != req.key_len)
122     {
123       __close (sock);
124       return 1;
125     }
126
127   nbytes = __read (sock, &pw_resp, sizeof (pw_response_header));
128   if (nbytes != sizeof (pw_response_header))
129     {
130       __close (sock);
131       return 1;
132     }
133
134   if (pw_resp.found == -1)
135     {
136       /* The daemon does not cache this database.  */
137       __close (sock);
138       __nss_not_use_nscd_passwd = 1;
139       return 1;
140     }
141
142   if (pw_resp.found == 1)
143     {
144       char *p = buffer;
145       size_t total = (pw_resp.pw_name_len + pw_resp.pw_passwd_len
146                       + pw_resp.pw_gecos_len + pw_resp.pw_dir_len
147                       + pw_resp.pw_shell_len);
148
149       if (buflen < total)
150         {
151           __set_errno (ERANGE);
152           __close (sock);
153           return -1;
154         }
155
156       /* Set the information we already have.  */
157       resultbuf->pw_uid = pw_resp.pw_uid;
158       resultbuf->pw_gid = pw_resp.pw_gid;
159
160       /* get pw_name */
161       resultbuf->pw_name = p;
162       p += pw_resp.pw_name_len;
163       /* get pw_passwd */
164       resultbuf->pw_passwd = p;
165       p += pw_resp.pw_passwd_len;
166       /* get pw_gecos */
167       resultbuf->pw_gecos = p;
168       p += pw_resp.pw_gecos_len;
169       /* get pw_dir */
170       resultbuf->pw_dir = p;
171       p += pw_resp.pw_dir_len;
172       /* get pw_pshell */
173       resultbuf->pw_shell = p;
174
175       nbytes = __read (sock, buffer, total);
176
177       __close (sock);
178
179       return nbytes == total ? 0 : 1;
180     }
181   else
182     {
183       __close (sock);
184       return -1;
185     }
186 }