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