]> git.cameronkatri.com Git - pw-darwin.git/blob - libutil/login_cap.c
Make the long-awaited change from $Id$ to $FreeBSD$
[pw-darwin.git] / libutil / login_cap.c
1 /*-
2 * Copyright (c) 1996 by
3 * Sean Eric Fagan <sef@kithrup.com>
4 * David Nugent <davidn@blaze.net.au>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, is permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice immediately at the beginning of the file, without modification,
12 * this list of conditions, and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. This work was done expressly for inclusion into FreeBSD. Other use
17 * is permitted provided this notation is included.
18 * 4. Absolutely no warranty of function or purpose is made by the authors.
19 * 5. Modifications may be freely made to this file providing the above
20 * conditions are met.
21 *
22 * Low-level routines relating to the user capabilities database
23 *
24 * $FreeBSD$
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <unistd.h>
32
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #include <sys/param.h>
37 #include <pwd.h>
38 #include <login_cap.h>
39
40 #ifdef RLIM_LONG
41 # define STRTOV strtol
42 #else
43 # define STRTOV strtoq
44 #endif
45
46 static int lc_object_count = 0;
47
48 static size_t internal_stringsz = 0;
49 static char * internal_string = NULL;
50 static size_t internal_arraysz = 0;
51 static char ** internal_array = NULL;
52
53 static char *
54 allocstr(char * str)
55 {
56 char * p;
57 size_t sz = strlen(str) + 1; /* realloc() only if necessary */
58 if (sz <= internal_stringsz)
59 p = strcpy(internal_string, str);
60 else if ((p = realloc(internal_string, sz)) != NULL) {
61 internal_stringsz = sz;
62 internal_string = strcpy(p, str);
63 }
64 return p;
65 }
66
67 static char **
68 allocarray(size_t sz)
69 {
70 char ** p;
71 if (sz <= internal_arraysz)
72 p = internal_array;
73 else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) {
74 internal_arraysz = sz;
75 internal_array = p;
76 }
77 return p;
78 }
79
80
81 /*
82 * arrayize()
83 * Turn a simple string <str> seperated by any of
84 * the set of <chars> into an array. The last element
85 * of the array will be NULL, as is proper.
86 * Free using freearraystr()
87 */
88
89 static char **
90 arrayize(char *str, const char *chars, int *size)
91 {
92 int i;
93 char *ptr;
94 char **res = NULL;
95
96 for (i = 0, ptr = str; *ptr; i++) {
97 int count = strcspn(ptr, chars);
98 ptr += count;
99 if (*ptr)
100 ++ptr;
101 }
102
103 if ((ptr = allocstr(str)) == NULL) {
104 res = NULL;
105 i = 0;
106 } else if ((res = allocarray(++i)) == NULL) {
107 free(str);
108 i = 0;
109 } else {
110 for (i = 0; *ptr; i++) {
111 int count = strcspn(ptr, chars);
112 res[i] = ptr;
113 ptr += count;
114 if (*ptr)
115 *ptr++ = '\0';
116 }
117 res[i] = 0;
118 }
119 if (size)
120 *size = i;
121 return res;
122 }
123
124 static void
125 freearraystr(char ** array)
126 {
127 /*
128 * the array[0] should be free'd, and then array.
129 */
130 if (array) {
131 free(array[0]);
132 free(array);
133 }
134 }
135
136
137 /*
138 * login_close()
139 * Frees up all resources relating to a login class
140 *
141 */
142
143 void
144 login_close(login_cap_t * lc)
145 {
146 if (lc) {
147 free(lc->lc_style);
148 free(lc->lc_class);
149 free(lc);
150 if (--lc_object_count == 0) {
151 free(internal_string);
152 free(internal_array);
153 internal_array = NULL;
154 internal_string = NULL;
155 cgetclose();
156 }
157 }
158 }
159
160
161 /*
162 * login_getclassbyname() get the login class by its name.
163 * If the name given is NULL or empty, the default class
164 * LOGIN_DEFCLASS (ie. "default") is fetched. If the
165 * 'dir' argument contains a non-NULL non-empty string,
166 * then the file _FILE_LOGIN_CONF is picked up from that
167 * directory instead of the system login database.
168 * Return a filled-out login_cap_t structure, including
169 * class name, and the capability record buffer.
170 */
171
172 login_cap_t *
173 login_getclassbyname(char const * name, char const * dir)
174 {
175 login_cap_t *lc = malloc(sizeof(login_cap_t));
176
177 if (lc != NULL) {
178 int i = 0;
179 char userpath[MAXPATHLEN];
180 static char *login_dbarray[] = { NULL, NULL, NULL };
181
182 if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, _FILE_LOGIN_CONF) < MAXPATHLEN)
183 login_dbarray[i++] = userpath;
184 else
185 login_dbarray[i++] = _PATH_LOGIN_CONF;
186 login_dbarray[i ] = NULL;
187
188 lc->lc_cap = lc->lc_class = lc->lc_style = NULL;
189
190 if ((name == NULL || cgetent(&lc->lc_cap, login_dbarray, (char*)name) != 0) &&
191 cgetent(&lc->lc_cap, login_dbarray, (char*)(name = LOGIN_DEFCLASS)) != 0) {
192 free(lc);
193 lc = NULL;
194 } else {
195 ++lc_object_count;
196 lc->lc_class = strdup(name);
197 }
198 }
199
200 return lc;
201 }
202
203
204
205 /*
206 * login_getclass()
207 * Get the login class for a given password entry from
208 * the system (only) login class database.
209 * If the password entry's class field is not set, or
210 * the class specified does not exist, then use the
211 * default of LOGIN_DEFCLASS (ie. "default").
212 * Return a filled-out login_cap_t structure, including
213 * class name, and the capability record buffer.
214 */
215
216 login_cap_t *
217 login_getclass(const struct passwd *pwd)
218 {
219 const char * class = NULL;
220 if (pwd != NULL) {
221 if ((class = pwd->pw_class) == NULL || *class == '\0')
222 class = (pwd->pw_uid == 0) ? "root" : NULL;
223 }
224 return login_getclassbyname(class, 0);
225 }
226
227
228 /*
229 * login_getuserclass()
230 * Get the login class for a given password entry, allowing user
231 * overrides via ~/.login_conf.
232 * ### WAS: If the password entry's class field is not set,
233 * ####### or the class specified does not exist, then use
234 * If an entry with the recordid "me" does not exist, then use
235 * the default of LOGIN_DEFCLASS (ie. "default").
236 * Return a filled-out login_cap_t structure, including
237 * class name, and the capability record buffer.
238 */
239
240 login_cap_t *
241 login_getuserclass(const struct passwd *pwd)
242 {
243 const char * class = "me"; /* (pwd == NULL) ? NULL : pwd->pw_class; */
244 const char * home = (pwd == NULL) ? NULL : pwd->pw_dir;
245 return login_getclassbyname(class, home);
246 }
247
248
249
250 /*
251 * login_getcapstr()
252 * Given a login_cap entry, and a capability name, return the
253 * value defined for that capability, a defualt if not found, or
254 * an error string on error.
255 */
256
257 char *
258 login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error)
259 {
260 char *res;
261 int ret;
262
263 if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0')
264 return def;
265
266 if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) {
267 return def;
268 } else if (ret >= 0)
269 return res;
270 else
271 return error;
272 }
273
274
275 /*
276 * login_getcaplist()
277 * Given a login_cap entry, and a capability name, return the
278 * value defined for that capability split into an array of
279 * strings.
280 */
281
282 char **
283 login_getcaplist(login_cap_t *lc, const char * cap, const char * chars)
284 {
285 char * lstring;
286
287 if (chars == NULL)
288 chars = ". \t";
289 if ((lstring = login_getcapstr(lc, (char*)cap, NULL, NULL)) != NULL)
290 return arrayize(lstring, chars, NULL);
291 return NULL;
292 }
293
294
295 /*
296 * login_getpath()
297 * From the login_cap_t <lc>, get the capability <cap> which is
298 * formatted as either a space or comma delimited list of paths
299 * and append them all into a string and separate by semicolons.
300 * If there is an error of any kind, return <error>.
301 */
302
303 char *
304 login_getpath(login_cap_t *lc, const char *cap, char * error)
305 {
306 char *str = login_getcapstr(lc, (char*)cap, NULL, NULL);
307
308 if (str == NULL)
309 str = error;
310 else {
311 char *ptr = str;
312
313 while (*ptr) {
314 int count = strcspn(ptr, ", \t");
315 ptr += count;
316 if (*ptr)
317 *ptr++ = ':';
318 }
319 }
320 return str;
321 }
322
323
324 /*
325 * login_getcaptime()
326 * From the login_cap_t <lc>, get the capability <cap>, which is
327 * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not
328 * present in <lc>, return <def>; if there is an error of some kind,
329 * return <error>.
330 */
331
332 rlim_t
333 login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
334 {
335 char *res, *ep;
336 int ret;
337 rlim_t tot = 0, tim;
338
339 errno = 0;
340 if (lc == NULL || lc->lc_cap == NULL)
341 return def;
342
343 /*
344 * Look for <cap> in lc_cap.
345 * If it's not there (-1), return <def>.
346 * If there's an error, return <error>.
347 */
348
349 if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
350 return def;
351 else if (ret < 0)
352 return error;
353
354 /*
355 * "inf" and "infinity" are two special cases for this.
356 */
357 if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
358 return RLIM_INFINITY;
359
360 /*
361 * Now go through the string, turning something like 1h2m3s into
362 * an integral value. Whee.
363 */
364
365 errno = 0;
366 while (*res) {
367 tim = STRTOV(res, &ep, 0);
368 if ((ep == NULL) || (ep == res) || errno) {
369 return error;
370 }
371 /* Look for suffixes */
372 switch (*ep++) {
373 case 0:
374 ep--; break; /* end of string */
375 case 's': case 'S': /* seconds */
376 break;
377 case 'm': case 'M': /* minutes */
378 tim *= 60L;
379 break;
380 case 'h': case 'H': /* hours */
381 tim *= (60L * 60L);
382 break;
383 case 'd': case 'D': /* days */
384 tim *= (60L * 60L * 24L);
385 break;
386 case 'w': case 'W': /* weeks */
387 tim *= (60L * 60L * 24L * 7L);
388 case 'y': case 'Y': /* Years */
389 /* I refuse to take leap years into account here. Sue me. */
390 tim *= (60L * 60L * 24L * 365L);
391 default:
392 return error;
393 }
394 res = ep;
395 tot += tim;
396 }
397 return tot;
398 }
399
400
401 /*
402 * login_getcapnum()
403 * From the login_cap_t <lc>, extract the numerical value <cap>.
404 * If it is not present, return <def> for a default, and return
405 * <error> if there is an error.
406 * Like login_getcaptime(), only it only converts to a number, not
407 * to a time; "infinity" and "inf" are 'special.'
408 */
409
410 rlim_t
411 login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
412 {
413 char *ep, *res;
414 int ret;
415 rlim_t val;
416
417 if (lc == NULL || lc->lc_cap == NULL)
418 return def;
419
420 /*
421 * For BSDI compatibility, try for the tag=<val> first
422 */
423 if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) {
424 long lval;
425 /*
426 * String capability not present, so try for tag#<val> as numeric
427 */
428 if ((ret = cgetnum(lc->lc_cap, (char *)cap, &lval)) == -1)
429 return def; /* Not there, so return default */
430 else if (ret < 0)
431 return error;
432 return (rlim_t)lval;
433 }
434 else if (ret < 0)
435 return error;
436
437 if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
438 return RLIM_INFINITY;
439
440 errno = 0;
441 val = STRTOV(res, &ep, 0);
442 if ((ep == NULL) || (ep == res) || errno)
443 return error;
444 return val;
445 }
446
447
448 /*
449 * login_getcapsize()
450 * From the login_cap_t <lc>, extract the capability <cap>, which is
451 * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity".
452 * If not present, return <def>, or <error> if there is an error of
453 * some sort.
454 */
455
456 rlim_t
457 login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) {
458 char *ep, *res;
459 int ret;
460 rlim_t val;
461 rlim_t mult;
462
463 if (lc == NULL || lc->lc_cap == NULL)
464 return def;
465
466 if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
467 return def;
468 else if (ret < 0)
469 return error;
470
471 errno = 0;
472 val = STRTOV(res, &ep, 0);
473 if ((res == NULL) || (res == ep) || errno)
474 return error;
475 switch (*ep) {
476 case 0: /* end of string */
477 mult = 1; break;
478 case 'b': case 'B': /* 512-byte blocks */
479 mult = 512; break;
480 case 'k': case 'K': /* 1024-byte Kilobytes */
481 mult = 1024; break;
482 case 'm': case 'M': /* 1024-k kbytes */
483 mult = 1024 * 1024; break;
484 case 'g': case 'G': /* 1Gbyte */
485 mult = 1024 * 1024 * 1024; break;
486 #ifndef RLIM_LONG
487 case 't': case 'T': /* 1TBte */
488 mult = 1024LL * 1024LL * 1024LL * 1024LL; break;
489 #endif
490 default:
491 return error;
492 }
493 return val * mult;
494 }
495
496
497 /*
498 * login_getcapbool()
499 * From the login_cap_t <lc>, check for the existance of the capability
500 * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return
501 * the whether or not <cap> exists there.
502 */
503
504 int
505 login_getcapbool(login_cap_t *lc, const char *cap, int def)
506 {
507 if (lc == NULL || lc->lc_cap == NULL)
508 return def;
509 return (cgetcap(lc->lc_cap, (char *)cap, ':') != NULL);
510 }
511
512
513 /*
514 * login_getstyle()
515 * Given a login_cap entry <lc>, and optionally a type of auth <auth>,
516 * and optionally a style <style>, find the style that best suits these
517 * rules:
518 * 1. If <auth> is non-null, look for an "auth-<auth>=" string
519 * in the capability; if not present, default to "auth=".
520 * 2. If there is no auth list found from (1), default to
521 * "passwd" as an authorization list.
522 * 3. If <style> is non-null, look for <style> in the list of
523 * authorization methods found from (2); if <style> is NULL, default
524 * to LOGIN_DEFSTYLE ("passwd").
525 * 4. If the chosen style is found in the chosen list of authorization
526 * methods, return that; otherwise, return NULL.
527 * E.g.:
528 * login_getstyle(lc, NULL, "ftp");
529 * login_getstyle(lc, "login", NULL);
530 * login_getstyle(lc, "skey", "network");
531 */
532
533 char *
534 login_getstyle(login_cap_t *lc, char *style, const char *auth)
535 {
536 int i;
537 char **authtypes = NULL;
538 char *auths= NULL;
539 char realauth[64];
540
541 static char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL };
542
543 if (auth != NULL && *auth != '\0' &&
544 snprintf(realauth, sizeof realauth, "auth-%s", auth) < sizeof realauth)
545 authtypes = login_getcaplist(lc, realauth, NULL);
546
547 if (authtypes == NULL)
548 authtypes = login_getcaplist(lc, "auth", NULL);
549
550 if (authtypes == NULL)
551 authtypes = defauthtypes;
552
553 /*
554 * We have at least one authtype now; auths is a comma-seperated
555 * (or space-separated) list of authentication types. We have to
556 * convert from this to an array of char*'s; authtypes then gets this.
557 */
558 i = 0;
559 if (style != NULL && *style != '\0') {
560 while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0)
561 i++;
562 }
563 lc->lc_style = NULL;
564 if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL)
565 lc->lc_style = auths;
566
567 return lc->lc_style;
568 }
569
570