2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/usr.sbin/nscd/nscdcli.c,v 1.5 2008/10/23 00:28:21 delphij Exp $
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/event.h>
45 #define DEFAULT_NSCD_IO_TIMEOUT 4
47 static int safe_write(struct nscd_connection_
*, const void *, size_t);
48 static int safe_read(struct nscd_connection_
*, void *, size_t);
49 static int send_credentials(struct nscd_connection_
*, int);
52 safe_write(struct nscd_connection_
*connection
, const void *data
,
55 struct kevent eventlist
;
59 struct timespec timeout
;
64 timeout
.tv_sec
= DEFAULT_NSCD_IO_TIMEOUT
;
68 nevents
= kevent(connection
->write_queue
, NULL
, 0, &eventlist
,
70 if ((nevents
== 1) && (eventlist
.filter
== EVFILT_WRITE
)) {
71 s_result
= write(connection
->sockfd
, data
+ result
,
72 eventlist
.data
< data_size
- result
?
73 eventlist
.data
: data_size
- result
);
79 if (eventlist
.flags
& EV_EOF
)
80 return (result
< data_size
? -1 : 0);
83 } while (result
< data_size
);
89 safe_read(struct nscd_connection_
*connection
, void *data
, size_t data_size
)
91 struct kevent eventlist
;
94 struct timespec timeout
;
100 timeout
.tv_sec
= DEFAULT_NSCD_IO_TIMEOUT
;
104 nevents
= kevent(connection
->read_queue
, NULL
, 0, &eventlist
, 1,
106 if ((nevents
== 1) && (eventlist
.filter
== EVFILT_READ
)) {
107 s_result
= read(connection
->sockfd
, data
+ result
,
108 eventlist
.data
<= data_size
- result
? eventlist
.data
:
115 if (eventlist
.flags
& EV_EOF
)
116 return (result
< data_size
? -1 : 0);
119 } while (result
< data_size
);
125 send_credentials(struct nscd_connection_
*connection
, int type
)
127 struct kevent eventlist
;
132 struct msghdr cred_hdr
;
137 struct cmsgcred creds
;
140 TRACE_IN(send_credentials
);
141 memset(&cmsg
, 0, sizeof(cmsg
));
142 cmsg
.hdr
.cmsg_len
= sizeof(cmsg
);
143 cmsg
.hdr
.cmsg_level
= SOL_SOCKET
;
144 cmsg
.hdr
.cmsg_type
= SCM_CREDS
;
146 memset(&cred_hdr
, 0, sizeof(struct msghdr
));
147 cred_hdr
.msg_iov
= &iov
;
148 cred_hdr
.msg_iovlen
= 1;
149 cred_hdr
.msg_control
= &cmsg
;
150 cred_hdr
.msg_controllen
= sizeof(cmsg
);
152 iov
.iov_base
= &type
;
153 iov
.iov_len
= sizeof(int);
155 EV_SET(&eventlist
, connection
->sockfd
, EVFILT_WRITE
, EV_ADD
,
156 NOTE_LOWAT
, sizeof(int), NULL
);
157 res
= kevent(connection
->write_queue
, &eventlist
, 1, NULL
, 0, NULL
);
159 nevents
= kevent(connection
->write_queue
, NULL
, 0, &eventlist
, 1, NULL
);
160 if ((nevents
== 1) && (eventlist
.filter
== EVFILT_WRITE
)) {
161 result
= (sendmsg(connection
->sockfd
, &cred_hdr
, 0) == -1) ? -1
163 EV_SET(&eventlist
, connection
->sockfd
, EVFILT_WRITE
, EV_ADD
,
165 kevent(connection
->write_queue
, &eventlist
, 1, NULL
, 0, NULL
);
166 TRACE_OUT(send_credentials
);
169 TRACE_OUT(send_credentials
);
174 struct nscd_connection_
*
175 open_nscd_connection__(struct nscd_connection_params
const *params
)
177 struct nscd_connection_
*retval
;
178 struct kevent eventlist
;
179 struct sockaddr_un client_address
;
180 int client_address_len
, client_socket
;
183 TRACE_IN(open_nscd_connection
);
184 assert(params
!= NULL
);
186 client_socket
= socket(PF_LOCAL
, SOCK_STREAM
, 0);
187 client_address
.sun_family
= PF_LOCAL
;
188 strlcpy(client_address
.sun_path
, params
->socket_path
,
189 sizeof(client_address
.sun_path
));
190 client_address_len
= sizeof(client_address
.sun_family
) +
191 strlen(client_address
.sun_path
) + 1;
193 res
= connect(client_socket
, (struct sockaddr
*)&client_address
,
196 close(client_socket
);
197 TRACE_OUT(open_nscd_connection
);
200 fcntl(client_socket
, F_SETFL
, O_NONBLOCK
);
202 retval
= calloc(1, sizeof(struct nscd_connection_
));
203 assert(retval
!= NULL
);
205 retval
->sockfd
= client_socket
;
207 retval
->write_queue
= kqueue();
208 assert(retval
->write_queue
!= -1);
210 EV_SET(&eventlist
, retval
->sockfd
, EVFILT_WRITE
, EV_ADD
,
212 res
= kevent(retval
->write_queue
, &eventlist
, 1, NULL
, 0, NULL
);
214 retval
->read_queue
= kqueue();
215 assert(retval
->read_queue
!= -1);
217 EV_SET(&eventlist
, retval
->sockfd
, EVFILT_READ
, EV_ADD
,
219 res
= kevent(retval
->read_queue
, &eventlist
, 1, NULL
, 0, NULL
);
221 TRACE_OUT(open_nscd_connection
);
226 close_nscd_connection__(struct nscd_connection_
*connection
)
229 TRACE_IN(close_nscd_connection
);
230 assert(connection
!= NULL
);
232 close(connection
->sockfd
);
233 close(connection
->read_queue
);
234 close(connection
->write_queue
);
236 TRACE_OUT(close_nscd_connection
);
240 nscd_transform__(struct nscd_connection_
*connection
,
241 const char *entry_name
, int transformation_type
)
247 TRACE_IN(nscd_transform
);
251 result
= send_credentials(connection
, CET_TRANSFORM_REQUEST
);
255 if (entry_name
!= NULL
)
256 name_size
= strlen(entry_name
);
260 result
= safe_write(connection
, &name_size
, sizeof(size_t));
264 result
= safe_write(connection
, &transformation_type
, sizeof(int));
268 if (entry_name
!= NULL
) {
269 result
= safe_write(connection
, entry_name
, name_size
);
274 result
= safe_read(connection
, &error_code
, sizeof(int));
279 TRACE_OUT(nscd_transform
);