Update doc/yat2m.c.
[pwmd.git] / src / util-misc.c
blob403af424783a1f1673b7d7dd30ac1681e7df0f48
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,
68 gpg_error_t *rc)
70 struct passwd *result;
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)
85 err = getpwnam_r (user, pw, *buf, len, &result);
86 if (!err)
87 return result;
89 else
91 err = getpwuid_r (uid, pw, *buf, len, &result);
92 if (!err)
93 return result;
96 errno = err;
97 *rc = gpg_error_from_errno (err);
98 return NULL;
99 #else
100 if (buf)
101 *buf = NULL;
103 errno = 0;
104 if (user)
105 result = getpwnam (user);
106 else
107 result = getpwuid (uid);
109 if (!result)
110 *rc = gpg_error_from_syserror ();
112 return result;
113 #endif
116 static char *
117 get_pwd_entry(uid_t uid, int which)
119 gpg_error_t rc;
120 char *buf;
121 struct passwd pw;
122 struct passwd *result = get_pwd_struct (NULL, uid, &pw, &buf, &rc);
123 char *value = NULL;
125 if (!result)
126 return NULL;
128 if (result)
130 if (!which)
131 value = str_dup (result->pw_dir);
132 else
133 value = str_dup (result->pw_name);
136 xfree (buf);
137 return value;
140 char *
141 get_username (uid_t uid)
143 return get_pwd_entry (uid, 1);
146 char *
147 get_home_dir ()
149 if (home_directory)
150 return home_directory;
152 home_directory = get_pwd_entry (getuid(), 0);
153 return home_directory;
156 char *
157 expand_homedir (char *str)
159 char *p = str;
161 if (*p++ == '~')
163 char *dir = get_pwd_entry(getuid(), 0);
164 char *s;
166 if (!dir)
167 return NULL;
169 s = str_asprintf ("%s%s", dir, p);
170 xfree (dir);
171 return s;
174 return str_dup (str);
177 /* The 'more' parameter lets the calling command process remaining
178 * non-option arguments. */
179 gpg_error_t
180 parse_options (char **line, struct argv_s * args[], void *data, int more)
182 char *p = *line;
183 gpg_error_t rc = 0;
185 for (; p && *p; p++)
187 while (*p == ' ')
188 p++;
190 if (!*p)
191 break;
193 if (*p == '-' && *(p + 1) == '-')
195 p += 2;
196 char opt[255] = { 0 }, value[255] =
199 char *tp;
200 unsigned len;
202 if (!*p || *p == ' ')
204 if (*p)
205 p++;
207 break;
210 for (tp = opt, len = 0; *p; p++, len++)
212 if (len + 1 == 255)
213 return GPG_ERR_LINE_TOO_LONG;
215 if (*p == ' ' || *p == '=')
217 *tp = 0;
219 if (*p == '=')
221 int inquote = 0;
223 p++;
225 for (tp = value, len = 0; *p; p++, len++)
227 if (len + 1 == 255)
228 return GPG_ERR_LINE_TOO_LONG;
230 if (*p == '\"')
232 inquote = !inquote;
233 continue;
235 else if (*p == ' ' && !inquote)
236 break;
238 *tp++ = *p;
241 *tp = 0;
244 break;
247 *tp++ = *p;
250 *tp = 0;
251 int match = 0;
253 for (int i = 0; args[i]; i++)
255 if (!strcmp (args[i]->opt, opt))
257 log_write1 ("param: name='%s' value='%s'", opt, value);
258 if (args[i]->type == OPTION_TYPE_NOARG && *value)
259 return GPG_ERR_SYNTAX;
260 else if (args[i]->type == OPTION_TYPE_ARG && !*value)
261 return GPG_ERR_SYNTAX;
263 rc = args[i]->func (data, value);
265 if (rc)
266 return rc;
268 match = 1;
269 break;
273 if (!match)
274 return GPG_ERR_UNKNOWN_OPTION;
276 if (!*p)
277 break;
279 continue;
282 if (*(p+1) && !more)
283 return GPG_ERR_SYNTAX;
285 break;
288 *line = p;
289 return rc;
292 char *
293 bin2hex (const unsigned char *data, size_t len)
295 size_t size = len * 2 + 1;
296 char buf[size];
297 size_t n;
299 buf[0] = 0;
301 for (n = 0; n < len; n++)
303 char c[3];
305 sprintf (c, "%02X", data[n]);
306 strcat (buf, c);
309 return str_dup (buf);
312 char *
313 plus_escape (const char *fmt, ...)
315 va_list ap;
316 char *str;
318 va_start (ap, fmt);
320 if (str_vasprintf (&str, fmt, ap) > 0)
322 char *p;
324 for (p = str; *p; p++)
326 if (*p == ' ')
327 *p = '+';
330 va_end (ap);
331 return str;
334 va_end (ap);
335 return NULL;
338 static char *
339 strip_texi (const char *str)
341 const char *p;
342 char *s = str_dup (str);
343 int c = 0;
345 if (!s)
346 return NULL;
348 for (p = str; *p; p++)
350 if (*p == '@' && *(p + 1) != '@')
352 if (!strncasecmp (p + 1, "table", 5)
353 || !strncasecmp (p + 1, "end ", 4))
355 while (*p++ != '\n');
356 p--;
357 continue;
359 else if (!strncasecmp (p + 1, "example", 7)
360 || !strncasecmp (p + 1, "end ", 4))
362 while (*p++ != '\n');
363 p--;
364 continue;
366 else if (!strncasecmp (p + 1, "sp ", 3))
368 p += 3;
370 while (*p && isdigit (*p++))
371 p++;
372 continue;
374 else if (!strncasecmp (p + 1, "item", 4))
376 p += 5;
377 while (*p && *p != '\n')
378 s[c++] = *p++;
380 s[c++] = ' ';
381 continue;
383 else if (!strncasecmp (p + 1, "pxref", 5))
385 p += 6;
386 strcat (s, "see ");
387 c = strlen (s);
388 goto close;
390 else if (!strncasecmp (p + 1, "xref", 4))
392 p += 5;
393 strcat (s, "See ");
394 c = strlen (s);
395 goto close;
398 while (*p && *p != '{')
400 if (*++p == '*')
402 p++;
403 goto append;
407 close:
408 if (*p)
410 p++;
411 s[c++] = '`';
412 while (*p && *p != '}')
413 s[c++] = *p++;
415 if (*p)
416 p++;
418 s[c++] = '\'';
421 else if (*p == '@' && *(p + 1) == '@')
422 p++;
424 append:
425 if (*p)
426 s[c++] = *p;
428 s[c] = 0;
431 s[c] = 0;
432 return s;
436 char *
437 strip_texi_and_wrap (const char *str)
439 char *tmp = strip_texi (str);
440 char *help = xmalloc (strlen (tmp) * 2 + 1);
441 char *p, *ph;
442 int i;
444 for (p = tmp, ph = help, i = 0; *p; p++, i++)
446 if (i == 78 || *p == '\n')
448 if (!isspace (*p))
450 char *t = ph;
451 int n = 0;
453 while (!(*--t == ' '))
454 n++;
456 *t++ = '\n';
457 i = -1;
458 p -= n;
459 while (n--)
461 *t++ = *p++;
462 i++;
465 else
467 *ph++ = '\n';
468 i = -1;
469 while (*p != '\n' && *p == ' ')
470 p++;
474 *ph++ = *p;
477 *ph = 0;
478 xfree (tmp);
479 return help;
482 void
483 free_key (void *data)
485 xfree (data);
488 gpg_error_t
489 create_thread (void *(*cb) (void *), void *data,
490 pthread_t * tid, int detached)
492 pthread_attr_t attr;
493 int n;
495 pthread_attr_init (&attr);
497 if (detached)
498 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
500 n = pthread_create (tid, &attr, cb, data);
501 pthread_attr_destroy (&attr);
502 return gpg_error_from_errno (n);
505 void
506 cleanup_mutex_cb (void *arg)
508 pthread_mutex_t *m = (pthread_mutex_t *) arg;
510 MUTEX_UNLOCK (m);
513 void
514 cleanup_fd_cb (void *arg)
516 int fd = *(int *) arg;
518 if (fd != -1)
519 close (fd);
522 void
523 cleanup_unlink_cb (void *arg)
525 char *file = arg;
527 if (file && *file)
528 unlink (file);
531 void
532 cleanup_cache_mutex (void *arg)
534 cache_unlock ();
538 valid_keygrip (const unsigned char *data, size_t len)
540 for (size_t i = 0; i < len; i++)
542 if (data[i])
543 return 1;
546 return 0;
549 /* The advisory lock should be obtained before calling this function. */
550 gpg_error_t
551 get_checksum (const char *filename, unsigned char **r_crc, size_t * r_crclen)
553 int fd;
554 unsigned char *buf;
555 gpg_error_t rc = 0;
556 struct stat st;
558 if (stat (filename, &st) == -1)
559 return gpg_error_from_errno (errno);
561 fd = open (filename, O_RDONLY);
562 if (fd == -1)
563 return gpg_error_from_errno (errno);
565 pthread_cleanup_push (cleanup_fd_cb, &fd);
566 buf = xmalloc (st.st_size);
567 if (buf)
569 pthread_cleanup_push (xfree, buf);
571 size_t len = read (fd, buf, st.st_size);
572 if (len == st.st_size)
574 if (buf)
576 unsigned char *crc;
578 len = gcry_md_get_algo_dlen (GCRY_MD_CRC32);
579 crc = xmalloc (len);
580 if (crc)
582 pthread_cleanup_push (xfree, crc);
583 gcry_md_hash_buffer (GCRY_MD_CRC32, crc, buf, st.st_size);
584 *r_crc = crc;
585 *r_crclen = len;
586 pthread_cleanup_pop (0);
588 else
589 rc = GPG_ERR_ENOMEM;
592 else
593 rc = GPG_ERR_TOO_SHORT;
595 pthread_cleanup_pop (1);
597 else
598 rc = GPG_ERR_ENOMEM;
600 pthread_cleanup_pop (1);
601 return rc;
604 wchar_t *str_to_wchar (const char *str)
606 wchar_t *wc;
607 mbstate_t ps;
608 const char *p = str;
609 size_t len;
611 memset (&ps, 0, sizeof(mbstate_t));
612 len = mbsrtowcs (NULL, &p, 0, &ps);
613 if (len == -1)
614 return NULL;
616 wc = xcalloc (len+1, sizeof(wchar_t));
617 p = str;
618 memset (&ps, 0, sizeof(mbstate_t));
619 len = mbsrtowcs (wc, &p, len, &ps);
620 return wc;