|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.