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