Let ATTR LIST bypass an ACL for an element.
[pwmd.git] / src / status.c
blob2ac239e325cdd3366c3e3905073ace0062a3caec
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <pthread.h>
25 #include <stdarg.h>
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
28 #include <errno.h>
30 #ifdef HAVE_LINUX_SOCKIOS_H
31 #include <linux/sockios.h>
32 #endif
34 #ifdef HAVE_SYS_FILIO_H
35 #include <sys/filio.h>
36 #endif
38 #include "pwmd-error.h"
39 #include "mutex.h"
40 #include "util-misc.h"
41 #include "common.h"
42 #include "util-string.h"
43 #include "status.h"
44 #include "cache.h"
45 #include "mem.h"
47 gpg_error_t
48 send_status (assuan_context_t ctx, status_msg_t which, const char *fmt, ...)
50 const char *line = NULL;
51 char buf[ASSUAN_LINELENGTH + 1];
52 const char *status = NULL;
53 va_list ap;
54 char *p;
55 #ifdef WITH_GNUTLS
56 struct client_s *client = ctx ? assuan_get_pointer (ctx) : NULL;
57 #endif
58 gpg_error_t rc = 0;
60 if (fmt)
62 va_start (ap, fmt);
63 vsnprintf (buf, sizeof (buf), fmt, ap);
64 va_end (ap);
65 line = buf;
68 switch (which)
70 case STATUS_GENKEY:
71 status = "GENKEY";
72 break;
73 case STATUS_XFER:
74 status = "XFER";
75 break;
76 case STATUS_CACHE:
77 snprintf (buf, sizeof (buf), "%u", cache_file_count ());
78 line = buf;
79 status = "CACHE";
80 break;
81 case STATUS_CLIENTS:
82 MUTEX_LOCK (&cn_mutex);
83 snprintf (buf, sizeof (buf), "%i", slist_length (cn_thread_list));
84 line = buf;
85 MUTEX_UNLOCK (&cn_mutex);
86 status = "CLIENTS";
87 break;
88 case STATUS_LOCKED:
89 status = "LOCKED";
90 line = _("Waiting for lock");
91 break;
92 case STATUS_ENCRYPT:
93 status = "ENCRYPT";
94 break;
95 case STATUS_DECRYPT:
96 status = "DECRYPT";
97 break;
98 case STATUS_NEWFILE:
99 status = "NEWFILE";
100 break;
101 case STATUS_KEEPALIVE:
102 status = "KEEPALIVE";
103 break;
104 case STATUS_AGENT:
105 p = strchr (line, ' ');
106 if (!p)
108 status = line;
109 line = NULL;
111 else
113 *p = 0;
114 status = line;
115 line = line + strlen (status) + 1;
117 break;
118 case STATUS_STATE:
119 status = "STATE";
120 break;
123 if (!ctx)
125 log_write ("%s %s", status, line ? line : "");
126 return 0;
129 #ifdef WITH_GNUTLS
130 if (client->thd->remote && which == STATUS_KEEPALIVE)
132 int buffered = 0;
134 #ifdef HAVE_DECL_SIOCOUTQ
135 if (ioctl (client->thd->fd, SIOCOUTQ, &buffered) == -1)
136 log_write ("%s(%i): ioctl: %s", __FUNCTION__, __LINE__,
137 pwmd_strerror (gpg_error_from_errno (errno)));
138 #elif defined (HAVE_DECL_FIONWRITE)
139 if (ioctl (client->thd->fd, FIONWRITE, &buffered) == -1)
140 log_write ("%s(%i): ioctl: %s", __FUNCTION__, __LINE__,
141 pwmd_strerror (gpg_error_from_errno (errno)));
142 #else
143 if (1)
145 int sndbuf;
146 socklen_t len = sizeof(int);
148 if (getsockopt (client->thd->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf,
149 &len) == -1)
150 log_write ("%s(%i): getsockopt: %s", __FUNCTION__, __LINE__,
151 pwmd_strerror (gpg_error_from_errno (errno)));
152 else
154 int lowat;
156 len = sizeof(int);
157 if (getsockopt (client->thd->fd, SOL_SOCKET, SO_SNDLOWAT,
158 &lowat, &len) == -1)
159 log_write ("%s(%i): getsockopt: %s", __FUNCTION__,
160 __LINE__, pwmd_strerror (gpg_error_from_errno (errno)));
161 else
163 len = sizeof(int);
164 if (setsockopt (client->thd->fd, SOL_SOCKET, SO_SNDLOWAT,
165 &sndbuf, len) == -1)
166 log_write ("%s(%i): setsockopt: %s", __FUNCTION__,
167 __LINE__,
168 pwmd_strerror (gpg_error_from_errno (errno)));
169 else
171 struct timeval tv = { 0, 0 };
172 fd_set wfds;
173 int n;
175 buffered = client->thd->last_buffer_size + 1;
176 FD_ZERO (&wfds);
177 FD_SET (client->thd->fd, &wfds);
178 n = select (client->thd->fd + 1, NULL, &wfds, NULL, &tv);
179 len = sizeof(int);
180 if (setsockopt (client->thd->fd, SOL_SOCKET, SO_SNDLOWAT,
181 &lowat, len) == -1)
182 log_write ("%s(%i): setsockopt: %s", __FUNCTION__,
183 __LINE__,
184 pwmd_strerror (gpg_error_from_errno (errno)));
185 if (n > 0 && FD_ISSET (client->thd->fd, &wfds))
186 buffered = 0;
191 #endif
192 if (buffered)
194 int interval = config_get_integer ("global", "keepalive_interval");
195 int timeout = config_get_integer ("global", "tls_timeout");
197 if (buffered < client->thd->last_buffer_size)
198 client->thd->buffer_timeout = 0;
200 client->thd->last_buffer_size = buffered;
202 if (++client->thd->buffer_timeout * interval >= timeout)
203 rc = gpg_error (GPG_ERR_ETIMEDOUT);
205 else
206 client->thd->buffer_timeout = client->thd->last_buffer_size = 0;
208 #endif
210 if (!rc)
211 rc = assuan_write_status (ctx, status, line);
213 #ifdef WITH_GNUTLS
214 if (client->thd->remote && which != STATUS_KEEPALIVE)
215 client->thd->buffer_timeout = client->thd->last_buffer_size = 0;
216 #endif
218 return rc;
221 static void
222 do_send_status_all (status_msg_t s, const char *line, pthread_t *not_tid,
223 int invoker)
225 MUTEX_LOCK (&cn_mutex);
226 int i = 0;
227 int t = slist_length (cn_thread_list);
229 for (; i < t; i++)
231 struct client_thread_s *thd = slist_nth_data (cn_thread_list, i);
232 struct status_msg_s *msg, *p;
233 char c = 0xff;
234 int match = 0;
236 if (not_tid && pthread_equal (*not_tid, thd->tid))
237 continue;
239 /* Only want to send this status message to invoking_user clients'. */
240 if (thd->state == CLIENT_STATE_UNKNOWN
241 || (invoker && peer_is_invoker (thd->cl)))
242 continue;
244 MUTEX_LOCK (&thd->status_mutex);
246 for (p = thd->msg_queue; p; p = p->next)
248 if (p->s == s)
250 match = 1;
251 break;
255 if (match && s != STATUS_STATE)
257 xfree (p->line);
258 p->line = line ? str_dup (line) : NULL;
260 if (!thd->wrote_status)
261 write (thd->status_msg_pipe[1], &c, 1);
263 thd->wrote_status = 1;
264 MUTEX_UNLOCK (&thd->status_mutex);
265 continue;
268 msg = xcalloc (1, sizeof (struct status_msg_s));
269 msg->s = s;
270 msg->line = line ? str_dup (line) : NULL;
272 for (p = thd->msg_queue; p && p->next; p = p->next);
273 if (!p)
274 thd->msg_queue = msg;
275 else
276 p->next = msg;
278 if (!thd->wrote_status)
279 write (thd->status_msg_pipe[1], &c, 1);
281 thd->wrote_status = 1;
282 MUTEX_UNLOCK (&thd->status_mutex);
285 MUTEX_UNLOCK (&cn_mutex);
288 void
289 send_status_all_not_self (int invoker, status_msg_t s, const char *fmt, ...)
291 char *line = NULL;
292 pthread_t tid = pthread_self ();
294 if (fmt)
296 va_list ap;
298 va_start (ap, fmt);
299 str_vasprintf (&line, fmt, ap);
300 va_end (ap);
303 do_send_status_all (s, line, &tid, invoker);
304 xfree (line);
307 void
308 send_status_all (status_msg_t s, const char *fmt, ...)
310 char *line = NULL;
312 if (fmt)
314 va_list ap;
316 va_start (ap, fmt);
317 str_vasprintf (&line, fmt, ap);
318 va_end (ap);
321 do_send_status_all (s, line, NULL, 0);
322 xfree (line);