]> git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/logindefs.c
chfn: fix use-after-free [coverity scan]
[thirdparty/util-linux.git] / login-utils / logindefs.c
1 /*
2 * Copyright (C) 2003, 2004, 2005 Thorsten Kukuk
3 * Author: Thorsten Kukuk <kukuk@suse.de>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain any existing copyright
10 * notice, and this entire permission notice in its entirety,
11 * including the disclaimer of warranties.
12 *
13 * 2. Redistributions in binary form must reproduce all prior and current
14 * copyright notices, this list of conditions, and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * 3. The name of any author may not be used to endorse or promote
19 * products derived from this software without their specific prior
20 * written permission.
21 */
22 #include <assert.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/syslog.h>
30
31 #include "c.h"
32 #include "logindefs.h"
33 #include "nls.h"
34 #include "pathnames.h"
35 #include "xalloc.h"
36
37 struct item {
38 char *name; /* name of the option. */
39 char *value; /* value of the option. */
40 char *path; /* name of config file for this option. */
41
42 struct item *next; /* pointer to next option. */
43 };
44
45 static struct item *list = NULL;
46
47 void free_getlogindefs_data(void)
48 {
49 struct item *ptr;
50
51 ptr = list;
52 while (ptr) {
53 struct item *tmp = ptr->next;
54
55 free(ptr->path);
56 free(ptr->name);
57 free(ptr->value);
58 free(ptr);
59 ptr = tmp;
60 }
61
62 list = NULL;
63 }
64
65 static void store(const char *name, const char *value, const char *path)
66 {
67 struct item *new = xmalloc(sizeof(struct item));
68
69 if (!name)
70 abort();
71
72 new->name = xstrdup(name);
73 new->value = value && *value ? xstrdup(value) : NULL;
74 new->path = xstrdup(path);
75 new->next = list;
76 list = new;
77 }
78
79 static void load_defaults(const char *filename)
80 {
81 FILE *f;
82 char buf[BUFSIZ];
83
84 f = fopen(filename, "r");
85 if (!f)
86 return;
87
88 while (fgets(buf, sizeof(buf), f)) {
89
90 char *p, *name, *data = NULL;
91
92 if (*buf == '#' || *buf == '\n')
93 continue; /* only comment or empty line */
94
95 p = strchr(buf, '#');
96 if (p)
97 *p = '\0';
98 else {
99 size_t n = strlen(buf);
100 if (n && *(buf + n - 1) == '\n')
101 *(buf + n - 1) = '\0';
102 }
103
104 if (!*buf)
105 continue; /* empty line */
106
107 /* ignore space at begin of the line */
108 name = buf;
109 while (*name && isspace((unsigned)*name))
110 name++;
111
112 /* go to the end of the name */
113 data = name;
114 while (*data && !(isspace((unsigned)*data) || *data == '='))
115 data++;
116 if (data > name && *data)
117 *data++ = '\0';
118
119 if (!*name || data == name)
120 continue;
121
122 /* go to the begin of the value */
123 while (*data
124 && (isspace((unsigned)*data) || *data == '='
125 || *data == '"'))
126 data++;
127
128 /* remove space at the end of the value */
129 p = data + strlen(data);
130 if (p > data)
131 p--;
132 while (p > data && (isspace((unsigned)*p) || *p == '"'))
133 *p-- = '\0';
134
135 store(name, data, filename);
136 }
137
138 fclose(f);
139 }
140
141 static struct item *search(const char *name)
142 {
143 struct item *ptr;
144
145 if (!list)
146 load_defaults(_PATH_LOGINDEFS);
147
148 ptr = list;
149 while (ptr != NULL) {
150 if (strcasecmp(name, ptr->name) == 0)
151 return ptr;
152 ptr = ptr->next;
153 }
154
155 return NULL;
156 }
157
158 static const char *search_config(const char *name)
159 {
160 struct item *ptr;
161
162 ptr = list;
163 while (ptr != NULL) {
164 if (strcasecmp(name, ptr->name) == 0)
165 return ptr->path;
166 ptr = ptr->next;
167 }
168
169 return NULL;
170 }
171
172 int getlogindefs_bool(const char *name, int dflt)
173 {
174 struct item *ptr = search(name);
175 return ptr && ptr->value ? (strcasecmp(ptr->value, "yes") == 0) : dflt;
176 }
177
178 long getlogindefs_num(const char *name, long dflt)
179 {
180 struct item *ptr = search(name);
181 char *end = NULL;
182 long retval;
183
184 if (!ptr || !ptr->value)
185 return dflt;
186
187 errno = 0;
188 retval = strtol(ptr->value, &end, 0);
189 if (end && *end == '\0' && !errno)
190 return retval;
191
192 syslog(LOG_NOTICE, _("%s: %s contains invalid numerical value: %s"),
193 search_config(name), name, ptr->value);
194 return dflt;
195 }
196
197 /*
198 * Returns:
199 * @dflt if @name not found
200 * "" (empty string) if found, but value not defined
201 * "string" if found
202 */
203 const char *getlogindefs_str(const char *name, const char *dflt)
204 {
205 struct item *ptr = search(name);
206
207 if (!ptr)
208 return dflt;
209 if (!ptr->value)
210 return "";
211 return ptr->value;
212 }
213
214 #ifdef TEST_PROGRAM
215 int main(int argc, char *argv[])
216 {
217 char *name, *type;
218
219 if (argc <= 1)
220 errx(EXIT_FAILURE, "usage: %s <filename> "
221 "[<str|num|bool> <valname>]", argv[0]);
222
223 load_defaults(argv[1]);
224
225 if (argc != 4) { /* list all */
226 struct item *ptr;
227
228 for (ptr = list; ptr; ptr = ptr->next)
229 printf("%s: $%s: '%s'\n", ptr->path, ptr->name,
230 ptr->value);
231
232 return EXIT_SUCCESS;
233 }
234
235 type = argv[2];
236 name = argv[3];
237
238 if (strcmp(type, "str") == 0)
239 printf("$%s: '%s'\n", name, getlogindefs_str(name, "DEFAULT"));
240 else if (strcmp(type, "num") == 0)
241 printf("$%s: '%ld'\n", name, getlogindefs_num(name, 0));
242 else if (strcmp(type, "bool") == 0)
243 printf("$%s: '%s'\n", name,
244 getlogindefs_bool(name, 0) ? "Y" : "N");
245
246 return EXIT_SUCCESS;
247 }
248 #endif