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