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