systems.c revision 44612
1/* 2 * System configuration routines 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: systems.c,v 1.41 1999/02/02 09:35:30 brian Exp $ 21 * 22 * TODO: 23 */ 24#include <sys/param.h> 25 26#include <ctype.h> 27#include <pwd.h> 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31#include <unistd.h> 32 33#include "defs.h" 34#include "command.h" 35#include "log.h" 36#include "id.h" 37#include "systems.h" 38 39#define issep(ch) ((ch) == ' ' || (ch) == '\t') 40 41FILE * 42OpenSecret(const char *file) 43{ 44 FILE *fp; 45 char line[100]; 46 47 snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file); 48 fp = ID0fopen(line, "r"); 49 if (fp == NULL) 50 log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line); 51 return (fp); 52} 53 54void 55CloseSecret(FILE * fp) 56{ 57 fclose(fp); 58} 59 60/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */ 61static void 62InterpretArg(char *from, char *to) 63{ 64 const char *env; 65 char *ptr, *startto, *endto; 66 int len; 67 68 startto = to; 69 endto = to + LINE_LEN - 1; 70 71 while(issep(*from)) 72 from++; 73 if (*from == '~') { 74 ptr = strchr(++from, '/'); 75 len = ptr ? ptr - from : strlen(from); 76 if (len == 0) { 77 if ((env = getenv("HOME")) == NULL) 78 env = _PATH_PPP; 79 strncpy(to, env, endto - to); 80 } else { 81 struct passwd *pwd; 82 83 strncpy(to, from, len); 84 to[len] = '\0'; 85 pwd = getpwnam(to); 86 if (pwd) 87 strncpy(to, pwd->pw_dir, endto-to); 88 else 89 strncpy(to, _PATH_PPP, endto - to); 90 endpwent(); 91 } 92 *endto = '\0'; 93 to += strlen(to); 94 from += len; 95 } 96 97 while (to < endto && *from != '\0') { 98 if (*from == '$') { 99 if (from[1] == '$') { 100 *to = '\0'; /* For an empty var name below */ 101 from += 2; 102 } else if (from[1] == '{') { 103 ptr = strchr(from+2, '}'); 104 if (ptr) { 105 len = ptr - from - 2; 106 if (endto - to < len ) 107 len = endto - to; 108 if (len) { 109 strncpy(to, from+2, len); 110 to[len] = '\0'; 111 from = ptr+1; 112 } else { 113 *to++ = *from++; 114 continue; 115 } 116 } else { 117 *to++ = *from++; 118 continue; 119 } 120 } else { 121 ptr = to; 122 for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++) 123 *ptr++ = *from; 124 *ptr = '\0'; 125 } 126 if (*to == '\0') 127 *to++ = '$'; 128 else if ((env = getenv(to)) != NULL) { 129 strncpy(to, env, endto - to); 130 *endto = '\0'; 131 to += strlen(to); 132 } 133 } else 134 *to++ = *from++; 135 } 136 while (to > startto) { 137 to--; 138 if (!issep(*to)) { 139 to++; 140 break; 141 } 142 } 143 *to = '\0'; 144} 145 146#define CTRL_UNKNOWN (0) 147#define CTRL_INCLUDE (1) 148 149static int 150DecodeCtrlCommand(char *line, char *arg) 151{ 152 if (!strncasecmp(line, "include", 7) && issep(line[7])) { 153 InterpretArg(line+8, arg); 154 return CTRL_INCLUDE; 155 } 156 return CTRL_UNKNOWN; 157} 158 159/* 160 * Initialised in system_IsValid(), set in ReadSystem(), 161 * used by system_IsValid() 162 */ 163static int modeok; 164static int userok; 165static int modereq; 166 167int 168AllowUsers(struct cmdargs const *arg) 169{ 170 /* arg->bundle may be NULL (see system_IsValid()) ! */ 171 int f; 172 char *user; 173 174 userok = 0; 175 user = getlogin(); 176 if (user && *user) 177 for (f = arg->argn; f < arg->argc; f++) 178 if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) { 179 userok = 1; 180 break; 181 } 182 183 return 0; 184} 185 186int 187AllowModes(struct cmdargs const *arg) 188{ 189 /* arg->bundle may be NULL (see system_IsValid()) ! */ 190 int f, mode, allowed; 191 192 allowed = 0; 193 for (f = arg->argn; f < arg->argc; f++) { 194 mode = Nam2mode(arg->argv[f]); 195 if (mode == PHYS_NONE || mode == PHYS_ALL) 196 log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]); 197 else 198 allowed |= mode; 199 } 200 201 modeok = modereq & allowed ? 1 : 0; 202 return 0; 203} 204 205static char * 206strip(char *line) 207{ 208 int len; 209 210 len = strlen(line); 211 while (len && (line[len-1] == '\n' || line[len-1] == '\r' || 212 issep(line[len-1]))) 213 line[--len] = '\0'; 214 215 while (issep(*line)) 216 line++; 217 218 if (*line == '#') 219 *line = '\0'; 220 221 return line; 222} 223 224static int 225xgets(char *buf, int buflen, FILE *fp) 226{ 227 int len, n; 228 229 n = 0; 230 while (fgets(buf, buflen-1, fp)) { 231 n++; 232 buf[buflen-1] = '\0'; 233 len = strlen(buf); 234 while (len && (buf[len-1] == '\n' || buf[len-1] == '\r')) 235 buf[--len] = '\0'; 236 if (len && buf[len-1] == '\\') { 237 buf += len - 1; 238 buflen -= len - 1; 239 if (!buflen) /* No buffer space */ 240 break; 241 } else 242 break; 243 } 244 return n; 245} 246 247/* Values for ``how'' in ReadSystem */ 248#define SYSTEM_EXISTS 1 249#define SYSTEM_VALIDATE 2 250#define SYSTEM_EXEC 3 251 252/* Returns -2 for ``file not found'' and -1 for ``label not found'' */ 253 254static int 255ReadSystem(struct bundle *bundle, const char *name, const char *file, 256 struct prompt *prompt, struct datalink *cx, int how) 257{ 258 FILE *fp; 259 char *cp, *wp; 260 int n, len; 261 char line[LINE_LEN]; 262 char filename[MAXPATHLEN]; 263 int linenum; 264 int argc; 265 char *argv[MAXARGS]; 266 int allowcmd; 267 int indent; 268 char arg[LINE_LEN]; 269 270 if (*file == '/') 271 snprintf(filename, sizeof filename, "%s", file); 272 else 273 snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file); 274 fp = ID0fopen(filename, "r"); 275 if (fp == NULL) { 276 log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename); 277 return -2; 278 } 279 log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); 280 281 linenum = 0; 282 while ((n = xgets(line, sizeof line, fp))) { 283 linenum += n; 284 if (issep(*line)) 285 continue; 286 287 cp = strip(line); 288 289 switch (*cp) { 290 case '\0': /* empty/comment */ 291 break; 292 293 case '!': 294 switch (DecodeCtrlCommand(cp+1, arg)) { 295 case CTRL_INCLUDE: 296 log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg); 297 n = ReadSystem(bundle, name, arg, prompt, cx, how); 298 log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg); 299 if (!n) 300 return 0; /* got it */ 301 break; 302 default: 303 log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp); 304 break; 305 } 306 break; 307 308 default: 309 wp = strchr(cp, ':'); 310 if (wp == NULL || wp[1] != '\0') { 311 log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n", 312 filename, linenum); 313 continue; 314 } 315 *wp = '\0'; 316 cp = strip(cp); /* lose any spaces between the label and the ':' */ 317 318 if (strcmp(cp, name) == 0) { 319 /* We're in business */ 320 if (how == SYSTEM_EXISTS) 321 return 0; 322 while ((n = xgets(line, sizeof line, fp))) { 323 linenum += n; 324 indent = issep(*line); 325 cp = strip(line); 326 327 if (*cp == '\0') /* empty / comment */ 328 continue; 329 330 if (!indent) { /* start of next section */ 331 wp = strchr(cp, ':'); 332 if ((how == SYSTEM_EXEC) && (wp == NULL || wp[1] != '\0')) 333 log_Printf(LogWARN, "Unindented command (%s line %d) - ignored\n", 334 filename, linenum); 335 break; 336 } 337 338 len = strlen(cp); 339 argc = command_Interpret(cp, len, argv); 340 allowcmd = argc > 0 && !strcasecmp(argv[0], "allow"); 341 if ((!(how == SYSTEM_EXEC) && allowcmd) || 342 ((how == SYSTEM_EXEC) && !allowcmd)) 343 command_Run(bundle, argc, (char const *const *)argv, prompt, 344 name, cx); 345 } 346 347 fclose(fp); /* everything read - get out */ 348 return 0; 349 } 350 break; 351 } 352 } 353 fclose(fp); 354 return -1; 355} 356 357const char * 358system_IsValid(const char *name, struct prompt *prompt, int mode) 359{ 360 /* 361 * Note: The ReadSystem() calls only result in calls to the Allow* 362 * functions. arg->bundle will be set to NULL for these commands ! 363 */ 364 int def, how, rs; 365 366 def = !strcmp(name, "default"); 367 how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE; 368 userok = 0; 369 modeok = 1; 370 modereq = mode; 371 372 rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how); 373 374 if (!def) { 375 if (rs == -1) 376 rs = 0; /* we don't care that ``default'' doesn't exist */ 377 378 if (rs == 0) 379 rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how); 380 381 if (rs == -1) 382 return "Configuration label not found"; 383 384 if (rs == -2) 385 return _PATH_PPP "/" CONFFILE ": File not found"; 386 } 387 388 if (how == SYSTEM_EXISTS) 389 userok = modeok = 1; 390 391 if (!userok) 392 return "User access denied"; 393 394 if (!modeok) 395 return "Mode denied for this label"; 396 397 return NULL; 398} 399 400int 401system_Select(struct bundle *bundle, const char *name, const char *file, 402 struct prompt *prompt, struct datalink *cx) 403{ 404 userok = modeok = 1; 405 modereq = PHYS_ALL; 406 return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC); 407} 408