1: # include <stdio.h> 2: 3: # include "../ingres.h" 4: # include "../aux.h" 5: # include "../unix.h" 6: # include "../access.h" 7: # include "../lock.h" 8: 9: /* 10: ** INITUCODE -- initialize standalone process 11: ** 12: ** This function initializes a standalone process, initializing 13: ** a lot of global variables, scanning the argument vector for 14: ** some special flags (-u and +-w), seperating flags and 15: ** parameters, and so forth. 16: ** 17: ** Every standalone program should begin with the lines: 18: ** # ifdef xTTR1 19: ** tTrace(&argc, argv, 'T'); 20: ** # endif 21: ** i = initucode(argc, argv, ...); 22: ** switch (i) 23: ** ... 24: ** 25: ** On a return of 2, 3, or 4, essentially none of the processing 26: ** is done (particularly true with return 4). Virtually nothing 27: ** can be done in the calling program except print a "usage" 28: ** message and exit. The exception to this is that 'Pathname' 29: ** is set, so that it can be used in the error printing. For 30: ** example, ingres.c cats file .../files/usage on this sort of 31: ** error. 32: ** 33: ** If it is preferable to not lock the database at this time, 34: ** the 'waitmode' parameter should be passed as -1. This still 35: ** causes the 'Wait_action' variable to be initialized, but the 36: ** database is not actually locked. It can be locked by calling: 37: ** db_lock(Dbpath, M_EXCL); 38: ** at the proper time. 39: ** 40: ** For the main effects of this routine, see the "Side Effects" 41: ** section below. 42: ** 43: ** argv[argc] is set to NULL so that it is well known on version 44: ** six or version seven systems. 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 -- the database does not exist. 69: ** 2 -- you are not authorized to access this database. 70: ** 3 -- you are not a valid INGRES user. 71: ** 4 -- no database name was specified (only if dbflag 72: ** == TRUE). 73: ** 5 -- everything is ok, but there was an indirect 74: ** taken. 75: ** 6 -- 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: ** MAXPVECT -- the maximum number of parameter type 122: ** arguments to any standalone program. 123: ** MAXFVECT -- 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: ** Defines: 129: ** initucode 130: ** db_lock -- to lock the database. 131: ** initdbpath -- to initialize the database pathname. 132: ** Parmvect[] 133: ** Flagvect[] 134: ** Usercode 135: ** Wait_action 136: ** Dbpath 137: ** Status -- the user status. 138: ** Lock 139: ** Ing_uid 140: ** Standalone -- '1' to indicate running standalone. 141: ** 142: ** Requires: 143: ** getpw -- to determine the Pathname entry. 144: ** Admin 145: ** 146: ** Called By: 147: ** All standalone routines. 148: ** 149: ** Files: 150: ** /etc/passwd -- to get the pathname for user "ingres". 151: ** .../files/users -- to get all the per-user information, 152: ** and to process the -u flag. 153: ** 154: ** Compilation Flags: 155: ** xB_UNIX, xV6_UNIX -- see comments in aux.h 156: ** 157: ** Trace Flags: 158: ** none 159: ** 160: ** Diagnostics: 161: ** Bad flag %s 162: ** The -u flag was incorrect. 163: ** Too many parameters 164: ** More than MAXPVECT parameters were specified. 165: ** Too many flags 166: ** More than MAXFVECT flags were specified. 167: ** Invalid user name %s 168: ** The name on the -u flag is not known to INGRES. 169: ** You may not use the -u flag 170: ** You are not INGRES or the DBA. If there is 171: ** no known database name, it means you are not 172: ** INGRES. 173: ** Database temporarily unavailable 174: ** Someone else is using the database in exclusive 175: ** mode, or you want it in exclusive mode and 176: ** someone else is using it. 177: ** 178: ** History: 179: ** 8/15/79 (eric) (6.2/7) -- set argv[argc] = NULL. 180: ** 6/29/79 (eric) (6.2/6) -- added Standalone. 181: ** 3/14/79 (eric) -- modified 'initdbpath' so that it 182: ** knows about databases being in data/base 183: ** instead of datadir. 184: ** 1/19/79 (eric) -- added 'initdbpath'. 185: ** 1/12/79 (eric) -- heavily modified for 6.2/0. 186: */ 187: 188: 189: # define MAXFVECT 15 190: # define MAXPVECT 20 191: 192: char *Usercode; /* the usercode of the effective user */ 193: int Status; /* the user status of the real user */ 194: int Rubignored; /* set if rubouts ignored */ 195: /* (also in initproc for system processes) */ 196: int Wait_action; /* the action on the db_lock */ 197: char *Dbpath; /* the pathname of the database */ 198: char *Flagvect[MAXFVECT+1]; /* the flags from argv */ 199: char *Parmvect[MAXPVECT+1]; /* the parameters from argv */ 200: int Ing_uid; /* the user id of the INGRES user */ 201: int Standalone; /* this is stand alone code */ 202: 203: initucode(argc, argv, dbflag, paramlist, waitmode) 204: int argc; 205: char **argv; 206: int dbflag; 207: char *paramlist[4]; 208: int waitmode; 209: { 210: register char *p; 211: char *q; 212: char c; 213: FILE *iop; 214: static char sbuf[MAXLINE * 2]; 215: register char *sbufp; 216: char buf[MAXLINE+1]; 217: register int i; 218: int npermit; 219: int rtval; 220: char *field[UF_NFIELDS]; 221: int actualuid; 222: auto int uid; 223: auto int gid; 224: int waitflag; 225: char *userflag; 226: struct sgttyb gttydummy; 227: int fvi, pvi; 228: char **avp; 229: char usr_ovrd[3]; 230: static int reenter; 231: extern rubcatch(); 232: 233: Standalone = TRUE; 234: sbufp = sbuf; 235: argv[argc] = NULL; 236: 237: /* 238: ** Set up interrupts. 239: */ 240: 241: reenter = 0; 242: setexit(); 243: if (reenter++) 244: exit(-1); 245: if (signal(2, 1) == 0) 246: signal(2, rubcatch); 247: 248: /* 249: ** Get pathname of INGRES subtree from /etc/passwd file 250: ** entry for USERINGRES (presumably "ingres") and save it 251: ** in 'Pathname'. 252: ** 253: ** This algorithm suggested by Jim Popa. 254: */ 255: 256: if ((iop = fopen("/etc/passwd", "r")) == NULL) 257: syserr("initucode: passwd"); 258: 259: do 260: { 261: if (fgetline(buf, MAXLINE, iop) == NULL) 262: syserr("initucode: no INGRES"); 263: 264: /* decode passwd entry */ 265: i = 0; 266: for (p = buf; *p != 0; p++) 267: { 268: if (*p == ':') 269: { 270: *p = 0; 271: i++; 272: field[i] = p + 1; 273: } 274: } 275: 276: /* check for enough fields for valid entry */ 277: if (i < 3) 278: syserr("initucode: passwd fmt %s", buf); 279: } while (!sequal(buf, USERINGRES)); 280: 281: /* we now have the INGRES passwd file entry in 'buf' */ 282: fclose(iop); 283: 284: /* copy pathname entry into 'Pathname' variable */ 285: Pathname = sbufp; 286: sbufp += smove(field[i - 1], sbufp) + 1; 287: 288: /* create the INGRES user id */ 289: if (atoi(p = field[2], &Ing_uid) != 0) 290: syserr("initucode: bad Ing_uid %s", p); 291: # ifdef xV6_UNIX 292: Ing_uid &= 0377; 293: # endif 294: # ifdef xB_UNIX 295: if (atoi(p = field[3], &gid) != 0) 296: syserr("initucode: bad Ing_gid %s", p); 297: Ing_uid = (Ing_uid & 0377) | ((gid & 0377) << 8); 298: # endif 299: 300: /* 301: ** Scan the argument vector. The following flags are pulled 302: ** out of the vector (and argc and argv are adjusted so it 303: ** looks like they never existed): 304: ** +w, -w -- (don't) wait for the database to be free. 305: ** -uxxx -- run as user xxx. If first character is a 306: ** colon, the format must be '-u:xx' where 'xx' is the 307: ** internal user code. 308: */ 309: 310: avp = argv; 311: fvi = 0; 312: pvi = 0; 313: waitflag = 0; 314: userflag = NULL; 315: usr_ovrd[0] = 0; 316: 317: for (i = argc; --i > 0; ) 318: { 319: p = *++avp; 320: if (p[0] == '+') 321: { 322: if (p[1] == 'w') 323: waitflag = 1; 324: else 325: goto boring; 326: } 327: else if (p[0] == '-') 328: { 329: switch (p[1]) 330: { 331: case 'w': 332: waitflag = -1; 333: break; 334: 335: case 'u': 336: if (p[2] == ':') 337: { 338: if (p[3] == 0 || p[4] == 0 || p[5] != 0) 339: { 340: printf("Bad flag %s\n", p); 341: exit(-1); 342: } 343: smove(&p[3], usr_ovrd); 344: } 345: else 346: userflag = &p[2]; 347: break; 348: 349: default: 350: /* not an interesting flag */ 351: boring: 352: if (fvi >= MAXFVECT) 353: { 354: printf("Too many flags\n"); 355: exit(-1); 356: } 357: Flagvect[fvi++] = p; 358: break; 359: } 360: } 361: else 362: { 363: /* not a flag: save in Parmvect */ 364: if (pvi >= MAXPVECT) 365: { 366: printf("Too many parmameters\n"); 367: exit(-1); 368: } 369: Parmvect[pvi++] = p; 370: } 371: } 372: 373: if (pvi <= 0 && dbflag) 374: { 375: return (4); /* no database name specified */ 376: } 377: 378: /* 379: ** Scan the "users" file. 380: */ 381: 382: if ((iop = fopen(ztack(Pathname, "/files/users"), "r")) == NULL) 383: syserr("initucode: open error"); 384: 385: /* get uid (out of loop) for test */ 386: # ifdef xV6_UNIX 387: actualuid = getuid() & 0377; 388: # endif 389: # ifndef xV6_UNIX 390: actualuid = getuid(); 391: # endif 392: 393: /* scan users file, one line at a time */ 394: rtval = 3; 395: while ((Usercode == NULL || userflag != NULL) && fgetline(buf, MAXLINE, iop) != NULL) 396: { 397: /* decode users file entry */ 398: i = 0; 399: field[0] = buf; 400: for (p = buf; *p != 0; p++) 401: { 402: if (*p == ':') 403: { 404: *p = 0; 405: i++; 406: field[i] = p + 1; 407: } 408: } 409: 410: /* check for correct number of fields */ 411: if (i != UF_NFIELDS - 1) 412: syserr("initucode: users fmt %s", buf); 413: 414: /* 415: ** Check to see if this entry is the override user. 416: ** If so, save his user code in usr_ovrd. 417: */ 418: 419: if (userflag != NULL && sequal(userflag, field[UF_NAME])) 420: { 421: smove(field[UF_UCODE], usr_ovrd); 422: userflag = NULL; 423: } 424: 425: /* don't bother with this shit if not needed */ 426: if (Usercode != NULL) 427: continue; 428: 429: /* 430: ** Build the user id of this entry into 'uid' 431: ** and see if it is this user. 432: */ 433: 434: if (atoi(p = field[UF_UID], &uid) != 0) 435: syserr("initucode: users: bad UID %s", p); 436: 437: # ifdef xB_UNIX 438: if (atoi(p = field[UF_GID], &gid) != 0) 439: syserr("initucode: users: bad GID %s", p); 440: uid = (uid & 0377) | ((gid & 0377) << 8); 441: # endif 442: 443: # ifdef xV6_UNIX 444: if ((uid & 0377) != actualuid) 445: continue; 446: # endif 447: # ifndef xV6_UNIX 448: if (uid != actualuid) 449: continue; 450: # endif 451: 452: /* 453: ** We now have the real user entry. 454: ** Fetch the usercode, the status bits, and other 455: ** fields from the users file, and save them in 456: ** a safe place (sbuf). 457: */ 458: 459: Usercode = sbufp; 460: sbufp += smove(field[UF_UCODE], sbufp) + 1; 461: Status = oatoi(field[UF_STAT]); 462: if (paramlist != NULL) 463: { 464: for (i = 0; i < 4; i++) 465: { 466: paramlist[i] = sbufp; 467: sbufp += smove(field[UF_FLAGS + i], sbufp) + 1; 468: } 469: } 470: 471: /* validate access permission */ 472: rtval = 0; 473: if (!dbflag || (Status & U_SUPER) != 0) 474: continue; 475: p = field[UF_DBLIST]; 476: if (*p == 0) 477: continue; 478: 479: /* select permission/no-permission */ 480: npermit = 0; 481: if (*p == '-') 482: { 483: p++; 484: npermit++; 485: } 486: 487: /* scan for database listed */ 488: if (!npermit) 489: rtval = 2; 490: for (c = *p; c != 0; p = q + 1) 491: { 492: for (q = p; *q != ',' && *q != 0; q++) 493: continue; 494: c = *q; 495: *q = 0; 496: if (sequal(Parmvect[0], p)) 497: { 498: rtval = npermit ? 2 : 0; 499: break; 500: } 501: } 502: } 503: fclose(iop); 504: 505: if (rtval != 0) 506: return (rtval); 507: 508: /* 509: ** Check for existance of the database. This is done by 510: ** first building the pathname of the database into 511: ** 'Dbpath', and then reading the admin file (just 512: ** the adhdr part). 513: */ 514: 515: if (dbflag) 516: { 517: Dbpath = sbufp; 518: switch (i = initdbpath(Parmvect[0], Dbpath, TRUE)) 519: { 520: case 0: 521: rtval = 0; 522: break; 523: 524: case 1: 525: rtval = 5; 526: break; 527: 528: case 2: 529: rtval = 1; 530: break; 531: 532: case 3: 533: rtval = 6; 534: break; 535: 536: default: 537: syserr("initucode: initdbpath %d", i); 538: } 539: sbufp += length(Dbpath) + 1; 540: 541: if (rtval == 0 || rtval == 5) 542: { 543: i = open(ztack(Dbpath, "/admin"), 0); 544: if (i < 0) 545: rtval += 1; 546: else 547: { 548: read(i, &Admin.adhdr, sizeof Admin.adhdr); 549: close(i); 550: if ((Admin.adhdr.adflags & A_NEWFMT) != 0) 551: syserr("I don't know about new databases"); 552: } 553: } 554: } 555: 556: /* 557: ** Check to see if the name on the -u flag is valid, and 558: ** that this user is allowed to use it. 559: */ 560: 561: if (userflag != NULL) 562: { 563: printf("Invalid user name %s\n", userflag); 564: exit(-1); 565: } 566: if (usr_ovrd[0] != '\0') 567: { 568: if ((Status & U_SUPER) == 0) 569: { 570: if (!dbflag || !bequal(Admin.adhdr.adowner, Usercode, 2)) 571: { 572: printf("You may not use the -u flag\n"); 573: exit(-1); 574: } 575: } 576: bmove(usr_ovrd, Usercode, 2); 577: } 578: 579: /* 580: ** Process the +-w flag. 581: ** First, determine the locking mode. If +w, always 582: ** wait; if -w, never wait; if unspecified, wait if in 583: ** background, but print error and exit if running 584: ** interactive. 585: */ 586: 587: if (waitflag > 0 || (waitflag == 0 && gtty(0, >tydummy) < 0)) 588: Wait_action = A_SLP; 589: else 590: Wait_action = A_RTN; 591: if (dbflag && waitmode >= 0) 592: db_lock(waitmode); 593: 594: /* 595: ** Return authorization value. 596: */ 597: 598: return (rtval); 599: } 600: /* 601: ** DB_LOCK -- lock database 602: ** 603: ** Locks the database. Everyone should do this before using any 604: ** database. 605: ** 606: ** Parameters: 607: ** database -- the pathname of the database. 608: ** mode -- M_EXCL -- get an exclusive lock. 609: ** M_SHARE -- get a shared lock. 610: ** 611: ** Returns: 612: ** none 613: ** 614: ** Side Effects: 615: ** Alockdes is opened. 616: ** 617: ** Requires: 618: ** setdbl 619: ** stat -- to find the inumber of the database. 620: ** Lock -- must have the .dbnode part filled in (done 621: ** by initdbpath). 622: ** Admin -- must have the adflags part filled in. 623: */ 624: 625: struct lockreq Lock; /* the database lock structure */ 626: 627: db_lock(mode) 628: int mode; 629: { 630: if ((Admin.adhdr.adflags & A_DBCONCUR) == 0) 631: return; 632: if (Alockdes < 0) 633: Alockdes = open("/dev/ingreslock", 1); 634: if (setdbl(Wait_action, mode) < 0) 635: { 636: printf("Database temporarily unavailable\n"); 637: exit(1); 638: } 639: } 640: /* 641: ** INITDBPATH -- initialize the pathname of the database 642: ** 643: ** The pathname of a specified database is created. Indirection 644: ** via a file is supported, so that if the pathname is a file, 645: ** the first line of the file is read and used as the pathname 646: ** of the real database. 647: ** 648: ** Parameters: 649: ** database -- the name of the database. If NULL, 650: ** the pathname of datadir is returned. 651: ** dbbuf -- a buffer into which the pathname should 652: ** be dumped. 653: ** follow -- if set, follow the indirect chain of 654: ** database pathnames. 655: ** 656: ** Returns: 657: ** 0 -- database exists in datadir 658: ** 1 -- database exists, but I followed a pointer. 659: ** 2 -- database doesn't exist in datadir. 660: ** 3 -- databae doesn't exist, but I followed a pointer. 661: ** 662: ** Side Effects: 663: ** none. 664: ** 665: ** Requires: 666: ** Pathname -- must have the pathname of the root of 667: ** the INGRES subtree. 668: ** Ing_uid -- must have the user id of the INGRES user. 669: */ 670: 671: initdbpath(database, dbpath, follow) 672: char *database; 673: char *dbpath; 674: int follow; 675: { 676: struct stat ibuf; 677: register char *d; 678: register FILE *f; 679: register int phase; 680: int retval; 681: int uid; 682: 683: d = dbpath; 684: 685: if (database == NULL) 686: { 687: concat(Pathname, "/data/base/", d); 688: return (0); 689: } 690: 691: /* get the basic pathname */ 692: concat(ztack(Pathname, "/datadir/"), database, d); 693: 694: /* 695: ** Iterate looking for database. 696: ** "Phase" is what we are trying: 697: ** -1 -- looking in datadir 698: ** 0 -- looking in data/base 699: ** 1 -- following indirect. 700: */ 701: 702: retval = 2; 703: for (phase = -1;;) 704: { 705: /* find out what sort of filesystem node this is */ 706: if (stat(d, &ibuf) < 0) 707: { 708: if (phase < 0) 709: { 710: concat(ztack(Pathname, "/data/base/"), database, d); 711: phase = 0; 712: continue; 713: } 714: else 715: return (retval); 716: } 717: 718: /* set up the lock structure for future use */ 719: bmove(&ibuf, Lock.dbnode, 4); 720: 721: retval -= 2; 722: if ((ibuf.st_mode & 060000) == 040000) 723: return (retval); 724: 725: /* if second time through, the database must be a directory */ 726: if (phase > 0) 727: syserr("initdbpath: not direc"); 728: 729: /* if we shouldn't follow the chain, say it exists */ 730: if (!follow) 731: return (3); 732: 733: /* it's a file -- see if we can use it */ 734: uid = ibuf.st_uid; 735: # ifdef xB_UNIX 736: uid = (uid & 0377) | ((ibuf.st_gid & 0377) << 8); 737: # endif 738: # ifdef xV6_UNIX 739: uid &= 0377; 740: # endif 741: if (uid != Ing_uid || (ibuf.st_mode & 0777) != 0600) 742: return (3); 743: 744: f = fopen(d, "r"); 745: if (f == NULL) 746: syserr("initdbpath: fopen"); 747: 748: /* read the pathname of the database */ 749: if (fgetline(d, MAXLINE, f) == NULL || d[0] != '/') 750: syserr("initdbpath: bad indirect"); 751: fclose(f); 752: 753: /* prepare for next iteration */ 754: retval = 3; 755: phase = 1; 756: } 757: }