login_cap.c revision 21399
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 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 = 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 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 = 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 122static void 123freearraystr(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 141void 142login_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 170login_cap_t * 171login_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 214login_cap_t * 215login_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 238login_cap_t * 239login_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 255char * 256login_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 280char ** 281login_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 301char * 302login_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 328rlim_t 329login_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 406rlim_t 407login_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 452rlim_t 453login_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 500int 501login_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 529char * 530login_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 567