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.35.2.4 1998/04/03 19:25:58 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 "command.h" 34 #include "log.h" 35 #include "id.h" 36 #include "defs.h" 37 #include "pathnames.h" 38 #include "systems.h" 39 40 #define issep(ch) ((ch) == ' ' || (ch) == '\t') 41 42 FILE * 43 OpenSecret(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 LogPrintf(LogWARN, "OpenSecret: Can't open %s.\n", line); 52 return (fp); 53 } 54 55 void 56 CloseSecret(FILE * fp) 57 { 58 fclose(fp); 59 } 60 61 /* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */ 62 static void 63 InterpretArg(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 150 static int 151 DecodeCtrlCommand(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 static int userok; 161 162 int 163 AllowUsers(struct cmdargs const *arg) 164 { 165 /* arg->bundle may be NULL (see ValidSystem()) ! */ 166 int f; 167 char *user; 168 169 userok = 0; 170 user = getlogin(); 171 if (user && *user) 172 for (f = 0; f < arg->argc; f++) 173 if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) { 174 userok = 1; 175 break; 176 } 177 178 return 0; 179 } 180 181 static struct { 182 int mode; 183 const char *name; 184 } modes[] = { 185 { MODE_INTER, "interactive" }, 186 { MODE_AUTO, "auto" }, 187 { MODE_DIRECT, "direct" }, 188 { MODE_DEDICATED, "dedicated" }, 189 { MODE_DDIAL, "ddial" }, 190 { MODE_BACKGROUND, "background" }, 191 { ~0, "*" }, 192 { 0, 0 } 193 }; 194 195 static int modeok; 196 197 int 198 AllowModes(struct cmdargs const *arg) 199 { 200 /* arg->bundle may be NULL (see ValidSystem()) ! */ 201 int f; 202 int m; 203 int allowed; 204 205 allowed = 0; 206 for (f = 0; f < arg->argc; f++) { 207 for (m = 0; modes[m].mode; m++) 208 if (!strcasecmp(modes[m].name, arg->argv[f])) { 209 allowed |= modes[m].mode; 210 break; 211 } 212 if (modes[m].mode == 0) 213 LogPrintf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]); 214 } 215 216 modeok = (mode | allowed) == allowed ? 1 : 0; 217 return 0; 218 } 219 220 static char * 221 strip(char *line) 222 { 223 int len; 224 225 len = strlen(line); 226 while (len && (line[len-1] == '\n' || line[len-1] == '\r' || 227 issep(line[len-1]))) 228 line[--len] = '\0'; 229 230 while (issep(*line)) 231 line++; 232 233 if (*line == '#') 234 *line = '\0'; 235 236 return line; 237 } 238 239 static int 240 xgets(char *buf, int buflen, FILE *fp) 241 { 242 int len, n; 243 244 n = 0; 245 while (fgets(buf, buflen-1, fp)) { 246 n++; 247 buf[buflen-1] = '\0'; 248 len = strlen(buf); 249 while (len && (buf[len-1] == '\n' || buf[len-1] == '\r')) 250 buf[--len] = '\0'; 251 if (len && buf[len-1] == '\\') { 252 buf += len - 1; 253 buflen -= len - 1; 254 if (!buflen) /* No buffer space */ 255 break; 256 } else 257 break; 258 } 259 return n; 260 } 261 262 static int 263 ReadSystem(struct bundle *bundle, const char *name, const char *file, 264 int doexec, struct prompt *prompt) 265 { 266 FILE *fp; 267 char *cp, *wp; 268 int n, len; 269 char line[LINE_LEN]; 270 char filename[MAXPATHLEN]; 271 int linenum; 272 int argc; 273 char **argv; 274 int allowcmd; 275 int indent; 276 char arg[LINE_LEN]; 277 278 if (*file == '/') 279 snprintf(filename, sizeof filename, "%s", file); 280 else 281 snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file); 282 fp = ID0fopen(filename, "r"); 283 if (fp == NULL) { 284 LogPrintf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename); 285 return (-1); 286 } 287 LogPrintf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); 288 289 linenum = 0; 290 while ((n = xgets(line, sizeof line, fp))) { 291 linenum += n; 292 if (issep(*line)) 293 continue; 294 295 cp = strip(line); 296 297 switch (*cp) { 298 case '\0': /* empty/comment */ 299 break; 300 301 case '!': 302 switch (DecodeCtrlCommand(cp+1, arg)) { 303 case CTRL_INCLUDE: 304 LogPrintf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg); 305 n = ReadSystem(bundle, name, arg, doexec, prompt); 306 LogPrintf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg); 307 if (!n) 308 return 0; /* got it */ 309 break; 310 default: 311 LogPrintf(LogWARN, "%s: %s: Invalid command\n", filename, cp); 312 break; 313 } 314 break; 315 316 default: 317 wp = strchr(cp, ':'); 318 if (wp == NULL || wp[1] != '\0') { 319 LogPrintf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n", 320 filename, linenum); 321 continue; 322 } 323 *wp = '\0'; 324 cp = strip(cp); /* lose any spaces between the label and the ':' */ 325 326 if (strcmp(cp, name) == 0) { 327 /* We're in business */ 328 while ((n = xgets(line, sizeof line, fp))) { 329 linenum += n; 330 indent = issep(*line); 331 cp = strip(line); 332 333 if (*cp == '\0') /* empty / comment */ 334 continue; 335 336 if (!indent) /* start of next section */ 337 break; 338 339 len = strlen(cp); 340 InterpretCommand(cp, len, &argc, &argv); 341 allowcmd = argc > 0 && !strcasecmp(*argv, "allow"); 342 if ((!doexec && allowcmd) || (doexec && !allowcmd)) 343 RunCommand(bundle, argc, (char const *const *)argv, prompt, name); 344 } 345 346 fclose(fp); /* everything read - get out */ 347 return 0; 348 } 349 break; 350 } 351 } 352 fclose(fp); 353 return -1; 354 } 355 356 int 357 ValidSystem(const char *name, struct prompt *prompt) 358 { 359 /* 360 * Note: The ReadSystem() calls only result in calls to the Allow* 361 * functions. arg->bundle will be set to NULL for these commands ! 362 */ 363 if (ID0realuid() == 0) 364 return userok = modeok = 1; 365 userok = 0; 366 modeok = 1; 367 ReadSystem(NULL, "default", CONFFILE, 0, prompt); 368 if (name != NULL) 369 ReadSystem(NULL, name, CONFFILE, 0, prompt); 370 return userok && modeok; 371 } 372 373 int 374 SelectSystem(struct bundle *bundle, const char *name, const char *file, 375 struct prompt *prompt) 376 { 377 userok = modeok = 1; 378 return ReadSystem(bundle, name, file, 1, prompt); 379 } 380 381 int 382 LoadCommand(struct cmdargs const *arg) 383 { 384 const char *name; 385 386 if (arg->argc > 0) 387 name = *arg->argv; 388 else 389 name = "default"; 390 391 if (!ValidSystem(name, arg->prompt)) { 392 LogPrintf(LogERROR, "%s: Label not allowed\n", name); 393 return 1; 394 } else if (SelectSystem(arg->bundle, name, CONFFILE, arg->prompt) < 0) { 395 LogPrintf(LogWARN, "%s: label not found.\n", name); 396 return -1; 397 } else 398 SetLabel(arg->argc ? name : NULL); 399 return 0; 400 } 401 402 int 403 SaveCommand(struct cmdargs const *arg) 404 { 405 LogPrintf(LogWARN, "save command is not implemented (yet).\n"); 406 return 1; 407 } 408