build: Update configure.ac to use recent macros.
[pwmd.git] / src / util-misc.c
blob64cf591cd3006fed0649fdb084a3f90671c24844
1 /*
2 Copyright (C) 2006-2021 Ben Kibbey <bjk@luxsci.net>
4 This file is part of pwmd.
6 Pwmd is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
11 Pwmd is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <pwd.h>
34 #include "pwmd-error.h"
35 #include <gcrypt.h>
36 #include "util-misc.h"
37 #include "util-string.h"
38 #include "mutex.h"
39 #include "cache.h"
40 #include "mem.h"
42 char *home_directory;
43 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,
68 gpg_error_t *rc)
70 struct passwd *result = NULL;
71 #ifdef HAVE_GETPWNAM_R
72 size_t len;
73 int err = 0;
75 len = sysconf (_SC_GETPW_R_SIZE_MAX);
76 if (len == -1)
77 len = 16384;
79 *buf = xmalloc (len);
80 if (!*buf)
81 return NULL;
83 if (user)
84 err = getpwnam_r (user, pw, *buf, len, &result);
85 else
86 err = getpwuid_r (uid, pw, *buf, len, &result);
88 if (!err && result)
89 return result;
91 xfree (*buf);
92 *buf = NULL;
93 errno = err;
94 *rc = gpg_error_from_errno (err);
95 return NULL;
96 #else
97 if (buf)
98 *buf = NULL;
100 errno = 0;
101 if (user)
102 result = getpwnam (user);
103 else
104 result = getpwuid (uid);
106 if (!result)
107 *rc = gpg_error_from_syserror ();
109 return result;
110 #endif
113 static char *
114 get_pwd_entry(uid_t uid, int which)
116 gpg_error_t rc;
117 char *buf;
118 struct passwd pw;
119 struct passwd *result = get_pwd_struct (NULL, uid, &pw, &buf, &rc);
120 char *value = NULL;
122 if (!result)
123 return NULL;
125 if (result)
127 if (!which)
128 value = str_dup (result->pw_dir);
129 else
130 value = str_dup (result->pw_name);
133 xfree (buf);
134 return value;
137 char *
138 get_username (uid_t uid)
140 return get_pwd_entry (uid, 1);
143 char *
144 get_home_dir ()
146 if (home_directory)
147 return home_directory;
149 home_directory = get_pwd_entry (getuid(), 0);
150 return home_directory;
153 char *
154 expand_homedir (char *str)
156 char *p = str;
158 if (*p++ == '~')
160 char *dir = get_pwd_entry(getuid(), 0);
161 char *s;
163 if (!dir)
164 return NULL;
166 s = str_asprintf ("%s%s", dir, p);
167 xfree (dir);
168 return s;
171 return str_dup (str);
174 /* The 'more' parameter lets the calling command process remaining
175 * non-option arguments. */
176 gpg_error_t
177 parse_options (char **line, struct argv_s * args[], void *data, int more)
179 char *p = *line;
180 gpg_error_t rc = 0;
182 for (; p && *p; p++)
184 while (*p == ' ')
185 p++;
187 if (!*p)
188 break;
190 if (*p == '-' && *(p + 1) == '-')
192 p += 2;
193 char opt[255] = { 0 }, value[255] =
196 char *tp;
197 unsigned len;
199 if (!*p || *p == ' ')
201 if (*p)
202 p++;
204 break;
207 for (tp = opt, len = 0; *p; p++, len++)
209 if (len + 1 == 255)
210 return GPG_ERR_LINE_TOO_LONG;
212 if (*p == ' ' || *p == '=')
214 *tp = 0;
216 if (*p == '=')
218 int inquote = 0;
220 p++;
222 for (tp = value, len = 0; *p; p++, len++)
224 if (len + 1 == 255)
225 return GPG_ERR_LINE_TOO_LONG;
227 if (*p == '\"')
229 inquote = !inquote;
230 continue;
232 else if (*p == ' ' && !inquote)
233 break;
235 *tp++ = *p;
238 *tp = 0;
241 break;
244 *tp++ = *p;
247 *tp = 0;
248 int match = 0;
250 for (int i = 0; args[i]; i++)
252 if (!strcmp (args[i]->opt, opt))
254 log_write2 ("param: name='%s' value='%s'", opt, value);
255 if (args[i]->type == OPTION_TYPE_NOARG && *value)
256 return GPG_ERR_SYNTAX;
257 else if (args[i]->type == OPTION_TYPE_ARG && !*value)
258 return GPG_ERR_SYNTAX;
260 if (args[i]->func)
262 rc = args[i]->func (data, value);
263 if (rc)
264 return rc;
267 match = 1;
268 break;
272 if (!match)
273 return GPG_ERR_UNKNOWN_OPTION;
275 if (!*p)
276 break;
278 continue;
281 if (*(p+1) && !more)
282 return GPG_ERR_SYNTAX;
284 break;
287 *line = p;
288 return rc;
291 char *
292 bin2hex (const unsigned char *data, size_t len)
294 size_t size = len * 2 + 1;
295 char buf[size];
296 size_t n;
298 buf[0] = 0;
300 for (n = 0; n < len; n++)
302 char c[3];
304 sprintf (c, "%02X", data[n]);
305 strcat (buf, c);
308 return str_dup (buf);
311 static char *
312 html_escape (const char *line, size_t len, int space)
314 struct string_s *string = string_new ("");
315 size_t n;
316 char *tmp;
318 if (!string)
319 return NULL;
321 for (n = 0; n < len; n++)
323 switch (line[n])
325 case '<':
326 string = string_append (string, "&lt;");
327 break;
328 case '>':
329 string = string_append (string, "&gt;");
330 break;
331 case ' ':
332 if (space)
334 string = string_append (string, "%20");
335 break;
337 default:
338 string = string_append_printf (string, "%c", line[n]);
339 break;
343 tmp = string->str;
344 string_free (string, 0);
345 return tmp;
348 static char *
349 strip_texi_html (const char *line)
351 size_t len;
352 const char *p;
353 char *tmp;
354 struct string_s *string = string_new ("<html><body>");
356 if (!string)
357 return NULL;
359 /* The command usage text. */
360 p = strchr (line, '\n');
361 if (p)
363 len = strlen (line)-strlen(p);
364 tmp = html_escape (line, len, 0);
365 string = string_append_printf (string, "<b>%s</b><p>", tmp);
366 xfree (tmp);
367 p++;
369 else
370 p = line;
372 for (; p && *p; p++)
374 int non_anchor = 1;
375 int var = 0;
376 int code = 0;
377 int emph = 0;
378 int cite = 0;
380 if (*p == '@' && *(p + 1) != '@')
382 p++;
384 if (!strncasecmp (p, "end ", 4))
386 p += 4;
387 if (!strncasecmp (p, "table", 5))
389 string = string_append (string, "</p>");
391 else if (!strncasecmp (p, "example", 7))
393 string = string_append (string, "</code>");
396 while (*p++ != '\n');
397 p--;
398 continue;
400 else if (!strncasecmp (p, "table ", 6))
402 while (*p++ != '\n');
403 p--;
404 continue;
406 else if (!strncasecmp (p, "example", 7))
408 string = string_append (string, "<code>");
409 while (*p++ != '\n');
410 p--;
411 continue;
413 else if (!strncasecmp (p, "sp ", 3))
415 while (*p++ != '\n');
416 p--;
417 string = string_append (string, "<p>");
418 continue;
420 else if (!strncasecmp (p, "item ", 5))
422 p += 5;
423 string = string_append (string, "<p><b>");
424 tmp = strchr (p, '\n');
425 len = strlen (p) - strlen (tmp);
426 while (len--)
428 if (*p == '<')
430 string = string_append (string, "&lt;");
431 p++;
433 else if (*p == '>')
435 string = string_append (string, "&gt;");
436 p++;
438 else
439 string = string_append_printf (string, "%c", *p++);
442 string = string_append (string, "</b><br/>");
443 continue;
445 else if (!strncasecmp (p, "pxref", 5)
446 || !strncasecmp (p, "npxref", 6))
448 int n = 0;
450 if (!strncasecmp (p, "npxref", 6))
451 n++;
453 p += n ? 7 : 6;
454 non_anchor = 0;
455 string = string_append_printf (string, "%s<a href=\"",
456 n ? "" : "see ");
457 goto close;
459 else if (!strncasecmp (p, "xref", 4))
461 p += 5;
462 non_anchor = 0;
463 string = string_append (string, "See <a href=\"");
464 goto close;
466 else if (!strncasecmp (p, "url", 3))
468 p += 4;
469 non_anchor = 0;
470 string = string_append (string, "<a href=\"");
471 goto close;
473 else if (!strncasecmp (p, "key", 3))
475 p += 4;
476 goto close;
478 else if (!strncasecmp (p, "file", 4))
480 p += 5;
481 var = 1;
482 string = string_append (string, "<var>");
483 goto close;
485 else if (!strncasecmp (p, "var", 3))
487 p += 4;
488 var = 1;
489 string = string_append (string, "<var>");
490 goto close;
492 else if (!strncasecmp (p, "option", 6))
494 p += 7;
495 var = 1;
496 string = string_append (string, "<var>");
497 goto close;
499 else if (!strncasecmp (p, "code", 4))
501 p += 5;
502 code = 1;
503 string = string_append (string, "<b>");
504 goto close;
506 else if (!strncasecmp (p, "emph", 4))
508 p += 5;
509 emph = 1;
510 string = string_append (string, "<em>");
511 goto close;
513 else if (!strncasecmp (p, "command", 7))
515 p += 8;
516 emph = 1;
517 string = string_append (string, "<em>");
518 goto close;
520 else if (!strncasecmp (p, "cite", 4))
522 p += 5;
523 cite = 1;
524 string = string_append (string, "<cite>");
525 goto close;
527 else if (!strncasecmp (p, "abbr", 4))
529 p += 5;
530 emph = 1;
531 string = string_append (string, "<em>");
532 goto close;
534 else if (!strncasecmp (p, "*", 1))
536 string = string_append (string, "<br/>");
537 continue;
540 while (*p && *p != '{')
542 if (*++p == '*')
544 p++;
545 goto append;
549 close:
550 if (*p)
552 char buf [255];
554 tmp = strchr (p, '}');
555 len = strlen (p) - strlen (tmp);
556 tmp = buf;
557 while (len--)
558 *tmp++ = *p++;
560 *tmp = 0;
562 if (*p)
563 p++;
565 if (!non_anchor)
567 tmp = html_escape (buf, strlen (buf), 1);
568 string = string_append_printf (string, "%s\">%s</a>", tmp, buf);
569 xfree (tmp);
571 else
572 string = string_append (string, buf);
574 if (var)
575 string = string_append (string, "</var>");
576 else if (code)
577 string = string_append (string, "</b>");
578 else if (emph)
579 string = string_append (string, "</em>");
580 else if (cite)
581 string = string_append (string, "</cite>");
584 else if (*p == '@' && *(p + 1) == '@')
585 p++;
587 append:
588 string = string_append_printf (string, "%c", *p);
590 if (!*p)
591 break;
594 string = string_append (string, "</body></html>");
595 tmp = string->str;
596 string_free (string, 0);
597 return tmp;
600 static char *
601 strip_texi (const char *str, int html)
603 const char *p;
604 char *s;
605 int c = 0;
607 if (html)
608 return strip_texi_html (str);
610 s = str_dup (str);
611 if (!s)
612 return NULL;
614 for (p = str; *p; p++)
616 if (*p == '@' && *(p + 1) != '@')
618 p++;
620 if (!strncasecmp (p, "table", 5)
621 || !strncasecmp (p, "end ", 4))
623 while (*p++ != '\n');
624 p--;
625 continue;
627 else if (!strncasecmp (p, "example", 7)
628 || !strncasecmp (p, "end ", 4))
630 while (*p++ != '\n');
631 p--;
632 continue;
634 else if (!strncasecmp (p, "sp ", 3))
636 while (*p++ != '\n');
637 p--;
638 continue;
640 else if (!strncasecmp (p, "item", 4))
642 p += 5;
643 while (*p && *p != '\n')
644 s[c++] = *p++;
646 s[c++] = '\n';
647 continue;
649 else if (!strncasecmp (p, "pxref", 5))
651 p += 5;
652 strcat (s, "see ");
653 c = strlen (s);
654 goto close;
656 else if (!strncasecmp (p, "xref", 4))
658 p += 4;
659 strcat (s, "See ");
660 c = strlen (s);
661 goto close;
663 else if (!strncasecmp (p, "*", 1))
665 s[c++] = '\n';
666 s[c] = 0;
667 continue;
670 while (*p && *p != '{')
672 if (*++p == '*')
674 p++;
675 goto append;
679 close:
680 if (*p)
682 p++;
683 s[c++] = '`';
684 while (*p && *p != '}')
685 s[c++] = *p++;
687 if (*p)
688 p++;
690 s[c++] = '\'';
691 s[c] = 0;
694 else if (*p == '@' && *(p + 1) == '@')
695 p++;
697 append:
698 if (*p)
699 s[c++] = *p;
701 s[c] = 0;
704 s[c] = 0;
705 return s;
709 char *
710 strip_texi_and_wrap (const char *str, int html)
712 char *tmp = strip_texi (str, html);
713 char *help = xcalloc (1, strlen (tmp) * 2 + 1);
714 char *p, *ph;
715 int i;
717 for (p = tmp, ph = help, i = 0; *p; p++, i++)
719 if (i == 78 || *p == '\n')
721 if (!isspace (*p))
723 char *t = ph;
724 int n = 0;
726 while (*(--t) != ' ')
727 n++;
729 *t++ = '\n';
730 i = -1;
731 p -= n;
732 while (n--)
734 *t++ = *p++;
735 i++;
738 else
740 *ph++ = '\n';
741 i = -1;
742 while (*p != '\n' && *p == ' ')
743 p++;
747 if (*p == '\n')
748 continue;
749 *ph++ = *p;
752 *ph = 0;
753 xfree (tmp);
754 return help;
757 void
758 free_key (void *data)
760 xfree (data);
763 gpg_error_t
764 create_thread (void *(*cb) (void *), void *data,
765 pthread_t * tid, int detached)
767 pthread_attr_t attr;
768 int n;
770 pthread_attr_init (&attr);
772 if (detached)
773 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
775 n = pthread_create (tid, &attr, cb, data);
776 pthread_attr_destroy (&attr);
777 return gpg_error_from_errno (n);
780 void
781 release_mutex_cb (void *arg)
783 pthread_mutex_t *m = (pthread_mutex_t *) arg;
785 MUTEX_UNLOCK (m);
788 void
789 close_fd_cb (void *arg)
791 int fd = *(int *)arg;
793 if (fd != -1)
794 close (fd);
797 gpg_error_t
798 get_checksum_memory (void *data, size_t size, unsigned char **r_crc,
799 size_t *r_crclen)
801 size_t len = gcry_md_get_algo_dlen (GCRY_MD_CRC32);
802 unsigned char *crc = xmalloc (len);
804 *r_crc = NULL;
805 *r_crclen = 0;
807 if (!crc)
808 return GPG_ERR_ENOMEM;
810 gcry_md_hash_buffer (GCRY_MD_CRC32, crc, data, size);
811 *r_crc = crc;
812 *r_crclen = len;
813 return 0;
816 /* The advisory lock should be obtained before calling this function. */
817 gpg_error_t
818 get_checksum (const char *filename, unsigned char **r_crc, size_t * r_crclen)
820 int fd = -1;
821 unsigned char *buf;
822 gpg_error_t rc;
823 struct stat st;
825 rc = open_check_file (filename, &fd, &st, 1);
826 if (rc)
827 return rc;
829 pthread_cleanup_push (close_fd_cb, &fd);
830 buf = xmalloc (st.st_size);
831 if (buf)
833 pthread_cleanup_push (xfree, buf);
835 size_t len = read (fd, buf, st.st_size);
836 if (len == st.st_size)
838 if (buf)
839 rc = get_checksum_memory (buf, st.st_size, r_crc, r_crclen);
840 else
841 rc = GPG_ERR_ENOMEM;
843 else
844 rc = GPG_ERR_TOO_SHORT;
846 pthread_cleanup_pop (1);
848 else
849 rc = GPG_ERR_ENOMEM;
851 pthread_cleanup_pop (1);
852 return rc;
855 wchar_t *str_to_wchar (const char *str)
857 wchar_t *wc;
858 mbstate_t ps;
859 const char *p = str;
860 size_t len;
862 memset (&ps, 0, sizeof(mbstate_t));
863 len = mbsrtowcs (NULL, &p, 0, &ps);
864 if (len == -1)
865 return NULL;
867 wc = xcalloc (len+1, sizeof(wchar_t));
868 if (!wc)
869 return NULL;
871 p = str;
872 memset (&ps, 0, sizeof(mbstate_t));
873 len = mbsrtowcs (wc, &p, len, &ps);
874 if (len == -1)
876 xfree (wc);
877 return NULL;
880 return wc;
883 char *
884 gnupg_escape (const char *str)
886 if (!str || !*str)
887 return NULL;
889 char *buf = xmalloc (strlen(str)*4+1), *b = buf;
890 const char *p;
892 if (!buf)
893 return NULL;
895 for (p = str; p && *p; p++)
897 if (*p == ':')
899 *b++ = '\\';
900 *b++ = 'x';
901 *b++ = '3';
902 *b++ = 'a';
903 continue;
905 else if (*p == '\\')
907 *b++ = '\\';
908 *b++ = 'x';
909 *b++ = '5';
910 *b++ = 'c';
911 continue;
914 *b++ = *p;
917 *b = 0;
918 return buf;
921 /* From Beej's Guide to Network Programming. It's a good tutorial. */
922 void *
923 get_in_addr (struct sockaddr *sa)
925 if (sa->sa_family == AF_INET)
926 return &(((struct sockaddr_in *) sa)->sin_addr);
928 return &(((struct sockaddr_in6 *) sa)->sin6_addr);
931 gpg_error_t
932 open_check_file (const char *filename, int *r_fd, struct stat *r_st, int reg)
934 int fd;
935 gpg_error_t rc = 0;
937 if (r_st)
938 memset (r_st, 9, sizeof (struct stat));
940 if (reg)
942 struct stat st;
944 if (lstat (filename, &st) == -1)
945 return gpg_err_code (gpg_error_from_syserror ());
947 if (!S_ISREG (st.st_mode))
948 return GPG_ERR_ENODEV;
950 if (r_st)
951 memcpy (r_st, &st, sizeof (struct stat));
954 if (r_fd)
956 fd = open (filename, O_RDONLY);
957 if (fd == -1)
958 return gpg_err_code (gpg_error_from_syserror ());
960 if (r_st && fstat (fd, r_st) == -1)
962 rc = gpg_err_code (gpg_error_from_syserror ());
963 close (fd);
964 return rc;
967 *r_fd = fd;
970 return 0;