Keep "gpg_homedir" and list file settings across SIGHUP.
[libpwmd.git] / src / util-misc.c
blob86c0d2788779de8e91bc7aabbcab025fcd0c5ba7
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of pwmd.
8 Pwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Pwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <pwd.h>
36 #include "pwmd-error.h"
37 #include <gcrypt.h>
38 #include "util-misc.h"
39 #include "util-string.h"
40 #include "mutex.h"
41 #include "cache.h"
42 #include "mem.h"
44 extern void log_write (const char *fmt, ...);
46 int
47 valid_filename (const char *filename)
49 const char *p;
51 if (!filename || !*filename)
52 return 0;
54 if (filename[0] == '-' && filename[1] == 0)
55 return 0;
57 for (p = filename; *p; p++)
59 if (*p == '/' || isspace (*p))
60 return 0;
63 return 1;
66 /* If 'user' is null then lookup entry for 'uid'. Caller must free 'buf'. */
67 struct passwd *
68 get_pwd_struct (const char *user, uid_t uid, struct passwd *pw, char **buf,
69 gpg_error_t *rc)
71 struct passwd *result;
72 #ifdef HAVE_GETPWNAM_R
73 size_t len;
74 int err = 0;
76 len = sysconf (_SC_GETPW_R_SIZE_MAX);
77 if (len == -1)
78 len = 16384;
80 *buf = xmalloc (len);
81 if (!*buf)
82 return NULL;
84 if (user)
86 err = getpwnam_r (user, pw, *buf, len, &result);
87 if (!err)
88 return result;
90 else
92 err = getpwuid_r (uid, pw, *buf, len, &result);
93 if (!err)
94 return result;
97 errno = err;
98 *rc = gpg_error_from_errno (err);
99 return NULL;
100 #else
101 if (buf)
102 *buf = NULL;
104 errno = 0;
105 if (user)
106 result = getpwnam (user);
107 else
108 result = getpwuid (uid);
110 if (!result)
111 *rc = gpg_error_from_syserror ();
113 return result;
114 #endif
117 static char *
118 get_pwd_entry(uid_t uid, int which)
120 gpg_error_t rc;
121 char *buf;
122 struct passwd pw;
123 struct passwd *result = get_pwd_struct (NULL, uid, &pw, &buf, &rc);
124 char *value = NULL;
126 if (!result)
127 return NULL;
129 if (result)
131 if (!which)
132 value = str_dup (result->pw_dir);
133 else
134 value = str_dup (result->pw_name);
137 xfree (buf);
138 return value;
141 char *
142 get_username (uid_t uid)
144 return get_pwd_entry (uid, 1);
147 char *
148 get_home_dir ()
150 if (home_directory)
151 return home_directory;
153 home_directory = get_pwd_entry (getuid(), 0);
154 return home_directory;
157 char *
158 expand_homedir (char *str)
160 char *p = str;
162 if (*p++ == '~')
164 char *dir = get_pwd_entry(getuid(), 0);
165 char *s;
167 if (!dir)
168 return NULL;
170 s = str_asprintf ("%s%s", dir, p);
171 xfree (dir);
172 return s;
175 return str_dup (str);
178 /* The 'more' parameter lets the calling command process remaining
179 * non-option arguments. */
180 gpg_error_t
181 parse_options (char **line, struct argv_s * args[], void *data, int more)
183 char *p = *line;
184 gpg_error_t rc = 0;
186 for (; p && *p; p++)
188 while (*p == ' ')
189 p++;
191 if (!*p)
192 break;
194 if (*p == '-' && *(p + 1) == '-')
196 p += 2;
197 char opt[255] = { 0 }, value[255] =
200 char *tp;
201 unsigned len;
203 if (!*p || *p == ' ')
205 if (*p)
206 p++;
208 break;
211 for (tp = opt, len = 0; *p; p++, len++)
213 if (len + 1 == 255)
214 return GPG_ERR_LINE_TOO_LONG;
216 if (*p == ' ' || *p == '=')
218 *tp = 0;
220 if (*p == '=')
222 int inquote = 0;
224 p++;
226 for (tp = value, len = 0; *p; p++, len++)
228 if (len + 1 == 255)
229 return GPG_ERR_LINE_TOO_LONG;
231 if (*p == '\"')
233 inquote = !inquote;
234 continue;
236 else if (*p == ' ' && !inquote)
237 break;
239 *tp++ = *p;
242 *tp = 0;
245 break;
248 *tp++ = *p;
251 *tp = 0;
252 int match = 0;
254 for (int i = 0; args[i]; i++)
256 if (!strcmp (args[i]->opt, opt))
258 log_write2 ("param: name='%s' value='%s'", opt, value);
259 if (args[i]->type == OPTION_TYPE_NOARG && *value)
260 return GPG_ERR_SYNTAX;
261 else if (args[i]->type == OPTION_TYPE_ARG && !*value)
262 return GPG_ERR_SYNTAX;
264 if (args[i]->func)
266 rc = args[i]->func (data, value);
267 if (rc)
268 return rc;
271 match = 1;
272 break;
276 if (!match)
277 return GPG_ERR_UNKNOWN_OPTION;
279 if (!*p)
280 break;
282 continue;
285 if (*(p+1) && !more)
286 return GPG_ERR_SYNTAX;
288 break;
291 *line = p;
292 return rc;
295 char *
296 bin2hex (const unsigned char *data, size_t len)
298 size_t size = len * 2 + 1;
299 char buf[size];
300 size_t n;
302 buf[0] = 0;
304 for (n = 0; n < len; n++)
306 char c[3];
308 sprintf (c, "%02X", data[n]);
309 strcat (buf, c);
312 return str_dup (buf);
315 static char *
316 html_escape (const char *line, size_t len, int space)
318 struct string_s *string = string_new ("");
319 size_t n;
320 char *tmp;
322 if (!string)
323 return NULL;
325 for (n = 0; n < len; n++)
327 switch (line[n])
329 case '<':
330 string = string_append (string, "&lt;");
331 break;
332 case '>':
333 string = string_append (string, "&gt;");
334 break;
335 case ' ':
336 if (space)
338 string = string_append (string, "%20");
339 break;
341 default:
342 string = string_append_printf (string, "%c", line[n]);
343 break;
347 tmp = string->str;
348 string_free (string, 0);
349 return tmp;
352 static char *
353 strip_texi_html (const char *line)
355 size_t len;
356 const char *p;
357 char *tmp;
358 struct string_s *string = string_new ("<html><body>");
360 if (!string)
361 return NULL;
363 /* The command usage text. */
364 p = strchr (line, '\n');
365 if (p)
367 len = strlen (line)-strlen(p);
368 tmp = html_escape (line, len, 0);
369 string = string_append_printf (string, "<b>%s</b><p>", tmp);
370 xfree (tmp);
371 p++;
373 else
374 p = line;
376 for (; p && *p; p++)
378 int non_anchor = 1;
379 int var = 0;
380 int code = 0;
381 int emph = 0;
382 int cite = 0;
384 if (*p == '@' && *(p + 1) != '@')
386 p++;
388 if (!strncasecmp (p, "end ", 4))
390 p += 4;
391 if (!strncasecmp (p, "table", 5))
393 string = string_append (string, "</p>");
395 else if (!strncasecmp (p, "example", 7))
397 string = string_append (string, "</code>");
400 while (*p++ != '\n');
401 p--;
402 continue;
404 else if (!strncasecmp (p, "table ", 6))
406 while (*p++ != '\n');
407 p--;
408 continue;
410 else if (!strncasecmp (p, "example", 7))
412 string = string_append (string, "<code>");
413 while (*p++ != '\n');
414 p--;
415 continue;
417 else if (!strncasecmp (p, "sp ", 3))
419 while (*p++ != '\n');
420 p--;
421 string = string_append (string, "<p>");
422 continue;
424 else if (!strncasecmp (p, "item ", 5))
426 p += 5;
427 string = string_append (string, "<p><b>");
428 tmp = strchr (p, '\n');
429 len = strlen (p) - strlen (tmp);
430 while (len--)
431 string = string_append_printf (string, "%c", *p++);
433 string = string_append (string, "</b><br/>");
434 continue;
436 else if (!strncasecmp (p, "pxref", 5)
437 || !strncasecmp (p, "npxref", 6))
439 int n = 0;
441 if (!strncasecmp (p, "npxref", 6))
442 n++;
444 p += n ? 7 : 6;
445 non_anchor = 0;
446 string = string_append_printf (string, "%s<a href=\"",
447 n ? "" : "see ");
448 goto close;
450 else if (!strncasecmp (p, "xref", 4))
452 p += 5;
453 non_anchor = 0;
454 string = string_append (string, "See <a href=\"");
455 goto close;
457 else if (!strncasecmp (p, "url", 3))
459 p += 4;
460 non_anchor = 0;
461 string = string_append (string, "<a href=\"");
462 goto close;
464 else if (!strncasecmp (p, "key", 3))
466 p += 4;
467 goto close;
469 else if (!strncasecmp (p, "file", 4))
471 p += 5;
472 var = 1;
473 string = string_append (string, "<var>");
474 goto close;
476 else if (!strncasecmp (p, "var", 3))
478 p += 4;
479 var = 1;
480 string = string_append (string, "<var>");
481 goto close;
483 else if (!strncasecmp (p, "option", 6))
485 p += 7;
486 var = 1;
487 string = string_append (string, "<var>");
488 goto close;
490 else if (!strncasecmp (p, "code", 4))
492 p += 5;
493 code = 1;
494 string = string_append (string, "<b>");
495 goto close;
497 else if (!strncasecmp (p, "emph", 4))
499 p += 5;
500 emph = 1;
501 string = string_append (string, "<em>");
502 goto close;
504 else if (!strncasecmp (p, "command", 7))
506 p += 8;
507 emph = 1;
508 string = string_append (string, "<em>");
509 goto close;
511 else if (!strncasecmp (p, "cite", 4))
513 p += 5;
514 cite = 1;
515 string = string_append (string, "<cite>");
516 goto close;
518 else if (!strncasecmp (p, "abbr", 4))
520 p += 5;
521 emph = 1;
522 string = string_append (string, "<em>");
523 goto close;
525 else if (!strncasecmp (p, "*", 1))
527 string = string_append (string, "<br/>");
528 continue;
531 while (*p && *p != '{')
533 if (*++p == '*')
535 p++;
536 goto append;
540 close:
541 if (*p)
543 char buf [255];
545 tmp = strchr (p, '}');
546 len = strlen (p) - strlen (tmp);
547 tmp = buf;
548 while (len--)
549 *tmp++ = *p++;
551 *tmp = 0;
553 if (*p)
554 p++;
556 if (!non_anchor)
558 tmp = html_escape (buf, strlen (buf), 1);
559 string = string_append_printf (string, "%s\">%s</a>", tmp, buf);
560 xfree (tmp);
562 else
563 string = string_append (string, buf);
565 if (var)
566 string = string_append (string, "</var>");
567 else if (code)
568 string = string_append (string, "</b>");
569 else if (emph)
570 string = string_append (string, "</em>");
571 else if (cite)
572 string = string_append (string, "</cite>");
575 else if (*p == '@' && *(p + 1) == '@')
576 p++;
578 append:
579 string = string_append_printf (string, "%c", *p);
581 if (!*p)
582 break;
585 string = string_append (string, "</body></html>");
586 tmp = string->str;
587 string_free (string, 0);
588 return tmp;
591 static char *
592 strip_texi (const char *str, int html)
594 const char *p;
595 char *s;
596 int c = 0;
598 if (html)
599 return strip_texi_html (str);
601 s = str_dup (str);
602 if (!s)
603 return NULL;
605 for (p = str; *p; p++)
607 if (*p == '@' && *(p + 1) != '@')
609 p++;
611 if (!strncasecmp (p, "table", 5)
612 || !strncasecmp (p, "end ", 4))
614 while (*p++ != '\n');
615 p--;
616 continue;
618 else if (!strncasecmp (p, "example", 7)
619 || !strncasecmp (p, "end ", 4))
621 while (*p++ != '\n');
622 p--;
623 continue;
625 else if (!strncasecmp (p, "sp ", 3))
627 while (*p++ != '\n');
628 p--;
629 continue;
631 else if (!strncasecmp (p, "item", 4))
633 p += 5;
634 while (*p && *p != '\n')
635 s[c++] = *p++;
637 s[c++] = '\n';
638 continue;
640 else if (!strncasecmp (p, "pxref", 5))
642 p += 5;
643 strcat (s, "see ");
644 c = strlen (s);
645 goto close;
647 else if (!strncasecmp (p, "xref", 4))
649 p += 4;
650 strcat (s, "See ");
651 c = strlen (s);
652 goto close;
654 else if (!strncasecmp (p, "*", 1))
656 s[c++] = '\n';
657 s[c] = 0;
658 continue;
661 while (*p && *p != '{')
663 if (*++p == '*')
665 p++;
666 goto append;
670 close:
671 if (*p)
673 p++;
674 s[c++] = '`';
675 while (*p && *p != '}')
676 s[c++] = *p++;
678 if (*p)
679 p++;
681 s[c++] = '\'';
682 s[c] = 0;
685 else if (*p == '@' && *(p + 1) == '@')
686 p++;
688 append:
689 if (*p)
690 s[c++] = *p;
692 s[c] = 0;
695 s[c] = 0;
696 return s;
700 char *
701 strip_texi_and_wrap (const char *str, int html)
703 char *tmp = strip_texi (str, html);
704 char *help = xmalloc (strlen (tmp) * 2 + 1);
705 char *p, *ph;
706 int i;
708 for (p = tmp, ph = help, i = 0; *p; p++, i++)
710 if (i == 78 || *p == '\n')
712 if (!isspace (*p))
714 char *t = ph;
715 int n = 0;
717 while (!(*--t == ' '))
718 n++;
720 *t++ = '\n';
721 i = -1;
722 p -= n;
723 while (n--)
725 *t++ = *p++;
726 i++;
729 else
731 *ph++ = '\n';
732 i = -1;
733 while (*p != '\n' && *p == ' ')
734 p++;
738 if (*p == '\n')
739 continue;
740 *ph++ = *p;
743 *ph = 0;
744 xfree (tmp);
745 return help;
748 void
749 free_key (void *data)
751 xfree (data);
754 gpg_error_t
755 create_thread (void *(*cb) (void *), void *data,
756 pthread_t * tid, int detached)
758 pthread_attr_t attr;
759 int n;
761 pthread_attr_init (&attr);
763 if (detached)
764 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
766 n = pthread_create (tid, &attr, cb, data);
767 pthread_attr_destroy (&attr);
768 return gpg_error_from_errno (n);
771 void
772 release_mutex_cb (void *arg)
774 pthread_mutex_t *m = (pthread_mutex_t *) arg;
776 MUTEX_UNLOCK (m);
779 void
780 close_fd_cb (void *arg)
782 int fd = *(int *) arg;
784 if (fd != -1)
785 close (fd);
788 /* The advisory lock should be obtained before calling this function. */
789 gpg_error_t
790 get_checksum (const char *filename, unsigned char **r_crc, size_t * r_crclen)
792 int fd;
793 unsigned char *buf;
794 gpg_error_t rc;
795 struct stat st;
797 rc = open_check_file (filename, &fd, &st, 1);
798 if (rc)
799 return rc;
801 pthread_cleanup_push (close_fd_cb, &fd);
802 buf = xmalloc (st.st_size);
803 if (buf)
805 pthread_cleanup_push (xfree, buf);
807 size_t len = read (fd, buf, st.st_size);
808 if (len == st.st_size)
810 if (buf)
812 unsigned char *crc;
814 len = gcry_md_get_algo_dlen (GCRY_MD_CRC32);
815 crc = xmalloc (len);
816 if (crc)
818 pthread_cleanup_push (xfree, crc);
819 gcry_md_hash_buffer (GCRY_MD_CRC32, crc, buf, st.st_size);
820 *r_crc = crc;
821 *r_crclen = len;
822 pthread_cleanup_pop (0);
824 else
825 rc = GPG_ERR_ENOMEM;
828 else
829 rc = GPG_ERR_TOO_SHORT;
831 pthread_cleanup_pop (1);
833 else
834 rc = GPG_ERR_ENOMEM;
836 pthread_cleanup_pop (1);
837 return rc;
840 wchar_t *str_to_wchar (const char *str)
842 wchar_t *wc;
843 mbstate_t ps;
844 const char *p = str;
845 size_t len;
847 memset (&ps, 0, sizeof(mbstate_t));
848 len = mbsrtowcs (NULL, &p, 0, &ps);
849 if (len == -1)
850 return NULL;
852 wc = xcalloc (len+1, sizeof(wchar_t));
853 if (!wc)
854 return NULL;
856 p = str;
857 memset (&ps, 0, sizeof(mbstate_t));
858 len = mbsrtowcs (wc, &p, len, &ps);
859 if (len == -1)
861 xfree (wc);
862 return NULL;
865 return wc;
868 char *
869 gnupg_escape (const char *str)
871 if (!str || !*str)
872 return NULL;
874 char *buf = xmalloc (strlen(str)*4+1), *b = buf;
875 const char *p;
877 if (!buf)
878 return NULL;
880 for (p = str; p && *p; p++)
882 if (*p == ':')
884 *b++ = '\\';
885 *b++ = 'x';
886 *b++ = '3';
887 *b++ = 'a';
888 continue;
890 else if (*p == '\\')
892 *b++ = '\\';
893 *b++ = 'x';
894 *b++ = '5';
895 *b++ = 'c';
896 continue;
899 *b++ = *p;
902 *b = 0;
903 return buf;
906 /* From Beej's Guide to Network Programming. It's a good tutorial. */
907 void *
908 get_in_addr (struct sockaddr *sa)
910 if (sa->sa_family == AF_INET)
911 return &(((struct sockaddr_in *) sa)->sin_addr);
913 return &(((struct sockaddr_in6 *) sa)->sin6_addr);
916 gpg_error_t
917 open_check_file (const char *filename, int *r_fd, struct stat *r_st, int reg)
919 int fd;
920 gpg_error_t rc = 0;
922 if (reg)
924 struct stat st;
926 if (lstat (filename, &st) == -1)
927 return gpg_error_from_syserror ();
929 if (!S_ISREG (st.st_mode))
930 return gpg_error_from_errno (ENODEV);
933 if (r_fd)
935 fd = open (filename, O_RDONLY);
936 if (fd == -1)
937 return gpg_error_from_syserror ();
939 if (r_st && fstat (fd, r_st) == -1)
941 rc = gpg_error_from_syserror ();
942 close (fd);
943 return rc;
946 *r_fd = fd;
949 return rc;