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.37 1998/06/15 19:05:47 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 /* Initialised in system_IsValid(), set in ReadSystem(), used by system_IsValid() */ 160 static int modeok; 161 static int userok; 162 static int modereq; 163 164 int 165 AllowUsers(struct cmdargs const *arg) 166 { 167 /* arg->bundle may be NULL (see system_IsValid()) ! */ 168 int f; 169 char *user; 170 171 userok = 0; 172 user = getlogin(); 173 if (user && *user) 174 for (f = arg->argn; f < arg->argc; f++) 175 if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) { 176 userok = 1; 177 break; 178 } 179 180 return 0; 181 } 182 183 int 184 AllowModes(struct cmdargs const *arg) 185 { 186 /* arg->bundle may be NULL (see system_IsValid()) ! */ 187 int f, mode, allowed; 188 189 allowed = 0; 190 for (f = arg->argn; f < arg->argc; f++) { 191 mode = Nam2mode(arg->argv[f]); 192 if (mode == PHYS_NONE || mode == PHYS_ALL) 193 log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]); 194 else 195 allowed |= mode; 196 } 197 198 modeok = modereq & allowed ? 1 : 0; 199 return 0; 200 } 201 202 static char * 203 strip(char *line) 204 { 205 int len; 206 207 len = strlen(line); 208 while (len && (line[len-1] == '\n' || line[len-1] == '\r' || 209 issep(line[len-1]))) 210 line[--len] = '\0'; 211 212 while (issep(*line)) 213 line++; 214 215 if (*line == '#') 216 *line = '\0'; 217 218 return line; 219 } 220 221 static int 222 xgets(char *buf, int buflen, FILE *fp) 223 { 224 int len, n; 225 226 n = 0; 227 while (fgets(buf, buflen-1, fp)) { 228 n++; 229 buf[buflen-1] = '\0'; 230 len = strlen(buf); 231 while (len && (buf[len-1] == '\n' || buf[len-1] == '\r')) 232 buf[--len] = '\0'; 233 if (len && buf[len-1] == '\\') { 234 buf += len - 1; 235 buflen -= len - 1; 236 if (!buflen) /* No buffer space */ 237 break; 238 } else 239 break; 240 } 241 return n; 242 } 243 244 static int 245 ReadSystem(struct bundle *bundle, const char *name, const char *file, 246 int doexec, struct prompt *prompt, struct datalink *cx) 247 { 248 FILE *fp; 249 char *cp, *wp; 250 int n, len; 251 char line[LINE_LEN]; 252 char filename[MAXPATHLEN]; 253 int linenum; 254 int argc; 255 char *argv[MAXARGS]; 256 int allowcmd; 257 int indent; 258 char arg[LINE_LEN]; 259 260 if (*file == '/') 261 snprintf(filename, sizeof filename, "%s", file); 262 else 263 snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file); 264 fp = ID0fopen(filename, "r"); 265 if (fp == NULL) { 266 log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename); 267 return (-1); 268 } 269 log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); 270 271 linenum = 0; 272 while ((n = xgets(line, sizeof line, fp))) { 273 linenum += n; 274 if (issep(*line)) 275 continue; 276 277 cp = strip(line); 278 279 switch (*cp) { 280 case '\0': /* empty/comment */ 281 break; 282 283 case '!': 284 switch (DecodeCtrlCommand(cp+1, arg)) { 285 case CTRL_INCLUDE: 286 log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg); 287 n = ReadSystem(bundle, name, arg, doexec, prompt, cx); 288 log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg); 289 if (!n) 290 return 0; /* got it */ 291 break; 292 default: 293 log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp); 294 break; 295 } 296 break; 297 298 default: 299 wp = strchr(cp, ':'); 300 if (wp == NULL || wp[1] != '\0') { 301 log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n", 302 filename, linenum); 303 continue; 304 } 305 *wp = '\0'; 306 cp = strip(cp); /* lose any spaces between the label and the ':' */ 307 308 if (strcmp(cp, name) == 0) { 309 /* We're in business */ 310 while ((n = xgets(line, sizeof line, fp))) { 311 linenum += n; 312 indent = issep(*line); 313 cp = strip(line); 314 315 if (*cp == '\0') /* empty / comment */ 316 continue; 317 318 if (!indent) /* start of next section */ 319 break; 320 321 len = strlen(cp); 322 argc = command_Interpret(cp, len, argv); 323 allowcmd = argc > 0 && !strcasecmp(argv[0], "allow"); 324 if ((!doexec && allowcmd) || (doexec && !allowcmd)) 325 command_Run(bundle, argc, (char const *const *)argv, prompt, 326 name, cx); 327 } 328 329 fclose(fp); /* everything read - get out */ 330 return 0; 331 } 332 break; 333 } 334 } 335 fclose(fp); 336 return -1; 337 } 338 339 int 340 system_IsValid(const char *name, struct prompt *prompt, int mode) 341 { 342 /* 343 * Note: The ReadSystem() calls only result in calls to the Allow* 344 * functions. arg->bundle will be set to NULL for these commands ! 345 */ 346 if (ID0realuid() == 0) 347 return userok = modeok = 1; 348 userok = 0; 349 modeok = 1; 350 modereq = mode; 351 ReadSystem(NULL, "default", CONFFILE, 0, prompt, NULL); 352 if (name != NULL) 353 ReadSystem(NULL, name, CONFFILE, 0, prompt, NULL); 354 return userok && modeok; 355 } 356 357 int 358 system_Select(struct bundle *bundle, const char *name, const char *file, 359 struct prompt *prompt, struct datalink *cx) 360 { 361 userok = modeok = 1; 362 modereq = PHYS_ALL; 363 return ReadSystem(bundle, name, file, 1, prompt, cx); 364 } 365