Remove unneccesary header files.
[kopensolaris-gnu/glibc.git] / login / utmp_daemon.c
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.
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 <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>
28
29 #include "utmp-private.h"
30 #include "programs/utmpd.h"
31
32
33 /* Descriptor for the socket.  */
34 static int daemon_sock = INT_MIN;
35
36
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);
47
48 /* Jump table for daemon functions.  */
49 struct utfuncs __libc_utmp_daemon_functions =
50 {
51   setutent_daemon,
52   getutent_r_daemon,
53   getutid_r_daemon,
54   getutline_r_daemon,
55   pututline_daemon,
56   endutent_daemon,
57   updwtmp_daemon
58 };
59
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);
70
71 static int open_socket (const char *name);
72 static int send_request (int sock, const request_header *request,
73                          reply_header *reply);
74
75
76 static int
77 setutent_daemon (void)
78 {
79   if (access (_PATH_UTMPD_RW, F_OK) == -1
80       && access (_PATH_UTMPD_RO, F_OK) == -1)
81     return 0;
82     
83   if (daemon_sock < 0)
84     {
85       daemon_sock = open_socket (_PATH_UTMPD_RW);
86       if (daemon_sock < 0)
87         {
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;
92         }
93     }
94
95   /* Send request to the daemon.  */
96   if (do_setutent (daemon_sock) < 0)
97     return 0;
98
99   return 1;
100 }
101
102
103 static void
104 endutent_daemon (void)
105 {
106   if (daemon_sock >= 0)
107     {
108       /* Send request to the daemon.  */
109       do_endutent (daemon_sock);
110       close (daemon_sock);
111     }
112
113   daemon_sock = INT_MIN;
114 }
115
116
117 static int
118 getutent_r_daemon (struct utmp *buffer, struct utmp **result)
119 {
120   /* Open connection if not already done.  */
121   if (daemon_sock == INT_MIN)
122     setutent_daemon ();
123
124   if (daemon_sock < 0)
125     {
126       /* Not available.  */
127       *result = NULL;
128       return -1;
129     }
130
131   /* Send request to the daemon.  */
132   if (do_getutent (daemon_sock, buffer) < 0)
133     {
134       *result = NULL;
135       return -1;;
136     }
137
138   *result = buffer;
139   return 0;
140 }
141
142
143 static int
144 getutline_r_daemon (const struct utmp *line, struct utmp *buffer,
145                     struct utmp **result)
146 {
147   if (daemon_sock < 0)
148     {
149       *result = NULL;
150       return -1;
151     }
152
153   /* Send request to the daemon.  */
154   if (do_getutline (daemon_sock, line, buffer) < 0)
155     {
156       *result = NULL;
157       return -1;;
158     }
159
160   *result = buffer;
161   return 0;
162 }
163
164
165 static int
166 getutid_r_daemon (const struct utmp *id, struct utmp *buffer,
167                   struct utmp **result)
168 {
169   if (daemon_sock < 0)
170     {
171       *result = NULL;
172       return -1;
173     }
174
175   /* Send request to the daemon.  */
176   if (do_getutid (daemon_sock, id, buffer) < 0)
177     {
178       *result = NULL;
179       return -1;
180     }
181
182   *result = buffer;
183   return 0;
184 }
185
186
187 static struct utmp *
188 pututline_daemon (const struct utmp *utmp)
189 {
190   /* Open connection if not already done.  */
191   if (daemon_sock == INT_MIN)
192     setutent_daemon ();
193
194   if (daemon_sock < 0)
195     /* Something went wrong.  */
196     return NULL;
197
198   /* Send request to the daemon.  */
199   if (do_pututline (daemon_sock, utmp) < 0)
200     return NULL;
201
202   return (struct utmp *)utmp;
203 }
204
205
206 static int
207 updwtmp_daemon (const char *file, const struct utmp *utmp)
208 {
209   int sock;
210
211   /* Only try to open for both reading and writing.  */
212   sock = open_socket (_PATH_UTMPD_RW);
213   if (sock < 0)
214     return -1;
215
216   /* Send request to the daemon.  */
217   if (do_updwtmp (sock, file, utmp) < 0)
218     {
219       close (sock);
220       return -1;
221     }
222
223   close (sock);
224   return 0;
225 }
226
227
228 static int
229 do_setutent (int sock)
230 {
231   setutent_request *request;
232   setutent_reply reply;
233   size_t size;
234
235   size = sizeof (setutent_request) + strlen (__libc_utmp_file_name) + 1;
236   
237   request = malloc (size);
238   if (request == NULL)
239     return -1;
240   
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);
245
246   reply.header.version = UTMPD_VERSION;
247   reply.header.size = sizeof (setutent_reply);
248   reply.header.type = UTMPD_REQ_SETUTENT;
249
250   if (send_request (sock, &request->header, &reply.header) < 0)
251     {
252       free (request);
253       return -1;
254     }
255
256   if (reply.result < 0)
257     __set_errno (reply.errnum);
258
259   free (request);
260   return reply.result;
261 }
262
263 static int
264 do_getutent (int sock, struct utmp *buffer)
265 {
266   getutent_request request;
267   getutent_reply reply;
268
269   request.header.version = UTMPD_VERSION;
270   request.header.size = sizeof (getutent_request);
271   request.header.type = UTMPD_REQ_GETUTENT;
272
273   reply.header.version = UTMPD_VERSION;
274   reply.header.size = sizeof (getutent_reply);
275   reply.header.type = UTMPD_REQ_GETUTENT;
276
277   if (send_request (sock, &request.header, &reply.header) < 0)
278     return -1;
279
280   if (reply.result < 0)
281     __set_errno (reply.errnum);
282   else
283     memcpy (buffer, &reply.entry, sizeof (struct utmp));
284
285   return reply.result;
286 }
287
288 static int
289 do_endutent (int sock)
290 {
291   endutent_request request;
292   endutent_reply reply;
293
294   request.header.version = UTMPD_VERSION;
295   request.header.size = sizeof (endutent_request);
296   request.header.type = UTMPD_REQ_ENDUTENT;
297
298   reply.header.version = UTMPD_VERSION;
299   reply.header.size = sizeof (endutent_reply);
300   reply.header.type = UTMPD_REQ_ENDUTENT;
301
302   if (send_request (sock, &request.header, &reply.header) < 0)
303     return -1;
304
305   if (reply.result < 0)
306     __set_errno (reply.errnum);
307
308   return reply.result;
309 }
310
311 static int
312 do_getutline (int sock, const struct utmp *line, struct utmp *buffer)
313 {
314   getutline_request request;
315   getutline_reply reply;
316
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));
321
322   reply.header.version = UTMPD_VERSION;
323   reply.header.size = sizeof (getutline_reply);
324   reply.header.type = UTMPD_REQ_GETUTLINE;
325
326   if (send_request (sock, &request.header, &reply.header) < 0)
327     return -1;
328
329   if (reply.result < 0)
330     __set_errno (reply.errnum);
331   else
332     memcpy (buffer, &reply.entry, sizeof (struct utmp));
333
334   return reply.result;
335 }
336
337 static int
338 do_getutid (int sock, const struct utmp *id, struct utmp *buffer)
339 {
340   getutid_request request;
341   getutid_reply reply;
342
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));
347
348   reply.header.version = UTMPD_VERSION;
349   reply.header.size = sizeof (getutid_reply);
350   reply.header.type = UTMPD_REQ_GETUTID;
351
352   if (send_request (sock, &request.header, &reply.header) < 0)
353     return -1;
354
355   if (reply.result < 0)
356     __set_errno (reply.errnum);
357   else
358     memcpy (buffer, &reply.entry, sizeof (struct utmp));
359
360   return reply.result;
361 }
362
363 static int
364 do_pututline (int sock, const struct utmp *utmp)
365 {
366   pututline_request request;
367   pututline_reply reply;
368
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));
373
374   reply.header.version = UTMPD_VERSION;
375   reply.header.size = sizeof (pututline_reply);
376   reply.header.type = UTMPD_REQ_PUTUTLINE;
377
378   if (send_request (sock, &request.header, &reply.header) < 0)
379     return -1;
380
381   if (reply.result < 0)
382     __set_errno (reply.errnum);
383
384   return reply.result;
385 }
386
387 static int
388 do_updwtmp (int sock, const char *file, const struct utmp *utmp)
389 {
390   updwtmp_request *request;
391   updwtmp_reply reply;
392   size_t size;
393
394   size = sizeof (updwtmp_request) + strlen (file) + 1;
395   
396   request = malloc (size);
397   if (request == NULL)
398     return -1;
399   
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);
405
406   reply.header.version = UTMPD_VERSION;
407   reply.header.size = sizeof (updwtmp_reply);
408   reply.header.type = UTMPD_REQ_UPDWTMP;
409
410   if (send_request (sock, &request->header, &reply.header) < 0)
411     {
412       free (request);
413       return -1;
414     }
415
416   if (reply.result < 0)
417     __set_errno (reply.errnum);
418
419   free (request);
420   return reply.result;
421 }
422
423
424 /* Create a socket connected to NAME.  */
425 static int
426 open_socket (const char *name)
427 {
428   struct sockaddr_un addr;
429   int sock;
430
431   sock = socket (PF_UNIX, SOCK_STREAM, 0);
432   if (sock < 0)
433     return -1;
434
435   addr.sun_family = AF_UNIX;
436   strcpy (addr.sun_path, name);
437   if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
438     {
439       close (sock);
440       return -1;
441     }
442
443   return sock;
444 }
445
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)
451 {
452   reply_header header;
453   ssize_t nbytes;
454
455   nbytes = write (sock, request, request->size);
456   if (nbytes != (ssize_t) request->size)
457     return -1;
458
459   nbytes = read (sock, &header, sizeof (reply_header));
460   if (nbytes != sizeof (reply_header))
461     return -1;
462
463   if (reply->version != header.version
464       || reply->size != header.size
465       || reply->type != header.type)
466     return -1;
467
468   nbytes = read (sock, reply + 1, reply->size - sizeof (reply_header));
469   if (nbytes != (ssize_t) (reply->size - sizeof (reply_header)))
470     return -1;
471
472   return 0;
473 }