File: read_config.c

package info (click to toggle)
account-utils 1.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 836 kB
  • sloc: ansic: 8,789; xml: 1,584; sh: 77; makefile: 10
file content (191 lines) | stat: -rw-r--r-- 4,469 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// SPDX-License-Identifier: GPL-2.0-or-later

#include <pwd.h>
#include <ctype.h>
#include <errno.h>
#include <libeconf.h>

#include "basics.h"
#include "read_config.h"

struct config_t *
struct_config_free(struct config_t *cfg)
{
  cfg->allow_get_user_record = mfree(cfg->allow_get_user_record);
  cfg->allow_verify_password = mfree(cfg->allow_verify_password);
  cfg->allow_expired_check = mfree(cfg->allow_expired_check);
  return NULL;
}

/* trim leading and trailing whitespaces */
static char *
trim_whitespace(char *str)
{
  char *end;

  while(isspace((unsigned char)*str))
    str++;

  if(*str == '\0')
    return str;

  end = str + strlen(str) - 1;

  while(end > str && isspace((unsigned char)*end))
    end--;

  *(end+1) = 0;
  return str;
}

/* function to resolve a single user string (name or UID) to a uid_t
   Returns 0 on success, -errno on failure */
static int
parse_token(const char *token, uid_t *result_uid)
{
  if (isempty(token))
    return -EINVAL;

  /* if the first character is a number, it must be a UID */
  if (isdigit(token[0]))
    {
      char *ep;
      long long ll;

      errno = 0;
      ll = strtol(token, &ep, 10);
      if (errno == ERANGE || ll < 0 || ll > UINT32_MAX ||
	  token == ep || *ep != '\0')
	{
	  if (errno == 0)
	    return -EINVAL;
	  else
	    return -errno;
	}
      *result_uid = (uid_t)ll;
      return 0;
    }
  else /* Try as username */
    {
      struct passwd *pwd;

      errno = 0;
      pwd = getpwnam(token);
      if (pwd == NULL)
	{
	  if (errno == 0)
	    return -ENODATA;
	  else
	    return -errno;
	}

      *result_uid = pwd->pw_uid;
    }
  return 0;
}

static econf_err
lookup_group(econf_file *key_file, const char *group, uid_t **list)
{
  _cleanup_free_ char *value = NULL;
  _cleanup_free_ uid_t *uids = NULL;
  econf_err error;

  *list = NULL;

  /* look at first in method specific group */
  error = econf_getStringValue(key_file, group, "allow", &value);
  if (error == ECONF_NOKEY || error == ECONF_NOGROUP)
    /* Fallback if key not found */
    error = econf_getStringValue(key_file, "global", "allow", &value);
  if (error == ECONF_NOKEY || error == ECONF_NOGROUP)
    /* no data, done */
    return ECONF_SUCCESS;
  /* error out in other cases */
  if (error != ECONF_SUCCESS)
    return error;

  if (isempty(value))
    return ECONF_SUCCESS;

  /* split value into tokens and parse them */

  /* count number of tokens */
  size_t count = 0;
  for (size_t i = 0; value[i] != '\0'; i++)
    if (value[i] == ',')
      count++;
  count++;

  /* allocate one more slot for the final "NULL" */
  uids = calloc(count + 1, sizeof (uid_t));
  if (uids == NULL)
    return ECONF_NOMEM;

  /* Split and store */
  count = 0;
  char *token = strtok(value, ",");
  while (token != NULL)
    {
      uid_t uid = 0;
      int r;

      token = trim_whitespace(token);
      r = parse_token(token, &uid);
      token = strtok(NULL, ",");
      if (r < 0)
	{
	  /* XXX we need a good warning */
	  continue; /* continue with the other user */
	}
      if (uid == 0) /* root is allways allowed, ignore */
	continue;
      uids[count++] = uid;
    }
  uids[count] = 0;

  *list = TAKE_PTR(uids);

  return ECONF_SUCCESS;
}

/* we will read everything and only report the firstx error */
econf_err
read_config(struct config_t *cfg)
{
  _cleanup_(econf_freeFilep) econf_file *key_file = NULL;
  econf_err error;
  econf_err retval = ECONF_SUCCESS;

#ifdef TESTSDIR
  error = econf_newKeyFile_with_options(&key_file, "ROOT_PREFIX="TESTSDIR);
  if (error)
    return error;
#endif

  /* This looks for pwaccessd.conf{.d} in /usr/share/account-utils/
     or /etc/account-utils/ */
  error = econf_readConfig(&key_file,
			   "account-utils", /* project name */
			   "/usr/share",    /* directory below /usr */
			   "pwaccessd",     /* file name without extension */
			   "conf",          /* suffix */
			   "=",             /* delimiter */
			   "#");            /* comment */
  if (error != ECONF_SUCCESS)
    return error;

  /* XXX read debug_level from [global] and set max_log_level */

  error = lookup_group(key_file, "GetUserRecord", &(cfg->allow_get_user_record));
  if (error && !retval)
    retval = error;
  error = lookup_group(key_file, "VerifyPassword", &(cfg->allow_verify_password));
  if (error && !retval)
    retval = error;
  error = lookup_group(key_file, "ExpiredCheck", &(cfg->allow_expired_check));
  if (error && !retval)
    return error;

  return retval;
}