Return an error for non-option arguments.
[pwmd.git] / src / util-misc.c
blobaa71d3b29540fd515721a46bb9956a5f4a8ed100
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 /* The 'more' parameter lets the calling command process remaining
161 * non-option arguments. */
162 gpg_error_t
163 parse_options (char **line, struct argv_s * args[], void *data, int more)
165 char *p = *line;
166 gpg_error_t rc = 0;
168 for (; p && *p; p++)
170 while (*p == ' ')
171 p++;
173 if (!*p)
174 break;
176 if (*p == '-' && *(p + 1) == '-')
178 p += 2;
179 char opt[255] = { 0 }, value[255] =
182 char *tp;
183 unsigned len;
185 if (!*p || *p == ' ')
187 if (*p)
188 p++;
190 break;
193 for (tp = opt, len = 0; *p; p++, len++)
195 if (len + 1 == 255)
196 return GPG_ERR_LINE_TOO_LONG;
198 if (*p == ' ' || *p == '=')
200 *tp = 0;
202 if (*p == '=')
204 int inquote = 0;
206 p++;
208 for (tp = value, len = 0; *p; p++, len++)
210 if (len + 1 == 255)
211 return GPG_ERR_LINE_TOO_LONG;
213 if (*p == '\"')
215 inquote = !inquote;
216 continue;
218 else if (*p == ' ' && !inquote)
219 break;
221 *tp++ = *p;
224 *tp = 0;
227 break;
230 *tp++ = *p;
233 *tp = 0;
234 int match = 0;
236 for (int i = 0; args[i]; i++)
238 if (!strcmp (args[i]->opt, opt))
240 log_write1 ("param: name='%s' value='%s'", opt, value);
241 if (args[i]->type == OPTION_TYPE_NOARG && *value)
242 return GPG_ERR_SYNTAX;
243 else if (args[i]->type == OPTION_TYPE_ARG && !*value)
244 return GPG_ERR_SYNTAX;
246 rc = args[i]->func (data, value);
248 if (rc)
249 return rc;
251 match = 1;
252 break;
256 if (!match)
257 return GPG_ERR_UNKNOWN_OPTION;
259 if (!*p)
260 break;
262 continue;
265 if (*(p+1) && !more)
266 return GPG_ERR_SYNTAX;
268 break;
271 *line = p;
272 return rc;
275 char *
276 bin2hex (const unsigned char *data, size_t len)
278 size_t size = len * 2 + 1;
279 char buf[size];
280 size_t n;
282 buf[0] = 0;
284 for (n = 0; n < len; n++)
286 char c[3];
288 sprintf (c, "%02X", data[n]);
289 strcat (buf, c);
292 return str_dup (buf);
295 char *
296 plus_escape (const char *fmt, ...)
298 va_list ap;
299 char *str;
301 va_start (ap, fmt);
303 if (str_vasprintf (&str, fmt, ap) > 0)
305 char *p;
307 for (p = str; *p; p++)
309 if (*p == ' ')
310 *p = '+';
313 va_end (ap);
314 return str;
317 va_end (ap);
318 return NULL;
321 static char *
322 strip_texi (const char *str)
324 const char *p;
325 char *s = str_dup (str);
326 int c = 0;
328 if (!s)
329 return NULL;
331 for (p = str; *p; p++)
333 if (*p == '@' && *(p + 1) != '@')
335 if (!strncasecmp (p + 1, "table", 5)
336 || !strncasecmp (p + 1, "end ", 4))
338 while (*p++ != '\n');
339 p--;
340 continue;
342 else if (!strncasecmp (p + 1, "example", 7)
343 || !strncasecmp (p + 1, "end ", 4))
345 while (*p++ != '\n');
346 p--;
347 continue;
349 else if (!strncasecmp (p + 1, "sp ", 3))
351 p += 3;
353 while (*p && isdigit (*p++))
354 p++;
355 continue;
357 else if (!strncasecmp (p + 1, "item", 4))
359 p += 5;
360 while (*p && *p != '\n')
361 s[c++] = *p++;
363 continue;
365 else if (!strncasecmp (p + 1, "pxref", 5))
367 p += 6;
368 strcat (s, "see ");
369 c = strlen (s);
370 goto close;
372 else if (!strncasecmp (p + 1, "xref", 4))
374 p += 5;
375 strcat (s, "See ");
376 c = strlen (s);
377 goto close;
380 while (*p && *p != '{')
382 if (*++p == '*')
384 p++;
385 goto append;
389 close:
390 if (*p)
392 p++;
393 s[c++] = '`';
394 while (*p && *p != '}')
395 s[c++] = *p++;
397 if (*p)
398 p++;
400 s[c++] = '\'';
403 else if (*p == '@' && *(p + 1) == '@')
404 p++;
406 append:
407 if (*p)
408 s[c++] = *p;
410 s[c] = 0;
413 s[c] = 0;
414 return s;
418 char *
419 strip_texi_and_wrap (const char *str)
421 char *tmp = strip_texi (str);
422 char *help = xmalloc (strlen (tmp) * 2 + 1);
423 char *p, *ph;
424 int i;
426 for (p = tmp, ph = help, i = 0; *p; p++, i++)
428 if (i == 78 || *p == '\n')
430 if (!isspace (*p))
432 char *t = ph;
433 int n = 0;
435 while (!(*--t == ' '))
436 n++;
438 *t++ = '\n';
439 i = -1;
440 p -= n;
441 while (n--)
443 *t++ = *p++;
444 i++;
447 else
449 *ph++ = '\n';
450 i = -1;
451 while (*p != '\n' && *p == ' ')
452 p++;
456 *ph++ = *p;
459 *ph = 0;
460 xfree (tmp);
461 return help;
464 void
465 free_key (void *data)
467 xfree (data);
470 gpg_error_t
471 create_thread (void *(*cb) (void *), void *data,
472 pthread_t * tid, int detached)
474 pthread_attr_t attr;
475 int n;
477 pthread_attr_init (&attr);
479 if (detached)
480 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
482 n = pthread_create (tid, &attr, cb, data);
483 pthread_attr_destroy (&attr);
484 return gpg_error_from_errno (n);
487 void
488 cleanup_mutex_cb (void *arg)
490 pthread_mutex_t *m = (pthread_mutex_t *) arg;
492 MUTEX_UNLOCK (m);
495 void
496 cleanup_fd_cb (void *arg)
498 int fd = *(int *) arg;
500 if (fd != -1)
501 close (fd);
504 void
505 cleanup_unlink_cb (void *arg)
507 char *file = arg;
509 if (file && *file)
510 unlink (file);
513 void
514 cleanup_cache_mutex (void *arg)
516 cache_unlock ();
520 valid_keygrip (const unsigned char *data, size_t len)
522 for (size_t i = 0; i < len; i++)
524 if (data[i])
525 return 1;
528 return 0;
531 gpg_error_t
532 get_checksum (const char *filename, unsigned char **r_crc, size_t * r_crclen)
534 int fd;
535 unsigned char *buf;
536 gpg_error_t rc = 0;
537 struct stat st;
539 if (stat (filename, &st) == -1)
540 return gpg_error_from_errno (errno);
542 fd = open (filename, O_RDONLY);
543 if (fd == -1)
544 return gpg_error_from_errno (errno);
546 pthread_cleanup_push (cleanup_fd_cb, &fd);
547 buf = xmalloc (st.st_size);
548 if (buf)
550 pthread_cleanup_push (xfree, buf);
552 size_t len = read (fd, buf, st.st_size);
553 if (len == st.st_size)
555 if (buf)
557 unsigned char *crc;
559 len = gcry_md_get_algo_dlen (GCRY_MD_CRC32);
560 crc = xmalloc (len);
561 if (crc)
563 pthread_cleanup_push (xfree, crc);
564 gcry_md_hash_buffer (GCRY_MD_CRC32, crc, buf, st.st_size);
565 *r_crc = crc;
566 *r_crclen = len;
567 pthread_cleanup_pop (0);
569 else
570 rc = GPG_ERR_ENOMEM;
573 else
574 rc = GPG_ERR_TOO_SHORT;
576 pthread_cleanup_pop (1);
578 else
579 rc = GPG_ERR_ENOMEM;
581 pthread_cleanup_pop (1);
582 return rc;
585 wchar_t *str_to_wchar (const char *str)
587 wchar_t *wc;
588 mbstate_t ps;
589 const char *p = str;
590 size_t len;
592 memset (&ps, 0, sizeof(mbstate_t));
593 len = mbsrtowcs (NULL, &p, 0, &ps);
594 if (len == -1)
595 return NULL;
597 wc = xcalloc (len+1, sizeof(wchar_t));
598 p = str;
599 memset (&ps, 0, sizeof(mbstate_t));
600 len = mbsrtowcs (wc, &p, len, &ps);
601 return wc;