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