1: # include <stdio.h> 2: # include <ingres.h> 3: # include <aux.h> 4: # include <version.h> 5: # include <opsys.h> 6: # include <access.h> 7: # include <lock.h> 8: # include <signal.h> 9: # include <sccs.h> 10: # include <setjmp.h> 11: # include <pwd.h> 12: 13: SCCSID(@(#)initucode.c 8.5 2/8/85) 14: 15: /* 16: ** INITUCODE -- initialize standalone process 17: ** 18: ** This function initializes a standalone process, initializing 19: ** a lot of global variables, scanning the argument vector for 20: ** some special flags (-u and +-w), seperating flags and 21: ** parameters, and so forth. 22: ** 23: ** Every standalone program should begin with the lines: 24: ** i = initucode(argc, argv, ...); 25: ** switch (i) 26: ** ... 27: ** 28: ** On a return of 2, 3, or 4, essentially none of the processing 29: ** is done (particularly true with return 4). Virtually nothing 30: ** can be done in the calling program except print a "usage" 31: ** message and exit. The exception to this is that 'Pathname' 32: ** is set, so that it can be used in the error printing. For 33: ** example, ingres.c cats file .../files/usage on this sort of 34: ** error. 35: ** 36: ** If it is preferable to not lock the database at this time, 37: ** the 'waitmode' parameter should be passed as -1. This still 38: ** causes the 'Wait_action' variable to be initialized, but the 39: ** database is not actually locked. It can be locked by calling: 40: ** db_lock(Dbpath, M_EXCL); 41: ** at the proper time. 42: ** 43: ** For the main effects of this routine, see the "Side Effects" 44: ** section below. 45: ** 46: ** Parameters: 47: ** argc -- argc from main. 48: ** argv -- argv from main. 49: ** dbflag -- TRUE -- take the first parameter as the 50: ** database name. 51: ** FALSE -- don't take the first parameter as 52: ** the database name. 53: ** paramlist -- a pointer to an array[4] of pointers 54: ** to character; set to the extra fields of 55: ** the users file entry for the real user 56: ** executing the code (not the user on the 57: ** -u flag). If NULL, this is ignored. 58: ** waitmode -- M_EXCL -- set an exclusive lock on the 59: ** database. 60: ** M_SHARE -- set a shared lock on the database. 61: ** -1 -- don't set a lock on the database. 62: ** However, other stuff (Wait_action) is 63: ** still set up so that the lock can be 64: ** placed later by calling 'db_lock'. 65: ** 66: ** Returns: 67: ** 0 -- everything is ok. 68: ** 1(NODB) -- the database does not exist. 69: ** 2(NOACCESS)-- you are not authorized to access this database. 70: ** 3(INVALIDUSR)-- you are not a valid INGRES user. 71: ** 4(NODBNAME)-- no database name was specified (only if dbflag 72: ** == TRUE). 73: ** 5(INDIRECT)-- everything is ok, but there was an indirect 74: ** taken. 75: ** 6(INDNODB)-- there was an indirect taken, but there was no 76: ** database there. 77: ** 78: ** If dbflag == FALSE, you can only get returns 0 and 79: ** 3. 80: ** 81: ** Side Effects: 82: ** A lot of variables are set, as follows: 83: ** 84: ** Dbpath -- set to the pathname of the database (only 85: ** if dbflag == TRUE). It is set even if the 86: ** database does not exist. 87: ** Parmvect -- set to the parameters from argv, that is, 88: ** anything not beginning with '+' or '-'. 89: ** Flagvect -- set to the flags from argv, that is, 90: ** everything beginning with '+' or '-'. The 91: ** flags '+w', '-w', and '-u' are stripped out, 92: ** however. 93: ** Wait_action -- set to the appropriate action (A_SLP 94: ** or A_RTN) based on the +-w flags and whether 95: ** we are running in background or not. 96: ** This is automatically used by 'db_lock()'. 97: ** Usercode -- set to the persons effective user code 98: ** (that is, after the -u processing). Only 99: ** the INGRES user or the DBA can use the -u 100: ** flag. 101: ** Pathname -- set to the pathname of the INGRES subtree. 102: ** Status -- an integer set to the user status field 103: ** of the users file for the real user. 104: ** Ing_uid -- set to the user id of the INGRES user. 105: ** 106: ** The rubout signal (signal 2) is caught, and refered 107: ** to the standard rubout processor (see rub.c); thus, 108: ** a routine called 'rubproc' must be defined in the 109: ** standalone code (which will just call exit, in the 110: ** normal case). 111: ** 112: ** The 'adminhdr' part of the 'Admin' struct is filled 113: ** in. This is not done with readadmin() and is not 114: ** equivalent to an 'admininit()', but it does make 115: ** the DBA and database status available. 116: ** 117: ** This routine can also exit immediately with an 118: ** error message. 119: ** 120: ** Defined Constants: 121: ** MAXPARGS -- the maximum number of parameter type 122: ** arguments to any standalone program. 123: ** MAXFARGS -- the maximum number of flag type arg- 124: ** uments to any standalong program (not inclu- 125: ** ding flags in the users file, and the +-w 126: ** and -u flags). 127: ** 128: ** Files: 129: ** /etc/passwd -- to get the pathname for user "ingres". 130: ** .../files/users -- to get all the per-user information, 131: ** and to process the -u flag. 132: ** 133: ** Compilation Flags: 134: ** xB_UNIX, xV6_UNIX -- see comments in aux.h 135: ** 136: ** Trace Flags: 137: ** none 138: */ 139: 140: 141: # define MAXFARGS 15 /* maximum flag-type arguments */ 142: # define MAXPARGS 20 /* maximum parameter-type args */ 143: 144: char *Usercode; /* the usercode of the effective user */ 145: char *Pathname; /* path of INGRES subtree */ 146: int Status; /* the user status of the real user */ 147: int Rubignored; /* set if rubouts ignored */ 148: /* (also in initproc for system processes) */ 149: int Wait_action; /* the action on the db_lock */ 150: char *Dbpath; /* the pathname of the database */ 151: char *Flagvect[MAXFARGS+1]; /* the flags from argv */ 152: char *Parmvect[MAXPARGS+1]; /* the parameters from argv */ 153: int Ing_uid; /* the user id of the INGRES user */ 154: jmp_buf Initbuf; /* Buffer to go back to initucode with */ 155: 156: initucode(argc, argv, dbflag, paramlist, waitmode) 157: int argc; 158: char **argv; 159: int dbflag; 160: char *paramlist[4]; 161: int waitmode; 162: { 163: register char *p; 164: char *q; 165: char c; 166: FILE *iop; 167: static char sbuf[MAXLINE * 2]; 168: register char *sbufp; 169: char buf[MAXLINE+1]; 170: register int i; 171: int npermit; 172: int rtval; 173: char *field[UF_NFIELDS]; 174: int actualuid; 175: auto int uid; 176: auto int gid; 177: int waitflag; 178: char *userflag; 179: struct sgttyb gttydummy; 180: int fvi, pvi; 181: char **avp; 182: char usr_ovrd[3]; 183: extern rubcatch(); 184: static short tvect[100]; 185: bool nobuffer; 186: struct passwd *pwd; 187: struct passwd *getpwnam(); 188: # ifdef xV7_UNIX 189: extern char *getenv(); 190: # endif xV7_UNIX 191: 192: /* 193: ** Set up interrupts. 194: */ 195: 196: if ( setjmp(Initbuf) ) 197: exit(-1); 198: if (signal(SIGINT, SIG_IGN) == SIG_DFL) 199: signal(SIGINT, rubcatch); 200: # ifdef xV6_UNIX 201: for (avp = argv; *avp != 0 && *avp != (char *) -1; avp++) 202: continue; 203: *avp = NULL; 204: # endif 205: 206: /* 207: ** Do basic initialization, such as setting trace flags. 208: */ 209: 210: nobuffer = tTrace(argv, 'T', tvect, 100); 211: if (!nobuffer) 212: set_so_buf(); 213: sbufp = sbuf; 214: 215: /* 216: ** Get pathname of INGRES subtree from /etc/passwd file 217: ** entry for USERINGRES (presumably "ingres") and save it 218: ** in 'Pathname'. 219: ** 220: ** This algorithm suggested by Jim Popa. 221: */ 222: 223: if ( (pwd = getpwnam(USERINGRES)) == NULL ) 224: syserr("initucode: No user %s in password file",USERINGRES); 225: # ifdef xV7_UNIX 226: Pathname = getenv("INGPATH"); 227: if (Pathname == NULL) 228: { 229: # endif xV7_UNIX 230: Pathname = sbufp; 231: sbufp += smove(pwd->pw_dir, sbufp) + 1; 232: # ifdef PATHEXT 233: sbufp += smove(PATHEXT, sbufp - 1); 234: # endif PATHEXT 235: # ifdef xV7_UNIX 236: } 237: # endif xV7_UNIX 238: 239: /* create the INGRES user id */ 240: Ing_uid = pwd->pw_uid; 241: # ifdef xV6_UNIX 242: Ing_uid &= I1MASK; 243: # endif 244: # ifdef xB_UNIX 245: gid = pwd->pw_gid; 246: Ing_uid = (Ing_uid & I1MASK) | ((gid & I1MASK) << 8); 247: # endif 248: endpwent(); 249: 250: /* 251: ** Scan the argument vector. The following flags are pulled 252: ** out of the vector (and argc and argv are adjusted so it 253: ** looks like they never existed): 254: ** +w, -w -- (don't) wait for the database to be free. 255: ** -uxxx -- run as user xxx. If first character is a 256: ** colon, the format must be '-u:xx' where 'xx' is the 257: ** internal user code. 258: */ 259: 260: avp = argv; 261: fvi = 0; 262: pvi = 0; 263: waitflag = 0; 264: userflag = NULL; 265: usr_ovrd[0] = 0; 266: 267: for (i = argc; --i > 0; ) 268: { 269: p = *++avp; 270: if (p[0] == '+') 271: { 272: if (p[1] == 'w') 273: waitflag = 1; 274: else 275: goto boring; 276: } 277: else if (p[0] == '-') 278: { 279: switch (p[1]) 280: { 281: case 'w': 282: waitflag = -1; 283: break; 284: 285: case 'u': 286: if (p[2] == ':') 287: { 288: if (p[3] == 0 || p[4] == 0 || p[5] != 0) 289: { 290: printf("Bad flag %s\n", p); 291: exit(-1); 292: } 293: smove(&p[3], usr_ovrd); 294: } 295: else 296: userflag = &p[2]; 297: break; 298: 299: default: 300: /* not an interesting flag */ 301: boring: 302: if (fvi >= MAXFARGS) 303: { 304: printf("Too many flags\n"); 305: exit(-1); 306: } 307: Flagvect[fvi++] = p; 308: break; 309: } 310: } 311: else 312: { 313: /* not a flag: save in Parmvect */ 314: if (pvi >= MAXPARGS) 315: { 316: printf("Too many parmameters\n"); 317: exit(-1); 318: } 319: Parmvect[pvi++] = p; 320: } 321: } 322: 323: if (pvi <= 0 && dbflag) 324: { 325: return (NODBNAME); /* no database name specified */ 326: } 327: 328: /* 329: ** Scan the "users" file. 330: */ 331: 332: if ((iop = fopen(ztack(Pathname, "/files/users"), "r")) == NULL) 333: syserr("initucode: open error"); 334: 335: /* get uid (out of loop) for test */ 336: # ifdef xV6_UNIX 337: actualuid = getuid() & I1MASK; 338: # endif 339: # ifndef xV6_UNIX 340: actualuid = getuid(); 341: # endif 342: 343: /* scan users file, one line at a time */ 344: rtval = INVALIDUSR; 345: while ((Usercode == NULL || userflag != NULL) && fgets(buf, MAXLINE, iop) != NULL) 346: { 347: 348: /* decode users file entry */ 349: i = 0; 350: field[0] = buf; 351: for (p = buf; *p != '\n' && *p != '\0'; p++) 352: { 353: if (*p == ':') 354: { 355: *p = 0; 356: i++; 357: field[i] = p + 1; 358: } 359: } 360: *p = '\0'; 361: 362: /* check for correct number of fields */ 363: if (i != UF_NFIELDS - 1) 364: syserr("initucode: users fmt %s", buf); 365: 366: /* 367: ** Check to see if this entry is the override user. 368: ** If so, save his user code in usr_ovrd. 369: */ 370: 371: if (userflag != NULL && sequal(userflag, field[UF_NAME])) 372: { 373: smove(field[UF_UCODE], usr_ovrd); 374: userflag = NULL; 375: } 376: 377: /* don't bother with this shit if not needed */ 378: if (Usercode != NULL) 379: continue; 380: 381: /* 382: ** Build the user id of this entry into 'uid' 383: ** and see if it is this user. 384: */ 385: 386: uid = atoi(field[UF_UID]); 387: 388: # ifdef xB_UNIX 389: gid = atoi(field[UF_GID]); 390: uid = (uid & I1MASK) | ((gid & I1MASK) << 8); 391: # endif 392: 393: # ifdef xV6_UNIX 394: if ((uid & I1MASK) != actualuid) 395: continue; 396: # endif 397: # ifndef xV6_UNIX 398: if (uid != actualuid) 399: continue; 400: # endif 401: 402: /* 403: ** We now have the real user entry. 404: ** Fetch the usercode, the status bits, and other 405: ** fields from the users file, and save them in 406: ** a safe place (sbuf). 407: */ 408: 409: Usercode = sbufp; 410: sbufp += smove(field[UF_UCODE], sbufp) + 1; 411: Status = oatoi(field[UF_STAT]); 412: if (paramlist != NULL) 413: { 414: for (i = 0; i < 4; i++) 415: { 416: paramlist[i] = sbufp; 417: sbufp += smove(field[UF_FLAGS + i], sbufp) + 1; 418: } 419: } 420: 421: /* validate access permission */ 422: rtval = 0; 423: if (!dbflag || (Status & U_SUPER) != 0) 424: continue; 425: p = field[UF_DBLIST]; 426: if (*p == 0) 427: continue; 428: 429: /* select permission/no-permission */ 430: npermit = 0; 431: if (*p == '-') 432: { 433: p++; 434: npermit++; 435: } 436: 437: /* scan for database listed */ 438: if (!npermit) 439: rtval = NOACCESS; 440: for (c = *p; c != 0; p = q + 1) 441: { 442: for (q = p; *q != ',' && *q != 0; q++) 443: continue; 444: c = *q; 445: *q = 0; 446: if (sequal(Parmvect[0], p)) 447: { 448: rtval = npermit ? NOACCESS : 0; 449: break; 450: } 451: } 452: } 453: fclose(iop); 454: 455: if (rtval != 0) 456: return (rtval); 457: 458: /* 459: ** Check for existance of the database. This is done by 460: ** first building the pathname of the database into 461: ** 'Dbpath', and then reading the admin file (just 462: ** the adhdr part). 463: */ 464: 465: if (dbflag) 466: { 467: Dbpath = sbufp; 468: switch (i = initdbpath(Parmvect[0], Dbpath, TRUE)) 469: { 470: case DBEXIST: 471: rtval = 0; 472: break; 473: 474: case PTR2DB: 475: rtval = INDIRECT; 476: break; 477: 478: case NODBS: 479: rtval = NODB; 480: break; 481: 482: case PTR2NODBS: 483: rtval = INDNODB; 484: break; 485: 486: default: 487: syserr("initucode: initdbpath %d", i); 488: } 489: sbufp += length(Dbpath) + 1; 490: 491: if (rtval == 0 || rtval == INDIRECT) 492: { 493: i = open(ztack(Dbpath, "/admin"), O_RDONLY); 494: if (i < 0) 495: rtval += 1; 496: else 497: { 498: /* open and check admin file */ 499: checkadmin(i); 500: close(i); 501: } 502: } 503: } 504: 505: /* 506: ** Check to see if the name on the -u flag is valid, and 507: ** that this user is allowed to use it. 508: */ 509: 510: if (userflag != NULL) 511: { 512: printf("Invalid user name %s\n", userflag); 513: exit(-1); 514: } 515: if (usr_ovrd[0] != '\0') 516: { 517: if ((Status & U_SUPER) == 0) 518: { 519: if (!dbflag || !bequal(Admin.adhdr.adowner, Usercode, UCODE_SZ)) 520: { 521: printf("You may not use the -u flag\n"); 522: exit(-1); 523: } 524: } 525: bmove(usr_ovrd, Usercode, UCODE_SZ); 526: } 527: 528: /* 529: ** Process the +-w flag. 530: ** First, determine the locking mode. If +w, always 531: ** wait; if -w, never wait; if unspecified, wait if in 532: ** background, but print error and exit if running 533: ** interactive. 534: */ 535: 536: if (waitflag > 0 || (waitflag == 0 && gtty(0, >tydummy) < 0)) 537: Wait_action = A_SLP; 538: else 539: Wait_action = A_RTN; 540: if (dbflag && waitmode >= 0) 541: db_lock(waitmode); 542: 543: /* 544: ** Return authorization value. 545: */ 546: 547: return (rtval); 548: } 549: /* 550: ** DB_LOCK -- lock database 551: ** 552: ** Locks the database. Everyone should do this before using any 553: ** database. 554: ** 555: ** Parameters: 556: ** database -- the pathname of the database. 557: ** mode -- M_EXCL -- get an exclusive lock. 558: ** M_SHARE -- get a shared lock. 559: ** 560: ** Returns: 561: ** none 562: ** 563: ** Side Effects: 564: ** Alockdes is opened. 565: */ 566: 567: struct lockreq Lock; /* the database lock structure */ 568: 569: db_lock(mode) 570: int mode; 571: { 572: if ((Admin.adhdr.adflags & A_DBCONCUR) == 0) 573: return; 574: if (Alockdes < 0) 575: Alockdes = start_up_lock_driver(); 576: if (setdbl(Wait_action, mode) < 0) 577: { 578: printf("Database temporarily unavailable\n"); 579: exit(1); 580: } 581: } 582: /* 583: ** INITDBPATH -- initialize the pathname of the database 584: ** 585: ** The pathname of a specified database is created. Indirection 586: ** via a file is supported, so that if the pathname is a file, 587: ** the first line of the file is read and used as the pathname 588: ** of the real database. 589: ** 590: ** Parameters: 591: ** database -- the name of the database. If NULL, 592: ** the pathname of datadir is returned. 593: ** dbbuf -- a buffer into which the pathname should 594: ** be dumped. 595: ** follow -- if set, follow the indirect chain of 596: ** database pathnames. 597: ** 598: ** Returns: 599: ** 0(DBEXIST)-- database exists in datadir 600: ** 1(PTR2DB)-- database exists, but I followed a pointer. 601: ** 2(NODBS)-- database doesn't exist in datadir. 602: ** 3(PRT2NODBS)-- database doesn't exist, but I followed a pointer. 603: ** 604: ** Side Effects: 605: ** none. 606: */ 607: 608: initdbpath(database, dbpath, follow) 609: char *database; 610: char *dbpath; 611: int follow; 612: { 613: struct stat ibuf; 614: register char *d; 615: register FILE *f; 616: register int phase; 617: int retval; 618: int uid; 619: extern char *index(); 620: 621: d = dbpath; 622: 623: if (database == NULL) 624: { 625: # ifndef xDBPATH 626: concat(Pathname, "/data/base/", d); 627: # else 628: smove(xDBPATH, d); 629: # endif 630: return (DBEXIST); 631: } 632: 633: /* get the basic pathname */ 634: concat(ztack(Pathname, "/datadir/"), database, d); 635: 636: /* 637: ** Iterate looking for database. 638: ** "Phase" is what we are trying: 639: ** -1 -- looking in datadir 640: ** 0 -- looking in data/base 641: ** 1 -- following indirect. 642: */ 643: 644: retval = NODBS; 645: for (phase = -1;;) 646: { 647: /* find out what sort of filesystem node this is */ 648: if (stat(d, &ibuf) < 0) 649: { 650: if (phase < 0) 651: { 652: # ifdef xDBPATH 653: concat(xDBPATH, database, d); 654: # else 655: concat(ztack(Pathname, "/data/base/"), database, d); 656: # endif 657: phase = 0; 658: continue; 659: } 660: else 661: return (retval); 662: } 663: 664: /* set up the lock structure for future use */ 665: bmove(&ibuf, Lock.dbnode, 4); 666: 667: retval -= 2; 668: if ((ibuf.st_mode & S_IFMT) == S_IFDIR) 669: return (retval); 670: 671: /* if second time through, the database must be a directory */ 672: if (phase > 0) 673: syserr("initdbpath: not direc"); 674: 675: /* if we shouldn't follow the chain, say it exists */ 676: if (!follow) 677: return (PTR2NODBS); 678: 679: /* it's a file -- see if we can use it */ 680: uid = ibuf.st_uid; 681: # ifdef xB_UNIX 682: uid = (uid & I1MASK) | ((ibuf.st_gid & I1MASK) << 8); 683: # endif 684: # ifdef xV6_UNIX 685: uid &= I1MASK; 686: # endif 687: if (uid != Ing_uid || (ibuf.st_mode & 0777) != 0600) 688: return (PTR2NODBS); 689: 690: f = fopen(d, "r"); 691: if (f == NULL) 692: syserr("initdbpath: fopen"); 693: 694: /* read the pathname of the database */ 695: if (fgets(d, MAXLINE, f) == NULL || d[0] != '/') 696: syserr("initdbpath: bad indirect"); 697: *index(d, '\n') = '\0'; 698: fclose(f); 699: 700: /* prepare for next iteration */ 701: retval = 3; 702: phase = 1; 703: } 704: }