Update.
[glibc.git] / login / utmp_daemon.c
blob5907e06e2d0ffda70ae9a1cd598d853282ed136c
1 /* Copyright (C) 1997 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
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.
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.
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. */
20 #include <errno.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <unistd.h>
27 #include <utmp.h>
29 #include "utmp-private.h"
30 #include "programs/utmpd.h"
33 /* Descriptor for the socket. */
34 static int daemon_sock = INT_MIN;
37 /* Functions defined here. */
38 static int setutent_daemon (void);
39 static int getutent_r_daemon (struct utmp *buffer, struct utmp **result);
40 static int getutid_r_daemon (const struct utmp *line, struct utmp *buffer,
41 struct utmp **result);
42 static int getutline_r_daemon (const struct utmp *id, struct utmp *buffer,
43 struct utmp **result);
44 static struct utmp *pututline_daemon (const struct utmp *utmp);
45 static void endutent_daemon (void);
46 static int updwtmp_daemon (const char *file, const struct utmp *utmp);
48 /* Jump table for daemon functions. */
49 struct utfuncs __libc_utmp_daemon_functions =
51 setutent_daemon,
52 getutent_r_daemon,
53 getutid_r_daemon,
54 getutline_r_daemon,
55 pututline_daemon,
56 endutent_daemon,
57 updwtmp_daemon
60 static int do_setutent (int sock);
61 static int do_getutent (int sock, struct utmp *buffer);
62 static int do_endutent (int sock);
63 static int do_getutline (int sock, const struct utmp *line,
64 struct utmp *buffer);
65 static int do_getutid (int sock, const struct utmp *id,
66 struct utmp *buffer);
67 static int do_pututline (int sock, const struct utmp *utmp);
68 static int do_updwtmp (int sock, const char *file,
69 const struct utmp *utmp);
71 static int open_socket (const char *name);
72 static int send_request (int sock, const request_header *request,
73 reply_header *reply);
76 static int
77 setutent_daemon (void)
79 if (access (_PATH_UTMPD_RW, F_OK) == -1
80 && access (_PATH_UTMPD_RO, F_OK) == -1)
81 return 0;
83 if (daemon_sock < 0)
85 daemon_sock = open_socket (_PATH_UTMPD_RW);
86 if (daemon_sock < 0)
88 /* Hhm, read-write access did not work. Try read-only. */
89 daemon_sock = open_socket (_PATH_UTMPD_RO);
90 if (daemon_sock < 0)
91 return 0;
95 /* Send request to the daemon. */
96 if (do_setutent (daemon_sock) < 0)
97 return 0;
99 return 1;
103 static void
104 endutent_daemon (void)
106 if (daemon_sock >= 0)
108 /* Send request to the daemon. */
109 do_endutent (daemon_sock);
110 close (daemon_sock);
113 daemon_sock = INT_MIN;
117 static int
118 getutent_r_daemon (struct utmp *buffer, struct utmp **result)
120 /* Open connection if not already done. */
121 if (daemon_sock == INT_MIN)
122 setutent_daemon ();
124 if (daemon_sock < 0)
126 /* Not available. */
127 *result = NULL;
128 return -1;
131 /* Send request to the daemon. */
132 if (do_getutent (daemon_sock, buffer) < 0)
134 *result = NULL;
135 return -1;;
138 *result = buffer;
139 return 0;
143 static int
144 getutline_r_daemon (const struct utmp *line, struct utmp *buffer,
145 struct utmp **result)
147 if (daemon_sock < 0)
149 *result = NULL;
150 return -1;
153 /* Send request to the daemon. */
154 if (do_getutline (daemon_sock, line, buffer) < 0)
156 *result = NULL;
157 return -1;;
160 *result = buffer;
161 return 0;
165 static int
166 getutid_r_daemon (const struct utmp *id, struct utmp *buffer,
167 struct utmp **result)
169 if (daemon_sock < 0)
171 *result = NULL;
172 return -1;
175 /* Send request to the daemon. */
176 if (do_getutid (daemon_sock, id, buffer) < 0)
178 *result = NULL;
179 return -1;
182 *result = buffer;
183 return 0;
187 static struct utmp *
188 pututline_daemon (const struct utmp *utmp)
190 /* Open connection if not already done. */
191 if (daemon_sock == INT_MIN)
192 setutent_daemon ();
194 if (daemon_sock < 0)
195 /* Something went wrong. */
196 return NULL;
198 /* Send request to the daemon. */
199 if (do_pututline (daemon_sock, utmp) < 0)
200 return NULL;
202 return (struct utmp *)utmp;
206 static int
207 updwtmp_daemon (const char *file, const struct utmp *utmp)
209 int sock;
211 /* Only try to open for both reading and writing. */
212 sock = open_socket (_PATH_UTMPD_RW);
213 if (sock < 0)
214 return -1;
216 /* Send request to the daemon. */
217 if (do_updwtmp (sock, file, utmp) < 0)
219 close (sock);
220 return -1;
223 close (sock);
224 return 0;
228 static int
229 do_setutent (int sock)
231 setutent_request *request;
232 setutent_reply reply;
233 size_t size;
235 size = sizeof (setutent_request) + strlen (__libc_utmp_file_name) + 1;
237 request = malloc (size);
238 if (request == NULL)
239 return -1;
241 request->header.version = UTMPD_VERSION;
242 request->header.size = size;
243 request->header.type = UTMPD_REQ_SETUTENT;
244 strcpy (request->file, __libc_utmp_file_name);
246 reply.header.version = UTMPD_VERSION;
247 reply.header.size = sizeof (setutent_reply);
248 reply.header.type = UTMPD_REQ_SETUTENT;
250 if (send_request (sock, &request->header, &reply.header) < 0)
252 free (request);
253 return -1;
256 if (reply.result < 0)
257 __set_errno (reply.errnum);
259 free (request);
260 return reply.result;
263 static int
264 do_getutent (int sock, struct utmp *buffer)
266 getutent_request request;
267 getutent_reply reply;
269 request.header.version = UTMPD_VERSION;
270 request.header.size = sizeof (getutent_request);
271 request.header.type = UTMPD_REQ_GETUTENT;
273 reply.header.version = UTMPD_VERSION;
274 reply.header.size = sizeof (getutent_reply);
275 reply.header.type = UTMPD_REQ_GETUTENT;
277 if (send_request (sock, &request.header, &reply.header) < 0)
278 return -1;
280 if (reply.result < 0)
281 __set_errno (reply.errnum);
282 else
283 memcpy (buffer, &reply.entry, sizeof (struct utmp));
285 return reply.result;
288 static int
289 do_endutent (int sock)
291 endutent_request request;
292 endutent_reply reply;
294 request.header.version = UTMPD_VERSION;
295 request.header.size = sizeof (endutent_request);
296 request.header.type = UTMPD_REQ_ENDUTENT;
298 reply.header.version = UTMPD_VERSION;
299 reply.header.size = sizeof (endutent_reply);
300 reply.header.type = UTMPD_REQ_ENDUTENT;
302 if (send_request (sock, &request.header, &reply.header) < 0)
303 return -1;
305 if (reply.result < 0)
306 __set_errno (reply.errnum);
308 return reply.result;
311 static int
312 do_getutline (int sock, const struct utmp *line, struct utmp *buffer)
314 getutline_request request;
315 getutline_reply reply;
317 request.header.version = UTMPD_VERSION;
318 request.header.size = sizeof (getutline_request);
319 request.header.type = UTMPD_REQ_GETUTLINE;
320 memcpy (&request.line, line, sizeof (struct utmp));
322 reply.header.version = UTMPD_VERSION;
323 reply.header.size = sizeof (getutline_reply);
324 reply.header.type = UTMPD_REQ_GETUTLINE;
326 if (send_request (sock, &request.header, &reply.header) < 0)
327 return -1;
329 if (reply.result < 0)
330 __set_errno (reply.errnum);
331 else
332 memcpy (buffer, &reply.entry, sizeof (struct utmp));
334 return reply.result;
337 static int
338 do_getutid (int sock, const struct utmp *id, struct utmp *buffer)
340 getutid_request request;
341 getutid_reply reply;
343 request.header.version = UTMPD_VERSION;
344 request.header.size = sizeof (getutid_request);
345 request.header.type = UTMPD_REQ_GETUTID;
346 memcpy (&request.id, id, sizeof (struct utmp));
348 reply.header.version = UTMPD_VERSION;
349 reply.header.size = sizeof (getutid_reply);
350 reply.header.type = UTMPD_REQ_GETUTID;
352 if (send_request (sock, &request.header, &reply.header) < 0)
353 return -1;
355 if (reply.result < 0)
356 __set_errno (reply.errnum);
357 else
358 memcpy (buffer, &reply.entry, sizeof (struct utmp));
360 return reply.result;
363 static int
364 do_pututline (int sock, const struct utmp *utmp)
366 pututline_request request;
367 pututline_reply reply;
369 request.header.version = UTMPD_VERSION;
370 request.header.size = sizeof (pututline_request);
371 request.header.type = UTMPD_REQ_PUTUTLINE;
372 memcpy (&request.utmp, utmp, sizeof (struct utmp));
374 reply.header.version = UTMPD_VERSION;
375 reply.header.size = sizeof (pututline_reply);
376 reply.header.type = UTMPD_REQ_PUTUTLINE;
378 if (send_request (sock, &request.header, &reply.header) < 0)
379 return -1;
381 if (reply.result < 0)
382 __set_errno (reply.errnum);
384 return reply.result;
387 static int
388 do_updwtmp (int sock, const char *file, const struct utmp *utmp)
390 updwtmp_request *request;
391 updwtmp_reply reply;
392 size_t size;
394 size = sizeof (updwtmp_request) + strlen (file) + 1;
396 request = malloc (size);
397 if (request == NULL)
398 return -1;
400 request->header.version = UTMPD_VERSION;
401 request->header.size = size;
402 request->header.type = UTMPD_REQ_UPDWTMP;
403 memcpy (&request->utmp, utmp, sizeof (struct utmp));
404 strcpy (request->file, file);
406 reply.header.version = UTMPD_VERSION;
407 reply.header.size = sizeof (updwtmp_reply);
408 reply.header.type = UTMPD_REQ_UPDWTMP;
410 if (send_request (sock, &request->header, &reply.header) < 0)
412 free (request);
413 return -1;
416 if (reply.result < 0)
417 __set_errno (reply.errnum);
419 free (request);
420 return reply.result;
424 /* Create a socket connected to NAME. */
425 static int
426 open_socket (const char *name)
428 struct sockaddr_un addr;
429 int sock;
431 sock = socket (PF_UNIX, SOCK_STREAM, 0);
432 if (sock < 0)
433 return -1;
435 addr.sun_family = AF_UNIX;
436 strcpy (addr.sun_path, name);
437 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
439 close (sock);
440 return -1;
443 return sock;
446 /* Send REQUEST to SOCK, and wait for reply. Returns 0 if successful,
447 storing the reply in REPLY, and -1 if not. */
448 static int
449 send_request (int sock, const request_header *request,
450 reply_header *reply)
452 reply_header header;
453 ssize_t nbytes;
455 nbytes = write (sock, request, request->size);
456 if (nbytes != (ssize_t) request->size)
457 return -1;
459 nbytes = read (sock, &header, sizeof (reply_header));
460 if (nbytes != sizeof (reply_header))
461 return -1;
463 if (reply->version != header.version
464 || reply->size != header.size
465 || reply->type != header.type)
466 return -1;
468 nbytes = read (sock, reply + 1, reply->size - sizeof (reply_header));
469 if (nbytes != (ssize_t) (reply->size - sizeof (reply_header)))
470 return -1;
472 return 0;