Use _CALL_DL_FCT to call function from dynamically loaded object.
[kopensolaris-gnu/glibc.git] / login / utmp_daemon.c
1 /* Copyright (C) 1997, 1998 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 <assert.h>
21 #include <errno.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 = -1;
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_getutid (int sock, const struct utmp *id,
63                             struct utmp *buffer);
64 static int do_pututline (int sock, const struct utmp *utmp);
65 static int do_getutline (int sock, const struct utmp *line,
66                          struct utmp *buffer);
67 static int do_pututline (int sock, const struct utmp *utmp);
68 static int do_endutent (int sock);
69 static int do_updwtmp (int sock, const char *file,
70                        const struct utmp *utmp);
71
72 static int open_socket (const char *name);
73 static int send_request (int sock, const request_header *request,
74                          reply_header *reply);
75
76
77 static int
78 setutent_daemon (void)
79 {
80   if (access (_PATH_UTMPD_RW, F_OK) == -1
81       && access (_PATH_UTMPD_RO, F_OK) == -1)
82     return 0;
83
84   if (daemon_sock < 0)
85     {
86       daemon_sock = open_socket (_PATH_UTMPD_RW);
87       if (daemon_sock < 0)
88         {
89           /* Hhm, read-write access did not work.  Try read-only.  */
90           daemon_sock = open_socket (_PATH_UTMPD_RO);
91           if (daemon_sock < 0)
92             return 0;
93         }
94     }
95
96   /* Send request to the daemon.  */
97   if (do_setutent (daemon_sock) < 0)
98     return 0;
99
100   return 1;
101 }
102
103
104 static int
105 getutent_r_daemon (struct utmp *buffer, struct utmp **result)
106 {
107   assert (daemon_sock >= 0);
108
109   /* Send request to the daemon.  */
110   if (do_getutent (daemon_sock, buffer) < 0)
111     {
112       *result = NULL;
113       return -1;;
114     }
115
116   *result = buffer;
117   return 0;
118 }
119
120
121 static int
122 getutid_r_daemon (const struct utmp *id, struct utmp *buffer,
123                   struct utmp **result)
124 {
125   assert (daemon_sock >= 0);
126
127   /* Send request to the daemon.  */
128   if (do_getutid (daemon_sock, id, buffer) < 0)
129     {
130       *result = NULL;
131       return -1;
132     }
133
134   *result = buffer;
135   return 0;
136 }
137
138
139 static int
140 getutline_r_daemon (const struct utmp *line, struct utmp *buffer,
141                     struct utmp **result)
142 {
143   assert (daemon_sock >= 0);
144
145   /* Send request to the daemon.  */
146   if (do_getutline (daemon_sock, line, buffer) < 0)
147     {
148       *result = NULL;
149       return -1;
150     }
151
152   *result = buffer;
153   return 0;
154 }
155
156
157 static struct utmp *
158 pututline_daemon (const struct utmp *utmp)
159 {
160   assert (daemon_sock >= 0);
161
162   /* Send request to the daemon.  */
163   if (do_pututline (daemon_sock, utmp) < 0)
164     return NULL;
165
166   return (struct utmp *)utmp;
167 }
168
169
170 static void
171 endutent_daemon (void)
172 {
173   assert (daemon_sock >= 0);
174
175   /* Send request to the daemon.  */
176   do_endutent (daemon_sock);
177
178   close (daemon_sock);
179   daemon_sock = -1;
180 }
181
182
183 static int
184 updwtmp_daemon (const char *file, const struct utmp *utmp)
185 {
186   int sock;
187
188   /* Only try to open for both reading and writing.  */
189   sock = open_socket (_PATH_UTMPD_RW);
190   if (sock < 0)
191     return -1;
192
193   /* Send request to the daemon.  */
194   if (do_updwtmp (sock, file, utmp) < 0)
195     {
196       close (sock);
197       return -1;
198     }
199
200   close (sock);
201   return 0;
202 }
203
204
205 static int
206 do_setutent (int sock)
207 {
208   setutent_request *request;
209   setutent_reply reply;
210   size_t size;
211   size_t name_len;
212
213   name_len = strlen (__libc_utmp_file_name) + 1;
214   size = sizeof (setutent_request) + name_len;
215
216   request = malloc (size);
217   if (request == NULL)
218     return -1;
219
220   request->header.version = UTMPD_VERSION;
221   request->header.size = size;
222   request->header.type = UTMPD_REQ_SETUTENT;
223   memcpy (request->file, __libc_utmp_file_name, name_len);
224
225   reply.header.version = UTMPD_VERSION;
226   reply.header.size = sizeof (setutent_reply);
227   reply.header.type = UTMPD_REQ_SETUTENT;
228
229   if (send_request (sock, &request->header, &reply.header) < 0)
230     {
231       free (request);
232       return -1;
233     }
234
235   if (reply.result < 0)
236     __set_errno (reply.errnum);
237
238   free (request);
239   return reply.result;
240 }
241
242 static int
243 do_getutent (int sock, struct utmp *buffer)
244 {
245   getutent_request request;
246   getutent_reply reply;
247
248   request.header.version = UTMPD_VERSION;
249   request.header.size = sizeof (getutent_request);
250   request.header.type = UTMPD_REQ_GETUTENT;
251
252   reply.header.version = UTMPD_VERSION;
253   reply.header.size = sizeof (getutent_reply);
254   reply.header.type = UTMPD_REQ_GETUTENT;
255
256   if (send_request (sock, &request.header, &reply.header) < 0)
257     return -1;
258
259   if (reply.result < 0)
260     __set_errno (reply.errnum);
261   else
262     memcpy (buffer, &reply.entry, sizeof (struct utmp));
263
264   return reply.result;
265 }
266
267 static int
268 do_getutid (int sock, const struct utmp *id, struct utmp *buffer)
269 {
270   getutid_request request;
271   getutid_reply reply;
272
273   request.header.version = UTMPD_VERSION;
274   request.header.size = sizeof (getutid_request);
275   request.header.type = UTMPD_REQ_GETUTID;
276   memcpy (&request.id, id, sizeof (struct utmp));
277
278   reply.header.version = UTMPD_VERSION;
279   reply.header.size = sizeof (getutid_reply);
280   reply.header.type = UTMPD_REQ_GETUTID;
281
282   if (send_request (sock, &request.header, &reply.header) < 0)
283     return -1;
284
285   if (reply.result < 0)
286     __set_errno (reply.errnum);
287   else
288     memcpy (buffer, &reply.entry, sizeof (struct utmp));
289
290   return reply.result;
291 }
292
293 static int
294 do_getutline (int sock, const struct utmp *line, struct utmp *buffer)
295 {
296   getutline_request request;
297   getutline_reply reply;
298
299   request.header.version = UTMPD_VERSION;
300   request.header.size = sizeof (getutline_request);
301   request.header.type = UTMPD_REQ_GETUTLINE;
302   memcpy (&request.line, line, sizeof (struct utmp));
303
304   reply.header.version = UTMPD_VERSION;
305   reply.header.size = sizeof (getutline_reply);
306   reply.header.type = UTMPD_REQ_GETUTLINE;
307
308   if (send_request (sock, &request.header, &reply.header) < 0)
309     return -1;
310
311   if (reply.result < 0)
312     __set_errno (reply.errnum);
313   else
314     memcpy (buffer, &reply.entry, sizeof (struct utmp));
315
316   return reply.result;
317 }
318
319 static int
320 do_pututline (int sock, const struct utmp *utmp)
321 {
322   pututline_request request;
323   pututline_reply reply;
324
325   request.header.version = UTMPD_VERSION;
326   request.header.size = sizeof (pututline_request);
327   request.header.type = UTMPD_REQ_PUTUTLINE;
328   memcpy (&request.utmp, utmp, sizeof (struct utmp));
329
330   reply.header.version = UTMPD_VERSION;
331   reply.header.size = sizeof (pututline_reply);
332   reply.header.type = UTMPD_REQ_PUTUTLINE;
333
334   if (send_request (sock, &request.header, &reply.header) < 0)
335     return -1;
336
337   if (reply.result < 0)
338     __set_errno (reply.errnum);
339
340   return reply.result;
341 }
342
343 static int
344 do_endutent (int sock)
345 {
346   endutent_request request;
347   endutent_reply reply;
348
349   request.header.version = UTMPD_VERSION;
350   request.header.size = sizeof (endutent_request);
351   request.header.type = UTMPD_REQ_ENDUTENT;
352
353   reply.header.version = UTMPD_VERSION;
354   reply.header.size = sizeof (endutent_reply);
355   reply.header.type = UTMPD_REQ_ENDUTENT;
356
357   if (send_request (sock, &request.header, &reply.header) < 0)
358     return -1;
359
360   if (reply.result < 0)
361     __set_errno (reply.errnum);
362
363   return reply.result;
364 }
365
366 static int
367 do_updwtmp (int sock, const char *file, const struct utmp *utmp)
368 {
369   updwtmp_request *request;
370   updwtmp_reply reply;
371   size_t size;
372   size_t file_len;
373
374   file_len = strlen (file) + 1;
375   size = sizeof (updwtmp_request) + file_len;
376
377   request = malloc (size);
378   if (request == NULL)
379     return -1;
380
381   request->header.version = UTMPD_VERSION;
382   request->header.size = size;
383   request->header.type = UTMPD_REQ_UPDWTMP;
384   memcpy (&request->utmp, utmp, sizeof (struct utmp));
385   memcpy (request->file, file, file_len);
386
387   reply.header.version = UTMPD_VERSION;
388   reply.header.size = sizeof (updwtmp_reply);
389   reply.header.type = UTMPD_REQ_UPDWTMP;
390
391   if (send_request (sock, &request->header, &reply.header) < 0)
392     {
393       free (request);
394       return -1;
395     }
396
397   if (reply.result < 0)
398     __set_errno (reply.errnum);
399
400   free (request);
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 }