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