Update copyright year.
[pwmd.git] / src / util-misc.c
blob09f9b90da782582c00d3e6e38764462a429d8b75
1 /*
2 Copyright (C) 2006-2019 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 void log_write (const char *fmt, ...);
44 int
45 valid_filename (const char *filename)
47 const char *p;
49 if (!filename || !*filename)
50 return 0;
52 if (filename[0] == '-' && filename[1] == 0)
53 return 0;
55 for (p = filename; *p; p++)
57 if (*p == '/' || isspace (*p))
58 return 0;
61 return 1;
64 /* If 'user' is null then lookup entry for 'uid'. Caller must free 'buf'. */
65 struct passwd *
66 get_pwd_struct (const char *user, uid_t uid, struct passwd *pw, char **buf,
67 gpg_error_t *rc)
69 struct passwd *result = NULL;
70 #ifdef HAVE_GETPWNAM_R
71 size_t len;
72 int err = 0;
74 len = sysconf (_SC_GETPW_R_SIZE_MAX);
75 if (len == -1)
76 len = 16384;
78 *buf = xmalloc (len);
79 if (!*buf)
80 return NULL;
82 if (user)
83 err = getpwnam_r (user, pw, *buf, len, &result);
84 else
85 err = getpwuid_r (uid, pw, *buf, len, &result);
87 if (!err && result)
88 return result;
90 xfree (*buf);
91 *buf = NULL;
92 errno = err;
93 *rc = gpg_error_from_errno (err);
94 return NULL;
95 #else
96 if (buf)
97 *buf = NULL;
99 errno = 0;
100 if (user)
101 result = getpwnam (user);
102 else
103 result = getpwuid (uid);
105 if (!result)
106 *rc = gpg_error_from_syserror ();
108 return result;
109 #endif
112 static char *
113 get_pwd_entry(uid_t uid, int which)
115 gpg_error_t rc;
116 char *buf;
117 struct passwd pw;
118 struct passwd *result = get_pwd_struct (NULL, uid, &pw, &buf, &rc);
119 char *value = NULL;
121 if (!result)
122 return NULL;
124 if (result)
126 if (!which)
127 value = str_dup (result->pw_dir);
128 else
129 value = str_dup (result->pw_name);
132 xfree (buf);
133 return value;
136 char *
137 get_username (uid_t uid)
139 return get_pwd_entry (uid, 1);
142 char *
143 get_home_dir ()
145 if (home_directory)
146 return home_directory;
148 home_directory = get_pwd_entry (getuid(), 0);
149 return home_directory;
152 char *
153 expand_homedir (char *str)
155 char *p = str;
157 if (*p++ == '~')
159 char *dir = get_pwd_entry(getuid(), 0);
160 char *s;
162 if (!dir)
163 return NULL;
165 s = str_asprintf ("%s%s", dir, p);
166 xfree (dir);
167 return s;
170 return str_dup (str);
173 /* The 'more' parameter lets the calling command process remaining
174 * non-option arguments. */
175 gpg_error_t
176 parse_options (char **line, struct argv_s * args[], void *data, int more)
178 char *p = *line;
179 gpg_error_t rc = 0;
181 for (; p && *p; p++)
183 while (*p == ' ')
184 p++;
186 if (!*p)
187 break;
189 if (*p == '-' && *(p + 1) == '-')
191 p += 2;
192 char opt[255] = { 0 }, value[255] =
195 char *tp;
196 unsigned len;
198 if (!*p || *p == ' ')
200 if (*p)
201 p++;
203 break;
206 for (tp = opt, len = 0; *p; p++, len++)
208 if (len + 1 == 255)
209 return GPG_ERR_LINE_TOO_LONG;
211 if (*p == ' ' || *p == '=')
213 *tp = 0;
215 if (*p == '=')
217 int inquote = 0;
219 p++;
221 for (tp = value, len = 0; *p; p++, len++)
223 if (len + 1 == 255)
224 return GPG_ERR_LINE_TOO_LONG;
226 if (*p == '\"')
228 inquote = !inquote;
229 continue;
231 else if (*p == ' ' && !inquote)
232 break;
234 *tp++ = *p;
237 *tp = 0;
240 break;
243 *tp++ = *p;
246 *tp = 0;
247 int match = 0;
249 for (int i = 0; args[i]; i++)
251 if (!strcmp (args[i]->opt, opt))
253 log_write2 ("param: name='%s' value='%s'", opt, value);
254 if (args[i]->type == OPTION_TYPE_NOARG && *value)
255 return GPG_ERR_SYNTAX;
256 else if (args[i]->type == OPTION_TYPE_ARG && !*value)
257 return GPG_ERR_SYNTAX;
259 if (args[i]->func)
261 rc = args[i]->func (data, value);
262 if (rc)
263 return rc;
266 match = 1;
267 break;
271 if (!match)
272 return GPG_ERR_UNKNOWN_OPTION;
274 if (!*p)
275 break;
277 continue;
280 if (*(p+1) && !more)
281 return GPG_ERR_SYNTAX;
283 break;
286 *line = p;
287 return rc;
290 char *
291 bin2hex (const unsigned char *data, size_t len)
293 size_t size = len * 2 + 1;
294 char buf[size];
295 size_t n;
297 buf[0] = 0;
299 for (n = 0; n < len; n++)
301 char c[3];
303 sprintf (c, "%02X", data[n]);
304 strcat (buf, c);
307 return str_dup (buf);
310 static char *
311 html_escape (const char *line, size_t len, int space)
313 struct string_s *string = string_new ("");
314 size_t n;
315 char *tmp;
317 if (!string)
318 return NULL;
320 for (n = 0; n < len; n++)
322 switch (line[n])
324 case '<':
325 string = string_append (string, "&lt;");
326 break;
327 case '>':
328 string = string_append (string, "&gt;");
329 break;
330 case ' ':
331 if (space)
333 string = string_append (string, "%20");
334 break;
336 default:
337 string = string_append_printf (string, "%c", line[n]);
338 break;
342 tmp = string->str;
343 string_free (string, 0);
344 return tmp;
347 static char *
348 strip_texi_html (const char *line)
350 size_t len;
351 const char *p;
352 char *tmp;
353 struct string_s *string = string_new ("<html><body>");
355 if (!string)
356 return NULL;
358 /* The command usage text. */
359 p = strchr (line, '\n');
360 if (p)
362 len = strlen (line)-strlen(p);
363 tmp = html_escape (line, len, 0);
364 string = string_append_printf (string, "<b>%s</b><p>", tmp);
365 xfree (tmp);
366 p++;
368 else
369 p = line;
371 for (; p && *p; p++)
373 int non_anchor = 1;
374 int var = 0;
375 int code = 0;
376 int emph = 0;
377 int cite = 0;
379 if (*p == '@' && *(p + 1) != '@')
381 p++;
383 if (!strncasecmp (p, "end ", 4))
385 p += 4;
386 if (!strncasecmp (p, "table", 5))
388 string = string_append (string, "</p>");
390 else if (!strncasecmp (p, "example", 7))
392 string = string_append (string, "</code>");
395 while (*p++ != '\n');
396 p--;
397 continue;
399 else if (!strncasecmp (p, "table ", 6))
401 while (*p++ != '\n');
402 p--;
403 continue;
405 else if (!strncasecmp (p, "example", 7))
407 string = string_append (string, "<code>");
408 while (*p++ != '\n');
409 p--;
410 continue;
412 else if (!strncasecmp (p, "sp ", 3))
414 while (*p++ != '\n');
415 p--;
416 string = string_append (string, "<p>");
417 continue;
419 else if (!strncasecmp (p, "item ", 5))
421 p += 5;
422 string = string_append (string, "<p><b>");
423 tmp = strchr (p, '\n');
424 len = strlen (p) - strlen (tmp);
425 while (len--)
427 if (*p == '<')
429 string = string_append (string, "&lt;");
430 p++;
432 else if (*p == '>')
434 string = string_append (string, "&gt;");
435 p++;
437 else
438 string = string_append_printf (string, "%c", *p++);
441 string = string_append (string, "</b><br/>");
442 continue;
444 else if (!strncasecmp (p, "pxref", 5)
445 || !strncasecmp (p, "npxref", 6))
447 int n = 0;
449 if (!strncasecmp (p, "npxref", 6))
450 n++;
452 p += n ? 7 : 6;
453 non_anchor = 0;
454 string = string_append_printf (string, "%s<a href=\"",
455 n ? "" : "see ");
456 goto close;
458 else if (!strncasecmp (p, "xref", 4))
460 p += 5;
461 non_anchor = 0;
462 string = string_append (string, "See <a href=\"");
463 goto close;
465 else if (!strncasecmp (p, "url", 3))
467 p += 4;
468 non_anchor = 0;
469 string = string_append (string, "<a href=\"");
470 goto close;
472 else if (!strncasecmp (p, "key", 3))
474 p += 4;
475 goto close;
477 else if (!strncasecmp (p, "file", 4))
479 p += 5;
480 var = 1;
481 string = string_append (string, "<var>");
482 goto close;
484 else if (!strncasecmp (p, "var", 3))
486 p += 4;
487 var = 1;
488 string = string_append (string, "<var>");
489 goto close;
491 else if (!strncasecmp (p, "option", 6))
493 p += 7;
494 var = 1;
495 string = string_append (string, "<var>");
496 goto close;
498 else if (!strncasecmp (p, "code", 4))
500 p += 5;
501 code = 1;
502 string = string_append (string, "<b>");
503 goto close;
505 else if (!strncasecmp (p, "emph", 4))
507 p += 5;
508 emph = 1;
509 string = string_append (string, "<em>");
510 goto close;
512 else if (!strncasecmp (p, "command", 7))
514 p += 8;
515 emph = 1;
516 string = string_append (string, "<em>");
517 goto close;
519 else if (!strncasecmp (p, "cite", 4))
521 p += 5;
522 cite = 1;
523 string = string_append (string, "<cite>");
524 goto close;
526 else if (!strncasecmp (p, "abbr", 4))
528 p += 5;
529 emph = 1;
530 string = string_append (string, "<em>");
531 goto close;
533 else if (!strncasecmp (p, "*", 1))
535 string = string_append (string, "<br/>");
536 continue;
539 while (*p && *p != '{')
541 if (*++p == '*')
543 p++;
544 goto append;
548 close:
549 if (*p)
551 char buf [255];
553 tmp = strchr (p, '}');
554 len = strlen (p) - strlen (tmp);
555 tmp = buf;
556 while (len--)
557 *tmp++ = *p++;
559 *tmp = 0;
561 if (*p)
562 p++;
564 if (!non_anchor)
566 tmp = html_escape (buf, strlen (buf), 1);
567 string = string_append_printf (string, "%s\">%s</a>", tmp, buf);
568 xfree (tmp);
570 else
571 string = string_append (string, buf);
573 if (var)
574 string = string_append (string, "</var>");
575 else if (code)
576 string = string_append (string, "</b>");
577 else if (emph)
578 string = string_append (string, "</em>");
579 else if (cite)
580 string = string_append (string, "</cite>");
583 else if (*p == '@' && *(p + 1) == '@')
584 p++;
586 append:
587 string = string_append_printf (string, "%c", *p);
589 if (!*p)
590 break;
593 string = string_append (string, "</body></html>");
594 tmp = string->str;
595 string_free (string, 0);
596 return tmp;
599 static char *
600 strip_texi (const char *str, int html)
602 const char *p;
603 char *s;
604 int c = 0;
606 if (html)
607 return strip_texi_html (str);
609 s = str_dup (str);
610 if (!s)
611 return NULL;
613 for (p = str; *p; p++)
615 if (*p == '@' && *(p + 1) != '@')
617 p++;
619 if (!strncasecmp (p, "table", 5)
620 || !strncasecmp (p, "end ", 4))
622 while (*p++ != '\n');
623 p--;
624 continue;
626 else if (!strncasecmp (p, "example", 7)
627 || !strncasecmp (p, "end ", 4))
629 while (*p++ != '\n');
630 p--;
631 continue;
633 else if (!strncasecmp (p, "sp ", 3))
635 while (*p++ != '\n');
636 p--;
637 continue;
639 else if (!strncasecmp (p, "item", 4))
641 p += 5;
642 while (*p && *p != '\n')
643 s[c++] = *p++;
645 s[c++] = '\n';
646 continue;
648 else if (!strncasecmp (p, "pxref", 5))
650 p += 5;
651 strcat (s, "see ");
652 c = strlen (s);
653 goto close;
655 else if (!strncasecmp (p, "xref", 4))
657 p += 4;
658 strcat (s, "See ");
659 c = strlen (s);
660 goto close;
662 else if (!strncasecmp (p, "*", 1))
664 s[c++] = '\n';
665 s[c] = 0;
666 continue;
669 while (*p && *p != '{')
671 if (*++p == '*')
673 p++;
674 goto append;
678 close:
679 if (*p)
681 p++;
682 s[c++] = '`';
683 while (*p && *p != '}')
684 s[c++] = *p++;
686 if (*p)
687 p++;
689 s[c++] = '\'';
690 s[c] = 0;
693 else if (*p == '@' && *(p + 1) == '@')
694 p++;
696 append:
697 if (*p)
698 s[c++] = *p;
700 s[c] = 0;
703 s[c] = 0;
704 return s;
708 char *
709 strip_texi_and_wrap (const char *str, int html)
711 char *tmp = strip_texi (str, html);
712 char *help = xcalloc (1, strlen (tmp) * 2 + 1);
713 char *p, *ph;
714 int i;
716 for (p = tmp, ph = help, i = 0; *p; p++, i++)
718 if (i == 78 || *p == '\n')
720 if (!isspace (*p))
722 char *t = ph;
723 int n = 0;
725 while (*(--t) != ' ')
726 n++;
728 *t++ = '\n';
729 i = -1;
730 p -= n;
731 while (n--)
733 *t++ = *p++;
734 i++;
737 else
739 *ph++ = '\n';
740 i = -1;
741 while (*p != '\n' && *p == ' ')
742 p++;
746 if (*p == '\n')
747 continue;
748 *ph++ = *p;
751 *ph = 0;
752 xfree (tmp);
753 return help;
756 void
757 free_key (void *data)
759 xfree (data);
762 gpg_error_t
763 create_thread (void *(*cb) (void *), void *data,
764 pthread_t * tid, int detached)
766 pthread_attr_t attr;
767 int n;
769 pthread_attr_init (&attr);
771 if (detached)
772 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
774 n = pthread_create (tid, &attr, cb, data);
775 pthread_attr_destroy (&attr);
776 return gpg_error_from_errno (n);
779 void
780 release_mutex_cb (void *arg)
782 pthread_mutex_t *m = (pthread_mutex_t *) arg;
784 MUTEX_UNLOCK (m);
787 void
788 close_fd_cb (void *arg)
790 int fd = *(int *)arg;
792 if (fd != -1)
793 close (fd);
796 gpg_error_t
797 get_checksum_memory (void *data, size_t size, unsigned char **r_crc,
798 size_t *r_crclen)
800 size_t len = gcry_md_get_algo_dlen (GCRY_MD_CRC32);
801 unsigned char *crc = xmalloc (len);
803 *r_crc = NULL;
804 *r_crclen = 0;
806 if (!crc)
807 return GPG_ERR_ENOMEM;
809 gcry_md_hash_buffer (GCRY_MD_CRC32, crc, data, size);
810 *r_crc = crc;
811 *r_crclen = len;
812 return 0;
815 /* The advisory lock should be obtained before calling this function. */
816 gpg_error_t
817 get_checksum (const char *filename, unsigned char **r_crc, size_t * r_crclen)
819 int fd = -1;
820 unsigned char *buf;
821 gpg_error_t rc;
822 struct stat st;
824 rc = open_check_file (filename, &fd, &st, 1);
825 if (rc)
826 return rc;
828 pthread_cleanup_push (close_fd_cb, &fd);
829 buf = xmalloc (st.st_size);
830 if (buf)
832 pthread_cleanup_push (xfree, buf);
834 size_t len = read (fd, buf, st.st_size);
835 if (len == st.st_size)
837 if (buf)
838 rc = get_checksum_memory (buf, st.st_size, r_crc, r_crclen);
839 else
840 rc = GPG_ERR_ENOMEM;
842 else
843 rc = GPG_ERR_TOO_SHORT;
845 pthread_cleanup_pop (1);
847 else
848 rc = GPG_ERR_ENOMEM;
850 pthread_cleanup_pop (1);
851 return rc;
854 wchar_t *str_to_wchar (const char *str)
856 wchar_t *wc;
857 mbstate_t ps;
858 const char *p = str;
859 size_t len;
861 memset (&ps, 0, sizeof(mbstate_t));
862 len = mbsrtowcs (NULL, &p, 0, &ps);
863 if (len == -1)
864 return NULL;
866 wc = xcalloc (len+1, sizeof(wchar_t));
867 if (!wc)
868 return NULL;
870 p = str;
871 memset (&ps, 0, sizeof(mbstate_t));
872 len = mbsrtowcs (wc, &p, len, &ps);
873 if (len == -1)
875 xfree (wc);
876 return NULL;
879 return wc;
882 char *
883 gnupg_escape (const char *str)
885 if (!str || !*str)
886 return NULL;
888 char *buf = xmalloc (strlen(str)*4+1), *b = buf;
889 const char *p;
891 if (!buf)
892 return NULL;
894 for (p = str; p && *p; p++)
896 if (*p == ':')
898 *b++ = '\\';
899 *b++ = 'x';
900 *b++ = '3';
901 *b++ = 'a';
902 continue;
904 else if (*p == '\\')
906 *b++ = '\\';
907 *b++ = 'x';
908 *b++ = '5';
909 *b++ = 'c';
910 continue;
913 *b++ = *p;
916 *b = 0;
917 return buf;
920 /* From Beej's Guide to Network Programming. It's a good tutorial. */
921 void *
922 get_in_addr (struct sockaddr *sa)
924 if (sa->sa_family == AF_INET)
925 return &(((struct sockaddr_in *) sa)->sin_addr);
927 return &(((struct sockaddr_in6 *) sa)->sin6_addr);
930 gpg_error_t
931 open_check_file (const char *filename, int *r_fd, struct stat *r_st, int reg)
933 int fd;
934 gpg_error_t rc = 0;
936 if (reg)
938 struct stat st;
940 if (lstat (filename, &st) == -1)
941 return gpg_err_code (gpg_error_from_syserror ());
943 if (!S_ISREG (st.st_mode))
944 return GPG_ERR_ENODEV;
946 if (r_st)
947 memcpy (r_st, &st, sizeof (struct stat));
950 if (r_fd)
952 fd = open (filename, O_RDONLY);
953 if (fd == -1)
954 return gpg_err_code (gpg_error_from_syserror ());
956 if (r_st && fstat (fd, r_st) == -1)
958 rc = gpg_err_code (gpg_error_from_syserror ());
959 close (fd);
960 return rc;
963 *r_fd = fd;
966 return 0;