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.39 1998/10/17 12:28:03 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 41 FILE * 42 OpenSecret(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 54 void 55 CloseSecret(FILE * fp) 56 { 57 fclose(fp); 58 } 59 60 /* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */ 61 static void 62 InterpretArg(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 149 static int 150 DecodeCtrlCommand(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 */ 163 static int modeok; 164 static int userok; 165 static int modereq; 166 167 int 168 AllowUsers(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 186 int 187 AllowModes(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 205 static char * 206 strip(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 224 static int 225 xgets(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 static int 248 ReadSystem(struct bundle *bundle, const char *name, const char *file, 249 int doexec, struct prompt *prompt, struct datalink *cx) 250 { 251 FILE *fp; 252 char *cp, *wp; 253 int n, len; 254 char line[LINE_LEN]; 255 char filename[MAXPATHLEN]; 256 int linenum; 257 int argc; 258 char *argv[MAXARGS]; 259 int allowcmd; 260 int indent; 261 char arg[LINE_LEN]; 262 263 if (*file == '/') 264 snprintf(filename, sizeof filename, "%s", file); 265 else 266 snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file); 267 fp = ID0fopen(filename, "r"); 268 if (fp == NULL) { 269 log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename); 270 return (-1); 271 } 272 log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); 273 274 linenum = 0; 275 while ((n = xgets(line, sizeof line, fp))) { 276 linenum += n; 277 if (issep(*line)) 278 continue; 279 280 cp = strip(line); 281 282 switch (*cp) { 283 case '\0': /* empty/comment */ 284 break; 285 286 case '!': 287 switch (DecodeCtrlCommand(cp+1, arg)) { 288 case CTRL_INCLUDE: 289 log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg); 290 n = ReadSystem(bundle, name, arg, doexec, prompt, cx); 291 log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg); 292 if (!n) 293 return 0; /* got it */ 294 break; 295 default: 296 log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp); 297 break; 298 } 299 break; 300 301 default: 302 wp = strchr(cp, ':'); 303 if (wp == NULL || wp[1] != '\0') { 304 log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n", 305 filename, linenum); 306 continue; 307 } 308 *wp = '\0'; 309 cp = strip(cp); /* lose any spaces between the label and the ':' */ 310 311 if (strcmp(cp, name) == 0) { 312 /* We're in business */ 313 while ((n = xgets(line, sizeof line, fp))) { 314 linenum += n; 315 indent = issep(*line); 316 cp = strip(line); 317 318 if (*cp == '\0') /* empty / comment */ 319 continue; 320 321 if (!indent) { /* start of next section */ 322 wp = strchr(cp, ':'); 323 if (doexec && (wp == NULL || wp[1] != '\0')) 324 log_Printf(LogWARN, "Unindented command (%s line %d) - ignored\n", 325 filename, linenum); 326 break; 327 } 328 329 len = strlen(cp); 330 argc = command_Interpret(cp, len, argv); 331 allowcmd = argc > 0 && !strcasecmp(argv[0], "allow"); 332 if ((!doexec && allowcmd) || (doexec && !allowcmd)) 333 command_Run(bundle, argc, (char const *const *)argv, prompt, 334 name, cx); 335 } 336 337 fclose(fp); /* everything read - get out */ 338 return 0; 339 } 340 break; 341 } 342 } 343 fclose(fp); 344 return -1; 345 } 346 347 const char * 348 system_IsValid(const char *name, struct prompt *prompt, int mode) 349 { 350 /* 351 * Note: The ReadSystem() calls only result in calls to the Allow* 352 * functions. arg->bundle will be set to NULL for these commands ! 353 */ 354 int def; 355 356 if (ID0realuid() == 0) { 357 userok = modeok = 1; 358 return NULL; 359 } 360 361 def = !strcmp(name, "default"); 362 userok = 0; 363 modeok = 1; 364 modereq = mode; 365 366 if (ReadSystem(NULL, "default", CONFFILE, 0, prompt, NULL) != 0 && def) 367 return "System not found"; 368 369 if (!def && ReadSystem(NULL, name, CONFFILE, 0, prompt, NULL) != 0) 370 return "System not found"; 371 372 if (!userok) 373 return "Invalid user id"; 374 375 if (!modeok) 376 return "Invalid mode"; 377 378 return NULL; 379 } 380 381 int 382 system_Select(struct bundle *bundle, const char *name, const char *file, 383 struct prompt *prompt, struct datalink *cx) 384 { 385 userok = modeok = 1; 386 modereq = PHYS_ALL; 387 return ReadSystem(bundle, name, file, 1, prompt, cx); 388 } 389