Fix ACL crash for non-existing user.
[pwmd.git] / src / util-misc.c
blobff89bc80ddaa3518575e1fc265539f24795400ba
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 <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <pwd.h>
35 #include "pwmd-error.h"
36 #include <gcrypt.h>
37 #include "util-misc.h"
38 #include "util-string.h"
39 #include "mutex.h"
40 #include "cache.h"
41 #include "mem.h"
43 extern void log_write (const char *fmt, ...);
45 int
46 valid_filename (const char *filename)
48 const char *p;
50 if (!filename || !*filename)
51 return 0;
53 if (filename[0] == '-' && filename[1] == 0)
54 return 0;
56 for (p = filename; *p; p++)
58 if (*p == '/' || isspace (*p))
59 return 0;
62 return 1;
65 /* If 'user' is null then lookup entry for 'uid'. Caller must free 'buf'. */
66 struct passwd *
67 get_pwd_struct (const char *user, uid_t uid, struct passwd *pw, char **buf)
69 #ifdef HAVE_GETPWNAM_R
70 struct passwd *result;
71 size_t len;
73 len = sysconf (_SC_GETPW_R_SIZE_MAX);
74 if (len == -1)
75 len = 16384;
77 *buf = xmalloc (len);
78 if (!*buf)
79 return NULL;
81 if (user)
83 if (!getpwnam_r (user, pw, *buf, len, &result))
84 return result;
86 else
88 if (!getpwuid_r (uid, pw, *buf, len, &result))
89 return result;
92 return NULL;
93 #else
94 if (buf)
95 *buf = NULL;
97 if (user)
98 return getpwnam (user);
100 return getpwuid (uid);
101 #endif
104 static char *
105 get_pwd_entry(uid_t uid, int which)
107 char *buf;
108 struct passwd pw;
109 struct passwd *result = get_pwd_struct (NULL, uid, &pw, &buf);
110 char *value = NULL;
112 if (!result)
113 return NULL;
115 if (result)
117 if (!which)
118 value = str_dup (result->pw_dir);
119 else
120 value = str_dup (result->pw_name);
123 xfree (buf);
124 return value;
127 char *
128 get_username (uid_t uid)
130 return get_pwd_entry (uid, 1);
133 char *
134 get_home_dir ()
136 if (home_directory)
137 return home_directory;
139 home_directory = get_pwd_entry (getuid(), 0);
140 return home_directory;
143 char *
144 expand_homedir (char *str)
146 char *p = str;
148 if (*p++ == '~')
150 char *dir = get_pwd_entry(getuid(), 0);
151 char *s = str_asprintf ("%s%s", dir, p);
153 xfree (dir);
154 return s;
157 return str_dup (str);
160 gpg_error_t
161 parse_options (char **line, struct argv_s * args[], void *data)
163 char *p = *line;
164 gpg_error_t rc = 0;
166 for (; p && *p; p++)
168 while (*p == ' ')
169 p++;
171 if (!*p)
172 break;
174 if (*p == '-' && *(p + 1) == '-')
176 p += 2;
177 char opt[255] = { 0 }, value[255] =
180 char *tp;
181 unsigned len;
183 if (!*p || *p == ' ')
185 if (*p)
186 p++;
188 break;
191 for (tp = opt, len = 0; *p; p++, len++)
193 if (len + 1 == 255)
194 return GPG_ERR_LINE_TOO_LONG;
196 if (*p == ' ' || *p == '=')
198 *tp = 0;
200 if (*p == '=')
202 int inquote = 0;
204 p++;
206 for (tp = value, len = 0; *p; p++, len++)
208 if (len + 1 == 255)
209 return GPG_ERR_LINE_TOO_LONG;
211 if (*p == '\"')
213 inquote = !inquote;
214 continue;
216 else if (*p == ' ' && !inquote)
217 break;
219 *tp++ = *p;
222 *tp = 0;
225 break;
228 *tp++ = *p;
231 *tp = 0;
232 int match = 0;
234 for (int i = 0; args[i]; i++)
236 if (!strcmp (args[i]->opt, opt))
238 log_write1 ("param: name='%s' value='%s'", opt, value);
239 if (args[i]->type == OPTION_TYPE_NOARG && *value)
240 return GPG_ERR_SYNTAX;
241 else if (args[i]->type == OPTION_TYPE_ARG && !*value)
242 return GPG_ERR_SYNTAX;
244 rc = args[i]->func (data, value);
246 if (rc)
247 return rc;
249 match = 1;
250 break;
254 if (!match)
255 return GPG_ERR_UNKNOWN_OPTION;
257 if (!*p)
258 break;
260 continue;
263 break;
266 *line = p;
267 return rc;
270 char *
271 bin2hex (const unsigned char *data, size_t len)
273 size_t size = len * 2 + 1;
274 char buf[size];
275 size_t n;
277 buf[0] = 0;
279 for (n = 0; n < len; n++)
281 char c[3];
283 sprintf (c, "%02X", data[n]);
284 strcat (buf, c);
287 return str_dup (buf);
290 char *
291 plus_escape (const char *fmt, ...)
293 va_list ap;
294 char *str;
296 va_start (ap, fmt);
298 if (str_vasprintf (&str, fmt, ap) > 0)
300 char *p;
302 for (p = str; *p; p++)
304 if (*p == ' ')
305 *p = '+';
308 va_end (ap);
309 return str;
312 va_end (ap);
313 return NULL;
316 static char *
317 strip_texi (const char *str)
319 const char *p;
320 char *s = str_dup (str);
321 int c = 0;
323 if (!s)
324 return NULL;
326 for (p = str; *p; p++)
328 if (*p == '@' && *(p + 1) != '@')
330 if (!strncasecmp (p + 1, "table", 5)
331 || !strncasecmp (p + 1, "end ", 4))
333 while (*p++ != '\n');
334 p--;
335 continue;
337 else if (!strncasecmp (p + 1, "example", 7)
338 || !strncasecmp (p + 1, "end ", 4))
340 while (*p++ != '\n');
341 p--;
342 continue;
344 else if (!strncasecmp (p + 1, "sp ", 3))
346 p += 3;
348 while (*p && isdigit (*p++))
349 p++;
350 continue;
352 else if (!strncasecmp (p + 1, "item", 4))
354 p += 5;
355 while (*p && *p != '\n')
356 s[c++] = *p++;
358 continue;
360 else if (!strncasecmp (p + 1, "pxref", 5))
362 p += 6;
363 strcat (s, "see ");
364 c = strlen (s);
365 goto close;
367 else if (!strncasecmp (p + 1, "xref", 4))
369 p += 5;
370 strcat (s, "See ");
371 c = strlen (s);
372 goto close;
375 while (*p && *p != '{')
377 if (*++p == '*')
379 p++;
380 goto append;
384 close:
385 if (*p)
387 p++;
388 s[c++] = '`';
389 while (*p && *p != '}')
390 s[c++] = *p++;
392 if (*p)
393 p++;
395 s[c++] = '\'';
398 else if (*p == '@' && *(p + 1) == '@')
399 p++;
401 append:
402 if (*p)
403 s[c++] = *p;
405 s[c] = 0;
408 s[c] = 0;
409 return s;
413 char *
414 strip_texi_and_wrap (const char *str)
416 char *tmp = strip_texi (str);
417 char *help = xmalloc (strlen (tmp) * 2 + 1);
418 char *p, *ph;
419 int i;
421 for (p = tmp, ph = help, i = 0; *p; p++, i++)
423 if (i == 78 || *p == '\n')
425 if (!isspace (*p))
427 char *t = ph;
428 int n = 0;
430 while (!(*--t == ' '))
431 n++;
433 *t++ = '\n';
434 i = -1;
435 p -= n;
436 while (n--)
438 *t++ = *p++;
439 i++;
442 else
444 *ph++ = '\n';
445 i = -1;
446 while (*p != '\n' && *p == ' ')
447 p++;
451 *ph++ = *p;
454 *ph = 0;
455 xfree (tmp);
456 return help;
459 void
460 free_key (void *data)
462 xfree (data);
465 gpg_error_t
466 create_thread (void *(*cb) (void *), void *data,
467 pthread_t * tid, int detached)
469 pthread_attr_t attr;
470 int n;
472 pthread_attr_init (&attr);
474 if (detached)
475 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
477 n = pthread_create (tid, &attr, cb, data);
478 pthread_attr_destroy (&attr);
479 return gpg_error_from_errno (n);
482 void
483 cleanup_mutex_cb (void *arg)
485 pthread_mutex_t *m = (pthread_mutex_t *) arg;
487 MUTEX_UNLOCK (m);
490 void
491 cleanup_fd_cb (void *arg)
493 int fd = *(int *) arg;
495 if (fd != -1)
496 close (fd);
499 void
500 cleanup_unlink_cb (void *arg)
502 char *file = arg;
504 if (file && *file)
505 unlink (file);
508 void
509 cleanup_cache_mutex (void *arg)
511 cache_unlock ();
515 valid_keygrip (const unsigned char *data, size_t len)
517 for (size_t i = 0; i < len; i++)
519 if (data[i])
520 return 1;
523 return 0;
526 gpg_error_t
527 get_checksum (const char *filename, unsigned char **r_crc, size_t * r_crclen)
529 int fd;
530 unsigned char *buf;
531 gpg_error_t rc = 0;
532 struct stat st;
534 if (stat (filename, &st) == -1)
535 return gpg_error_from_errno (errno);
537 fd = open (filename, O_RDONLY);
538 if (fd == -1)
539 return gpg_error_from_errno (errno);
541 pthread_cleanup_push (cleanup_fd_cb, &fd);
542 buf = xmalloc (st.st_size);
543 if (buf)
545 pthread_cleanup_push (xfree, buf);
547 size_t len = read (fd, buf, st.st_size);
548 if (len == st.st_size)
550 if (buf)
552 unsigned char *crc;
554 len = gcry_md_get_algo_dlen (GCRY_MD_CRC32);
555 crc = xmalloc (len);
556 if (crc)
558 pthread_cleanup_push (xfree, crc);
559 gcry_md_hash_buffer (GCRY_MD_CRC32, crc, buf, st.st_size);
560 *r_crc = crc;
561 *r_crclen = len;
562 pthread_cleanup_pop (0);
564 else
565 rc = GPG_ERR_ENOMEM;
568 else
569 rc = GPG_ERR_TOO_SHORT;
571 pthread_cleanup_pop (1);
573 else
574 rc = GPG_ERR_ENOMEM;
576 pthread_cleanup_pop (1);
577 return rc;
580 wchar_t *str_to_wchar (const char *str)
582 wchar_t *wc;
583 mbstate_t ps;
584 const char *p = str;
585 size_t len;
587 memset (&ps, 0, sizeof(mbstate_t));
588 len = mbsrtowcs (NULL, &p, 0, &ps);
589 if (len == -1)
590 return NULL;
592 wc = xcalloc (len+1, sizeof(wchar_t));
593 p = str;
594 memset (&ps, 0, sizeof(mbstate_t));
595 len = mbsrtowcs (wc, &p, len, &ps);
596 return wc;