]>
Commit | Line | Data |
---|---|---|
c82d9c97 KZ |
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 | */ | |
3f9c237d | 22 | #include <assert.h> |
c82d9c97 | 23 | #include <ctype.h> |
3f9c237d SK |
24 | #include <errno.h> |
25 | #include <limits.h> | |
c82d9c97 KZ |
26 | #include <stdio.h> |
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
c82d9c97 KZ |
29 | #include <sys/syslog.h> |
30 | ||
31 | #include "c.h" | |
439cdf1e | 32 | #include "closestream.h" |
3f9c237d | 33 | #include "logindefs.h" |
c82d9c97 | 34 | #include "nls.h" |
c82d9c97 | 35 | #include "pathnames.h" |
3f9c237d | 36 | #include "xalloc.h" |
c82d9c97 KZ |
37 | |
38 | struct item { | |
39 | char *name; /* name of the option. */ | |
40 | char *value; /* value of the option. */ | |
41 | char *path; /* name of config file for this option. */ | |
42 | ||
43 | struct item *next; /* pointer to next option. */ | |
44 | }; | |
45 | ||
46 | static struct item *list = NULL; | |
47 | ||
9c44ac50 LN |
48 | void (*logindefs_load_defaults)(void) = NULL; |
49 | ||
c82d9c97 KZ |
50 | void free_getlogindefs_data(void) |
51 | { | |
52 | struct item *ptr; | |
53 | ||
54 | ptr = list; | |
55 | while (ptr) { | |
56 | struct item *tmp = ptr->next; | |
57 | ||
58 | free(ptr->path); | |
59 | free(ptr->name); | |
60 | free(ptr->value); | |
61 | free(ptr); | |
62 | ptr = tmp; | |
63 | } | |
64 | ||
65 | list = NULL; | |
66 | } | |
67 | ||
68 | static void store(const char *name, const char *value, const char *path) | |
69 | { | |
70 | struct item *new = xmalloc(sizeof(struct item)); | |
71 | ||
72 | if (!name) | |
73 | abort(); | |
74 | ||
75 | new->name = xstrdup(name); | |
76 | new->value = value && *value ? xstrdup(value) : NULL; | |
77 | new->path = xstrdup(path); | |
78 | new->next = list; | |
79 | list = new; | |
80 | } | |
81 | ||
9c44ac50 | 82 | void logindefs_load_file(const char *filename) |
c82d9c97 KZ |
83 | { |
84 | FILE *f; | |
85 | char buf[BUFSIZ]; | |
86 | ||
87 | f = fopen(filename, "r"); | |
88 | if (!f) | |
89 | return; | |
90 | ||
91 | while (fgets(buf, sizeof(buf), f)) { | |
92 | ||
93 | char *p, *name, *data = NULL; | |
94 | ||
95 | if (*buf == '#' || *buf == '\n') | |
3f9c237d | 96 | continue; /* only comment or empty line */ |
c82d9c97 KZ |
97 | |
98 | p = strchr(buf, '#'); | |
99 | if (p) | |
100 | *p = '\0'; | |
101 | else { | |
102 | size_t n = strlen(buf); | |
103 | if (n && *(buf + n - 1) == '\n') | |
104 | *(buf + n - 1) = '\0'; | |
105 | } | |
106 | ||
107 | if (!*buf) | |
3f9c237d | 108 | continue; /* empty line */ |
c82d9c97 KZ |
109 | |
110 | /* ignore space at begin of the line */ | |
111 | name = buf; | |
3f9c237d | 112 | while (*name && isspace((unsigned)*name)) |
c82d9c97 KZ |
113 | name++; |
114 | ||
115 | /* go to the end of the name */ | |
116 | data = name; | |
3f9c237d | 117 | while (*data && !(isspace((unsigned)*data) || *data == '=')) |
c82d9c97 KZ |
118 | data++; |
119 | if (data > name && *data) | |
120 | *data++ = '\0'; | |
121 | ||
122 | if (!*name || data == name) | |
123 | continue; | |
124 | ||
125 | /* go to the begin of the value */ | |
3f9c237d SK |
126 | while (*data |
127 | && (isspace((unsigned)*data) || *data == '=' | |
128 | || *data == '"')) | |
129 | data++; | |
c82d9c97 KZ |
130 | |
131 | /* remove space at the end of the value */ | |
132 | p = data + strlen(data); | |
133 | if (p > data) | |
134 | p--; | |
3f9c237d | 135 | while (p > data && (isspace((unsigned)*p) || *p == '"')) |
c82d9c97 KZ |
136 | *p-- = '\0'; |
137 | ||
138 | store(name, data, filename); | |
139 | } | |
140 | ||
141 | fclose(f); | |
142 | } | |
143 | ||
4082ab2c | 144 | static void load_defaults(void) |
9c44ac50 LN |
145 | { |
146 | if (logindefs_load_defaults) | |
147 | logindefs_load_defaults(); | |
148 | else | |
149 | logindefs_load_file(_PATH_LOGINDEFS); | |
150 | } | |
151 | ||
c82d9c97 KZ |
152 | static struct item *search(const char *name) |
153 | { | |
154 | struct item *ptr; | |
155 | ||
156 | if (!list) | |
9c44ac50 | 157 | load_defaults(); |
c82d9c97 KZ |
158 | |
159 | ptr = list; | |
160 | while (ptr != NULL) { | |
161 | if (strcasecmp(name, ptr->name) == 0) | |
162 | return ptr; | |
163 | ptr = ptr->next; | |
164 | } | |
165 | ||
166 | return NULL; | |
167 | } | |
168 | ||
169 | static const char *search_config(const char *name) | |
170 | { | |
171 | struct item *ptr; | |
172 | ||
173 | ptr = list; | |
174 | while (ptr != NULL) { | |
175 | if (strcasecmp(name, ptr->name) == 0) | |
176 | return ptr->path; | |
177 | ptr = ptr->next; | |
178 | } | |
179 | ||
180 | return NULL; | |
181 | } | |
182 | ||
183 | int getlogindefs_bool(const char *name, int dflt) | |
184 | { | |
3f9c237d | 185 | struct item *ptr = search(name); |
c82d9c97 KZ |
186 | return ptr && ptr->value ? (strcasecmp(ptr->value, "yes") == 0) : dflt; |
187 | } | |
188 | ||
c9baf5da | 189 | unsigned long getlogindefs_num(const char *name, long dflt) |
c82d9c97 KZ |
190 | { |
191 | struct item *ptr = search(name); | |
192 | char *end = NULL; | |
c9baf5da | 193 | unsigned long retval; |
c82d9c97 KZ |
194 | |
195 | if (!ptr || !ptr->value) | |
196 | return dflt; | |
197 | ||
198 | errno = 0; | |
c9baf5da | 199 | retval = strtoul(ptr->value, &end, 0); |
c82d9c97 KZ |
200 | if (end && *end == '\0' && !errno) |
201 | return retval; | |
202 | ||
203 | syslog(LOG_NOTICE, _("%s: %s contains invalid numerical value: %s"), | |
3f9c237d | 204 | search_config(name), name, ptr->value); |
c82d9c97 KZ |
205 | return dflt; |
206 | } | |
207 | ||
208 | /* | |
209 | * Returns: | |
210 | * @dflt if @name not found | |
211 | * "" (empty string) if found, but value not defined | |
212 | * "string" if found | |
213 | */ | |
214 | const char *getlogindefs_str(const char *name, const char *dflt) | |
215 | { | |
216 | struct item *ptr = search(name); | |
217 | ||
218 | if (!ptr) | |
219 | return dflt; | |
220 | if (!ptr->value) | |
221 | return ""; | |
222 | return ptr->value; | |
223 | } | |
224 | ||
607e6b7c | 225 | /* |
a8077509 | 226 | * For compatibility with shadow-utils we have to support additional |
607e6b7c KZ |
227 | * syntax for environment variables in login.defs(5) file. The standard |
228 | * syntax is: | |
229 | * | |
230 | * ENV_FOO data | |
231 | * | |
232 | * but shadow-utils supports also | |
233 | * | |
234 | * ENV_FOO FOO=data | |
235 | * | |
236 | * the FOO= prefix has to be remove before we call setenv(). | |
237 | */ | |
238 | int logindefs_setenv(const char *name, const char *conf, const char *dflt) | |
239 | { | |
240 | const char *val = getlogindefs_str(conf, dflt); | |
241 | const char *p; | |
242 | ||
243 | if (!val) | |
244 | return -1; | |
245 | ||
246 | p = strchr(val, '='); | |
247 | if (p) { | |
248 | size_t sz = strlen(name); | |
249 | ||
250 | if (strncmp(val, name, sz) == 0 && *(p + 1)) { | |
251 | val = p + 1; | |
252 | if (*val == '"') | |
253 | val++; | |
254 | if (!*val) | |
255 | val = dflt; | |
256 | } | |
257 | } | |
258 | ||
259 | return val ? setenv(name, val, 1) : -1; | |
260 | } | |
261 | ||
c82d9c97 KZ |
262 | #ifdef TEST_PROGRAM |
263 | int main(int argc, char *argv[]) | |
264 | { | |
265 | char *name, *type; | |
439cdf1e | 266 | atexit(close_stdout); |
c82d9c97 KZ |
267 | |
268 | if (argc <= 1) | |
269 | errx(EXIT_FAILURE, "usage: %s <filename> " | |
3f9c237d | 270 | "[<str|num|bool> <valname>]", argv[0]); |
c82d9c97 | 271 | |
9c44ac50 | 272 | logindefs_load_file(argv[1]); |
c82d9c97 | 273 | |
3f9c237d | 274 | if (argc != 4) { /* list all */ |
c82d9c97 KZ |
275 | struct item *ptr; |
276 | ||
277 | for (ptr = list; ptr; ptr = ptr->next) | |
3f9c237d SK |
278 | printf("%s: $%s: '%s'\n", ptr->path, ptr->name, |
279 | ptr->value); | |
c82d9c97 KZ |
280 | |
281 | return EXIT_SUCCESS; | |
282 | } | |
283 | ||
284 | type = argv[2]; | |
285 | name = argv[3]; | |
286 | ||
287 | if (strcmp(type, "str") == 0) | |
288 | printf("$%s: '%s'\n", name, getlogindefs_str(name, "DEFAULT")); | |
289 | else if (strcmp(type, "num") == 0) | |
290 | printf("$%s: '%ld'\n", name, getlogindefs_num(name, 0)); | |
291 | else if (strcmp(type, "bool") == 0) | |
3f9c237d SK |
292 | printf("$%s: '%s'\n", name, |
293 | getlogindefs_bool(name, 0) ? "Y" : "N"); | |
c82d9c97 KZ |
294 | |
295 | return EXIT_SUCCESS; | |
296 | } | |
297 | #endif |