1/* Copyright (c) 1993-2002
2 *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
20 *
21 ****************************************************************
22 */
23
24#include <sys/types.h>
25
26#include "config.h"
27
28
29/* XXX: WHY IS THIS HERE?? :XXX */
30
31#ifdef CHECKLOGIN
32# ifdef _SEQUENT_
33#  include <stdio.h>	/* needed by <pwd.h> */
34# endif /* _SEQUENT_ */
35# include <pwd.h>
36# ifdef SHADOWPW
37#  include <shadow.h>
38# endif /* SHADOWPW */
39#endif /* CHECKLOGIN */
40
41#ifndef NOSYSLOG
42# include <syslog.h>
43#endif
44
45#include "screen.h"	/* includes acls.h */
46#include "extern.h"
47
48
49/************************************************************************
50 * user managing code, this does not really belong into the acl stuff   *
51 ************************************************************************/
52
53extern struct comm comms[];
54extern struct win *windows, *wtab[];
55extern char NullStr[];
56extern char SockPath[];
57extern struct display *display, *displays;
58struct acluser *users;
59
60#ifdef MULTIUSER
61int maxusercount = 0;	/* used in process.c: RC_MONITOR, RC_SILENCE */
62
63/* record given user ids here */
64static AclBits userbits;
65
66/*
67 * rights a new unknown user will have on windows and cmds.
68 * These are changed by a "umask ?-..." command:
69 */
70static char default_w_bit[ACL_BITS_PER_WIN] =
71{
72  1,	/* EXEC */
73  1, 	/* WRITE */
74  1 	/* READ */
75};
76
77static char default_c_bit[ACL_BITS_PER_CMD] =
78{
79  0	/* EXEC */
80};
81
82/* rights of all users per newly created window */
83/*
84 * are now stored per user (umask)
85 * static AclBits default_w_userbits[ACL_BITS_PER_WIN];
86 * static AclBits default_c_userbits[ACL_BITS_PER_CMD];
87 */
88
89static int GrowBitfield __P((AclBits *, int, int, int));
90static struct aclusergroup **FindGroupPtr __P((struct aclusergroup **, struct acluser *, int));
91static int AclSetPermCmd __P((struct acluser *, char *, struct comm *));
92static int AclSetPermWin __P((struct acluser *, struct acluser *, char *, struct win *));
93static int UserAcl __P((struct acluser *, struct acluser **, int, char **));
94static int UserAclCopy __P((struct acluser **, struct acluser **));
95
96
97static int
98GrowBitfield(bfp, len, delta, defaultbit)
99AclBits *bfp;
100int len, delta, defaultbit;
101{
102  AclBits n, o = *bfp;
103  int i;
104
105  if (!(n = (AclBits)calloc(1, (unsigned long)(&ACLBYTE((char *)0, len + delta + 1)))))
106    return -1;
107  for (i = 0; i < (len + delta); i++)
108    {
109      if (((i <  len) && (ACLBIT(i) & ACLBYTE(o, i))) ||
110          ((i >= len) && (defaultbit)))
111	ACLBYTE(n, i) |= ACLBIT(i);
112    }
113  if (len)
114    free((char *)o);
115  *bfp = n;
116  return 0;
117}
118
119#endif /* MULTIUSER */
120
121/*
122 * Returns an nonzero Address. Its contents is either a User-ptr,
123 * or NULL which may be replaced by a User-ptr to create the entry.
124 */
125struct acluser **
126FindUserPtr(name)
127char *name;
128{
129  struct acluser **u;
130
131  for (u = &users; *u; u = &(*u)->u_next)
132    if (!strcmp((*u)->u_name, name))
133      break;
134#ifdef MULTIUSER
135  debug3("FindUserPtr %s %sfound, id %d\n", name, (*u)?"":"not ",
136         (*u)?(*u)->u_id:-1);
137#else /* MULTIUSER */
138  debug2("FindUserPtr %s %sfound\n", name, (*u)?"":"not ");
139#endif /* MULTIUSER */
140  return u;
141}
142
143int DefaultEsc = -1;		/* initialised by screen.c:main() */
144int DefaultMetaEsc = -1;
145
146/*
147 * Add a new user. His password may be NULL or "" if none. His name must not
148 * be "none", as this represents the NULL-pointer when dealing with groups.
149 * He has default rights, determined by umask.
150 */
151int
152UserAdd(name, pass, up)
153char *name, *pass;
154struct acluser **up;
155{
156#ifdef MULTIUSER
157  int j;
158#endif
159
160  if (!up)
161    up = FindUserPtr(name);
162  if (*up)
163    {
164      if (pass)
165        (*up)->u_password = SaveStr(pass);
166      return 1;		/* he is already there */
167    }
168  if (strcmp("none", name))	/* "none" is a reserved word */
169    *up = (struct acluser *)calloc(1, sizeof(struct acluser));
170  if (!*up)
171    return -1;		/* he still does not exist */
172#ifdef COPY_PASTE
173  (*up)->u_plop.buf = NULL;
174  (*up)->u_plop.len = 0;
175# ifdef ENCODINGS
176  (*up)->u_plop.enc = 0;
177# endif
178#endif
179  (*up)->u_Esc = DefaultEsc;
180  (*up)->u_MetaEsc = DefaultMetaEsc;
181  strncpy((*up)->u_name, name, 20);
182  (*up)->u_password = NULL;
183  if (pass)
184    (*up)->u_password = SaveStr(pass);
185  if (!(*up)->u_password)
186    (*up)->u_password = NullStr;
187  (*up)->u_detachwin = -1;
188  (*up)->u_detachotherwin = -1;
189
190#ifdef MULTIUSER
191  (*up)->u_group = NULL;
192  /* now find an unused index */
193  for ((*up)->u_id = 0; (*up)->u_id < maxusercount; (*up)->u_id++)
194    if (!(ACLBIT((*up)->u_id) & ACLBYTE(userbits, (*up)->u_id)))
195      break;
196  debug2("UserAdd %s id %d\n", name, (*up)->u_id);
197  if ((*up)->u_id == maxusercount)
198    {
199      int j;
200      struct win *w;
201      struct acluser *u;
202
203      debug2("growing all bitfields %d += %d\n", maxusercount, USER_CHUNK);
204      /* the bitfields are full, grow a chunk */
205      /* first, the used_uid_indicator: */
206      if (GrowBitfield(&userbits, maxusercount, USER_CHUNK, 0))
207        {
208	  free((char *)*up); *up = NULL; return -1;
209	}
210      /* second, default command bits  */
211      /* (only if we generate commands dynamically) */
212/*
213      for (j = 0; j < ACL_BITS_PER_CMD; j++)
214	if (GrowBitfield(&default_c_userbits[j], maxusercount, USER_CHUNK,
215	    default_c_bit[j]))
216	  {
217	    free((char *)*up); *up = NULL; return -1;
218	  }
219*/
220      /* third, the bits for each commands */
221      for (j = 0; j <= RC_LAST; j++)
222        {
223	  int i;
224
225	  for (i = 0; i < ACL_BITS_PER_CMD; i++)
226	    if (GrowBitfield(&comms[j].userbits[i], maxusercount, USER_CHUNK,
227	        default_c_bit[i]))
228	      {
229	        free((char *)*up); *up = NULL; return -1;
230	      }
231        }
232      /* fourth, default window creation bits per user */
233      for (u = users; u != *up; u = u->u_next)
234        {
235	  for (j = 0; j < ACL_BITS_PER_WIN; j++)
236	    {
237	      if (GrowBitfield(&u->u_umask_w_bits[j], maxusercount, USER_CHUNK,
238		  default_w_bit[j]))
239		{
240		  free((char *)*up); *up = NULL; return -1;
241		}
242	    }
243	}
244
245      /* fifth, the bits for each window */
246      /* keep these in sync with NewWindowAcl() */
247      for (w = windows; w; w = w->w_next)
248	{
249	  /* five a: the access control list */
250	  for (j = 0; j < ACL_BITS_PER_WIN; j++)
251	    if (GrowBitfield(&w->w_userbits[j], maxusercount, USER_CHUNK,
252		default_w_bit[j]))
253	      {
254		free((char *)*up); *up = NULL; return -1;
255	      }
256	  /* five b: the activity notify list */
257	  /* five c: the silence notify list */
258	  if (GrowBitfield(&w->w_mon_notify, maxusercount, USER_CHUNK, 0) ||
259	      GrowBitfield(&w->w_lio_notify, maxusercount, USER_CHUNK, 0))
260	    {
261	      free((char *)*up); *up = NULL; return -1;
262	    }
263	}
264      maxusercount += USER_CHUNK;
265    }
266
267  /* mark the user-entry as "in-use" */
268  ACLBYTE(userbits, (*up)->u_id) |= ACLBIT((*up)->u_id);
269
270  /* user id 0 is the session creator, he has all rights */
271  if ((*up)->u_id == 0)
272    AclSetPerm(NULL, *up, "+a", "#?");
273
274  /* user nobody has a fixed set of rights: */
275  if (!strcmp((*up)->u_name, "nobody"))
276    {
277      AclSetPerm(NULL, *up, "-rwx", "#?");
278      AclSetPerm(NULL, *up, "+x", "su");
279      AclSetPerm(NULL, *up, "+x", "detach");
280      AclSetPerm(NULL, *up, "+x", "displays");
281      AclSetPerm(NULL, *up, "+x", "version");
282    }
283
284  /*
285   * Create his umask:
286   * Give default_w_bit's for all users,
287   * but allow himself everything on "his" windows.
288   */
289  for (j = 0; j < ACL_BITS_PER_WIN; j++)
290    {
291      if (GrowBitfield(&(*up)->u_umask_w_bits[j], 0, maxusercount,
292          default_w_bit[j]))
293        {
294          free((char *)*up); *up = NULL; return -1;
295        }
296      ACLBYTE((*up)->u_umask_w_bits[j], (*up)->u_id) |= ACLBIT((*up)->u_id);
297    }
298#else /* MULTIUSER */
299  debug1("UserAdd %s\n", name);
300#endif /* MULTIUSER */
301  return 0;
302}
303
304#if 0
305/* change user's password */
306int
307UserSetPass(name, pass, up)
308char *name, *pass;
309struct acluser **up;
310{
311  if (!up)
312    up = FindUserPtr(name);
313  if (!*up)
314    return UserAdd(name, pass, up);
315  if (!strcmp(name, "nobody"))		/* he remains without password */
316    return -1;
317  strncpy((*up)->u_password, pass ? pass : "", 20);
318  (*up)->u_password[20] = '\0';
319  return 0;
320}
321#endif
322
323/*
324 * Remove a user from the list.
325 * Destroy all his permissions and completely detach him from the session.
326 */
327int
328UserDel(name, up)
329char *name;
330struct acluser **up;
331{
332  struct acluser *u;
333#ifdef MULTIUSER
334  int i;
335#endif
336  struct display *old, *next;
337
338  if (!up)
339    up = FindUserPtr(name);
340  if (!(u = *up))
341    return -1;			/* he who does not exist cannot be removed */
342  old = display;
343  for (display = displays; display; display = next)
344    {
345      next = display->d_next;	/* read the next ptr now, Detach may zap it. */
346      if (D_user != u)
347	continue;
348      if (display == old)
349	old = NULL;
350      Detach(D_REMOTE);
351    }
352  display = old;
353  *up = u->u_next;
354
355#ifdef MULTIUSER
356  for (up = &users; *up; up = &(*up)->u_next)
357    {
358      /* unlink all group references to this user */
359      struct aclusergroup **g = &(*up)->u_group;
360
361      while (*g)
362        {
363	  if ((*g)->u == u)
364	    {
365	      struct aclusergroup *next = (*g)->next;
366
367	      free((char *)(*g));
368	      *g = next;
369	    }
370	  else
371	    g = &(*g)->next;
372	}
373    }
374  ACLBYTE(userbits, u->u_id) &= ~ACLBIT(u->u_id);
375  /* restore the bits in his slot to default: */
376  AclSetPerm(NULL, u, default_w_bit[ACL_READ] ? "+r" : "-r", "#");
377  AclSetPerm(NULL, u, default_w_bit[ACL_WRITE]? "+w" : "-w", "#");
378  AclSetPerm(NULL, u, default_w_bit[ACL_EXEC] ? "+x" : "-x", "#");
379  AclSetPerm(NULL, u, default_c_bit[ACL_EXEC] ? "+x" : "-x", "?");
380  for (i = 0; i < ACL_BITS_PER_WIN; i++)
381    free((char *)u->u_umask_w_bits[i]);
382#endif /* MULTIUSER */
383  debug1("FREEING user structure for %s\n", u->u_name);
384#ifdef COPY_PASTE
385  UserFreeCopyBuffer(u);
386#endif
387  free((char *)u);
388  if (!users)
389    {
390      debug("Last user deleted. Feierabend.\n");
391      Finit(0);	/* Destroying whole session. Noone could ever attach again. */
392    }
393  return 0;
394}
395
396
397#ifdef COPY_PASTE
398
399/*
400 * returns 0 if the copy buffer was really deleted.
401 * Also removes any references into the users copybuffer
402 */
403int
404UserFreeCopyBuffer(u)
405struct acluser *u;
406{
407  struct win *w;
408  struct paster *pa;
409
410  if (!u->u_plop.buf)
411    return 1;
412  for (w = windows; w; w = w->w_next)
413    {
414      pa = &w->w_paster;
415      if (pa->pa_pasteptr >= u->u_plop.buf &&
416          pa->pa_pasteptr - u->u_plop.buf < u->u_plop.len)
417        FreePaster(pa);
418    }
419  free((char *)u->u_plop.buf);
420  u->u_plop.len = 0;
421  u->u_plop.buf = 0;
422  return 0;
423}
424#endif	/* COPY_PASTE */
425
426#ifdef MULTIUSER
427/*
428 * Traverses group nodes. It searches for a node that references user u.
429 * If recursive is true, nodes found in the users are also searched using
430 * depth first method.  If none of the nodes references u, the address of
431 * the last next pointer is returned. This address will contain NULL.
432 */
433static struct aclusergroup **
434FindGroupPtr(gp, u, recursive)
435struct aclusergroup **gp;
436struct acluser *u;
437int recursive;
438{
439  struct aclusergroup **g;
440
441  ASSERT(recursive < 1000);		/* Ouch, cycle detection failed */
442  while (*gp)
443    {
444      if ((*gp)->u == u)
445        return gp;			/* found him here. */
446      if (recursive &&
447          *(g = FindGroupPtr(&(*gp)->u->u_group, u, recursive + 1)))
448	return g;			/* found him there. */
449      gp = &(*gp)->next;
450    }
451  return gp;				/* *gp is NULL */
452}
453
454/*
455 * Returns nonzero if failed or already linked.
456 * Both users are created on demand.
457 * Cyclic links are prevented.
458 */
459int
460AclLinkUser(from, to)
461char *from, *to;
462{
463  struct acluser **u1, **u2;
464  struct aclusergroup **g;
465
466  if (!*(u1 = FindUserPtr(from)) && UserAdd(from, NULL, u1))
467    return -1;
468  if (!*(u2 = FindUserPtr(to)) && UserAdd(to, NULL, u2))
469    return -1;			/* hmm, could not find both users. */
470
471  if (*FindGroupPtr(&(*u2)->u_group, *u1, 1))
472    return 1;			/* cyclic link detected! */
473  if (*(g = FindGroupPtr(&(*u1)->u_group, *u2, 0)))
474    return 2;			/* aha, we are already linked! */
475
476  if (!(*g = (struct aclusergroup *)malloc(sizeof(struct aclusergroup))))
477    return -1;			/* Could not alloc link. Poor screen */
478  (*g)->u = (*u2);
479  (*g)->next = NULL;
480  return 0;
481}
482
483/*
484 * The user pointer stored at *up will be substituted by a pointer
485 * to the named user's structure, if passwords match.
486 * returns NULL if successfull, an static error string otherwise
487 */
488char *
489DoSu(up, name, pw1, pw2)
490struct acluser **up;
491char *name, *pw1, *pw2;
492{
493  struct acluser *u;
494  int sorry = 0;
495
496  if (!(u = *FindUserPtr(name)))
497    sorry++;
498  else
499    {
500#ifdef CHECKLOGIN
501      struct passwd *pp;
502#ifdef SHADOWPW
503      struct spwd *ss;
504      int t, c;
505#endif
506      char *pass = "";
507
508      if (!(pp = getpwnam(name)))
509        {
510	  debug1("getpwnam(\"%s\") failed\n", name);
511          if (!(pw1 && *pw1 && *pw1 != '\377'))
512	    {
513	      debug("no unix account, no screen passwd\n");
514	      sorry++;
515	    }
516	}
517      else
518        pass = pp->pw_passwd;
519#ifdef SHADOWPW
520      for (t = 0; t < 13; t++)
521        {
522	  c = pass[t];
523	  if (!(c == '.' || c == '/' ||
524	       (c >= '0' && c <= '9') ||
525	       (c >= 'a' && c <= 'z') ||
526	       (c >= 'A' && c <= 'Z')))
527	    break;
528	}
529      if (t < 13)
530        {
531	  if (!(ss = getspnam(name)))
532	    {
533	      debug1("getspnam(\"%s\") failed\n", name);
534	      sorry++;
535	    }
536	  else
537	    pass = ss->sp_pwdp;
538	}
539#endif /* SHADOWPW */
540
541      if (pw2 && *pw2 && *pw2 != '\377')	/* provided a system password */
542        {
543	  if (!*pass ||				/* but needed none */
544	      strcmp(crypt(pw2, pass), pass))
545	    {
546	      debug("System password mismatch\n");
547	      sorry++;
548	    }
549	}
550      else					/* no pasword provided */
551        if (*pass)				/* but need one */
552	  sorry++;
553#endif
554      if (pw1 && *pw1 && *pw1 != '\377')	/* provided a screen password */
555	{
556	  if (!*u->u_password ||		/* but needed none */
557	      strcmp(crypt(pw1, u->u_password), u->u_password))
558	    {
559	      debug("screen password mismatch\n");
560              sorry++;
561	    }
562	}
563      else					/* no pasword provided */
564        if (*u->u_password)			/* but need one */
565	  sorry++;
566    }
567
568  debug2("syslog(LOG_NOTICE, \"screen %s: \"su %s\" ", SockPath, name);
569  debug2("%s for \"%s\"\n", sorry ? "failed" : "succeded", (*up)->u_name);
570#ifndef NOSYSLOG
571# ifdef BSD_42
572  openlog("screen", LOG_PID);
573# else
574  openlog("screen", LOG_PID, LOG_AUTH);
575# endif /* BSD_42 */
576  syslog(LOG_NOTICE, "%s: \"su %s\" %s for \"%s\"", SockPath, name,
577         sorry ? "failed" : "succeded", (*up)->u_name);
578  closelog();
579#else
580  debug("NOT LOGGED.\n");
581#endif /* NOSYSLOG */
582
583  if (sorry)
584    return "Sorry.";
585  else
586    *up = u;	/* substitute user now */
587  return NULL;
588}
589#endif /* MULTIUSER */
590
591/************************************************************************
592 *                     end of user managing code                        *
593 ************************************************************************/
594
595
596#ifdef MULTIUSER
597
598/* This gives the users default rights to the new window w created by u */
599int
600NewWindowAcl(w, u)
601struct win *w;
602struct acluser *u;
603{
604  int i, j;
605
606  debug2("NewWindowAcl %s's umask_w_bits for window %d\n",
607         u ? u->u_name : "everybody", w->w_number);
608
609  /* keep these in sync with UserAdd part five. */
610  if (GrowBitfield(&w->w_mon_notify, 0, maxusercount, 0) ||
611      GrowBitfield(&w->w_lio_notify, 0, maxusercount, 0))
612    return -1;
613  for (j = 0; j < ACL_BITS_PER_WIN; j++)
614    {
615      /* we start with len 0 for the new bitfield size and add maxusercount */
616      if (GrowBitfield(&w->w_userbits[j], 0, maxusercount, 0))
617	{
618	  while (--j >= 0)
619	    free((char *)w->w_userbits[j]);
620	  free((char *)w->w_mon_notify);
621	  free((char *)w->w_lio_notify);
622	  return -1;
623	}
624      for (i = 0; i < maxusercount; i++)
625        if (u ? (ACLBIT(i) & ACLBYTE(u->u_umask_w_bits[j], i)) :
626	        default_w_bit[j])
627	  ACLBYTE(w->w_userbits[j], i) |= ACLBIT(i);
628    }
629  return 0;
630}
631
632void
633FreeWindowAcl(w)
634struct win *w;
635{
636  int i;
637
638  for (i = 0; i < ACL_BITS_PER_WIN; i++)
639    free((char *)w->w_userbits[i]);
640  free((char *)w->w_mon_notify);
641  free((char *)w->w_lio_notify);
642}
643
644
645/* if mode starts with '-' we remove the users exec bit for cmd */
646/*
647 * NOTE: before you make this function look the same as
648 * AclSetPermWin, try to merge both functions.
649 */
650static int
651AclSetPermCmd(u, mode, cmd)
652struct acluser *u;
653char *mode;
654struct comm *cmd;
655{
656  int neg = 0;
657  char *m = mode;
658
659  while (*m)
660    {
661      switch (*m++)
662        {
663	case '-':
664	  neg = 1;
665	  continue;
666        case '+':
667	  neg = 0;
668	  continue;
669        case 'a':
670        case 'e':
671        case 'x':
672/*	  debug3("AclSetPermCmd %s %s %s\n", u->u_name, mode, cmd->name); */
673	  if (neg)
674	    ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) &= ~ACLBIT(u->u_id);
675	  else
676	    ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) |= ACLBIT(u->u_id);
677	  break;
678        case 'r':
679	case 'w':
680	  break;
681        default:
682	  return -1;
683	}
684    }
685  return 0;
686}
687
688/* mode strings of the form +rwx -w+rx r -wx are parsed and evaluated */
689/*
690 * aclchg nerd -w+w 2
691 * releases a writelock on window 2 held by user nerd.
692 * Letter n allows network access on a window.
693 * uu should be NULL, except if you want to change his umask.
694 */
695static int
696AclSetPermWin(uu, u, mode, win)
697struct acluser *u, *uu;
698char *mode;
699struct win *win;
700{
701  int neg = 0;
702  int bit, bits;
703  AclBits *bitarray;
704  char *m = mode;
705
706  if (uu)
707    {
708      debug3("AclSetPermWin %s UMASK %s %s\n", uu->u_name, u->u_name, mode);
709      bitarray = uu->u_umask_w_bits;
710    }
711  else
712    {
713      ASSERT(win);
714      bitarray = win->w_userbits;
715      debug3("AclSetPermWin %s %s %d\n", u->u_name, mode, win->w_number);
716    }
717
718  while (*m)
719    {
720      switch (*m++)
721        {
722	case '-':
723	  neg = 1;
724	  continue;
725        case '+':
726	  neg = 0;
727	  continue;
728        case 'r':
729	  bits = (1 << ACL_READ);
730	  break;
731	case 'w':
732	  bits = (1 << ACL_WRITE);
733	  break;
734        case 'x':
735	  bits = (1 << ACL_EXEC);
736	  break;
737        case 'a':
738	  bits = (1 << ACL_BITS_PER_WIN) - 1;
739	  break;
740	default:
741	  return -1;
742        }
743      for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
744	{
745	  if (!(bits & (1 << bit)))
746	    continue;
747	  if (neg)
748	    ACLBYTE(bitarray[bit], u->u_id) &= ~ACLBIT(u->u_id);
749	  else
750	    ACLBYTE(bitarray[bit], u->u_id) |= ACLBIT(u->u_id);
751	  if (!uu && (win->w_wlockuser == u) && neg && (bit == ACL_WRITE))
752	    {
753	      debug2("%s lost writelock on win %d\n", u->u_name, win->w_number);
754	      win->w_wlockuser = NULL;
755	      if (win->w_wlock == WLOCK_ON)
756		win->w_wlock = WLOCK_AUTO;
757	    }
758	}
759    }
760  if (uu && u->u_name[0] == '?' && u->u_name[1] == '\0')
761    {
762      /*
763       * It is Mr. '?', the unknown user. He deserves special treatment as
764       * he defines the defaults. Sorry, this is global, not per user.
765       */
766      if (win)
767        {
768	  debug1("AclSetPermWin: default_w_bits '%s'.\n", mode);
769	  for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
770	    default_w_bit[bit] =
771	      (ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0;
772	}
773      else
774	{
775	  /*
776	   * Hack. I do not want to duplicate all the above code for
777	   * AclSetPermCmd. This asumes that there are not more bits
778	   * per cmd than per win.
779	   */
780	  debug1("AclSetPermWin: default_c_bits '%s'.\n", mode);
781	  for (bit = 0; bit < ACL_BITS_PER_CMD; bit++)
782	    default_c_bit[bit] =
783	      (ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0;
784	}
785      UserDel(u->u_name, NULL);
786    }
787  return 0;
788}
789
790/*
791 * String is broken down into comand and window names, mode applies
792 * A command name matches first, so do not use these as window names.
793 * uu should be NULL, except if you want to change his umask.
794 */
795int
796AclSetPerm(uu, u, mode, s)
797struct acluser *uu, *u;
798char *mode, *s;
799{
800  struct win *w;
801  int i;
802  char *p, ch;
803
804  debug3("AclSetPerm(uu, user '%s', mode '%s', object '%s')\n",
805         u->u_name, mode, s);
806  while (*s)
807    {
808      switch (*s)
809	{
810	case '*':			/* all windows and all commands */
811	  return AclSetPerm(uu, u, mode, "#?");
812	case '#':
813	  if (uu)			/* window umask or .. */
814	    AclSetPermWin(uu, u, mode, (struct win *)1);
815	  else				/* .. or all windows */
816	    for (w = windows; w; w = w->w_next)
817	      AclSetPermWin((struct acluser *)0, u, mode, w);
818	  s++;
819	  break;
820	case '?':
821	  if (uu)			/* command umask or .. */
822	    AclSetPermWin(uu, u, mode, (struct win *)0);
823	  else				/* .. or all commands */
824	    for (i = 0; i <= RC_LAST; i++)
825	      AclSetPermCmd(u, mode, &comms[i]);
826	  s++;
827	  break;
828	default:
829	  for (p = s; *p && *p != ' ' && *p != '\t' && *p != ','; p++)
830	    ;
831	  if ((ch = *p))
832	    *p++ = '\0';
833	  if ((i = FindCommnr(s)) != RC_ILLEGAL)
834	    AclSetPermCmd(u, mode, &comms[i]);
835	  else if (((i = WindowByNoN(s)) >= 0) && wtab[i])
836	    AclSetPermWin((struct acluser *)0, u, mode, wtab[i]);
837	  else
838	    /* checking group name */
839	    return -1;
840	  if (ch)
841	    p[-1] = ch;
842	  s = p;
843	}
844    }
845  return 0;
846}
847
848/*
849 * Generic ACL Manager:
850 *
851 * This handles acladd and aclchg identical.
852 * With 2 or 4 parameters, the second parameter is a password.
853 * With 3 or 4 parameters the last two parameters specify the permissions
854 *   else user is added with full permissions.
855 * With 1 parameter the users permissions are copied from user *argv.
856 *   Unlike the other cases, u->u_name should not match *argv here.
857 * uu should be NULL, except if you want to change his umask.
858 */
859static int
860UserAcl(uu, u, argc, argv)
861struct acluser *uu, **u;
862int argc;
863char **argv;
864{
865  if ((*u && !strcmp((*u)->u_name, "nobody")) ||
866      (argc > 1 && !strcmp(argv[0], "nobody")))
867    return -1;			/* do not change nobody! */
868
869  switch (argc)
870    {
871    case 1+1+2:
872      debug2("UserAcl: user '%s', password '%s':", argv[0], argv[1]);
873      return (UserAdd(argv[0], argv[1], u) < 0) ||
874	      AclSetPerm(uu, *u, argv[2], argv[3]);
875    case 1+2:
876      debug1("UserAcl: user '%s', no password:", argv[0]);
877      return (UserAdd(argv[0],    NULL, u) < 0) ||
878	      AclSetPerm(uu, *u, argv[1], argv[2]);
879    case 1+1:
880      debug2("UserAcl: user '%s', password '%s'\n", argv[0], argv[1]);
881      return UserAdd(argv[0], argv[1], u) < 0;
882    case 1:
883      debug1("UserAcl: user '%s', no password:", argv[0]);
884      return (UserAdd(argv[0],    NULL, u) < 0) ||
885	      AclSetPerm(uu, *u, "+a", "#?");
886    default:
887      return -1;
888    }
889}
890
891static int
892UserAclCopy(to_up, from_up)
893struct acluser **to_up, **from_up;
894{
895  struct win *w;
896  int i, j, to_id, from_id;
897
898  if (!*to_up || !*from_up)
899    return -1;
900  debug2("UserAclCopy: from user '%s' to user '%s'\n",
901         (*from_up)->u_name, (*to_up)->u_name);
902  if ((to_id = (*to_up)->u_id) == (from_id = (*from_up)->u_id))
903    return -1;
904  for (w = windows; w; w = w->w_next)
905    {
906      for (i = 0; i < ACL_BITS_PER_WIN; i++)
907        {
908	  if (ACLBYTE(w->w_userbits[i], from_id) & ACLBIT(from_id))
909	    ACLBYTE(w->w_userbits[i], to_id) |= ACLBIT(to_id);
910	  else
911	    {
912	      ACLBYTE(w->w_userbits[i], to_id) &= ~ACLBIT(to_id);
913	      if ((w->w_wlockuser == *to_up) && (i == ACL_WRITE))
914		{
915		  debug2("%s lost wlock on win %d\n",
916		         (*to_up)->u_name, w->w_number);
917		  w->w_wlockuser = NULL;
918		  if (w->w_wlock == WLOCK_ON)
919		    w->w_wlock = WLOCK_AUTO;
920		}
921	    }
922	}
923    }
924  for (j = 0; j <= RC_LAST; j++)
925    {
926      for (i = 0; i < ACL_BITS_PER_CMD; i++)
927        {
928	  if (ACLBYTE(comms[j].userbits[i], from_id) & ACLBIT(from_id))
929	    ACLBYTE(comms[j].userbits[i], to_id) |= ACLBIT(to_id);
930	  else
931	    ACLBYTE(comms[j].userbits[i], to_id) &= ~ACLBIT(to_id);
932	}
933    }
934
935  return 0;
936}
937
938/*
939 * Syntax:
940 * 	user [password] [+rwx #?]
941 * 	* [password] [+rwx #?]
942 *      user1,user2,user3 [password] [+rwx #?]
943 *	user1,user2,user3=user
944 * uu should be NULL, except if you want to change his umask.
945 */
946int
947UsersAcl(uu, argc, argv)
948struct acluser *uu;
949int argc;
950char **argv;
951{
952  char *s;
953  int r;
954  struct acluser **cf_u = NULL;
955
956  if (argc == 1)
957    {
958      char *p = NULL;
959
960      s = argv[0];
961      while (*s)
962        if (*s++ == '=') p = s;
963      if (p)
964        {
965          p[-1] = '\0';
966          cf_u = FindUserPtr(p);
967        }
968    }
969
970  if (argv[0][0] == '*' && argv[0][1] == '\0')
971    {
972      struct acluser **u;
973
974      debug("all users acls.\n");
975      for (u = &users; *u; u = &(*u)->u_next)
976	if (strcmp("nobody", (*u)->u_name) &&
977	    ((cf_u) ?
978	     ((r = UserAclCopy(u, cf_u)) < 0) :
979	     ((r = UserAcl(uu, u, argc, argv)) < 0)))
980	  return -1;
981      return 0;
982    }
983
984  do
985    {
986      for (s = argv[0]; *s && *s!=' ' && *s!='\t' && *s!=',' && *s!='='; s++)
987	;
988      *s ? (*s++ = '\0') : (*s = '\0');
989      debug2("UsersAcl(uu, \"%s\", argc=%d)\n", argv[0], argc);
990      if ((cf_u) ?
991	  ((r = UserAclCopy(FindUserPtr(argv[0]), cf_u)) < 0) :
992	  ((r = UserAcl(uu, FindUserPtr(argv[0]), argc, argv)) < 0))
993        return -1;
994    } while (*(argv[0] = s));
995  return 0;
996}
997
998/*
999 * Preprocess argments, so that umask can be set with UsersAcl
1000 *
1001 * all current users		umask �rwxn
1002 * one specific user		umask user1�rwxn
1003 * several users		umask user1,user2,...�rwxn
1004 * default_w_bits		umask ?�rwxn
1005 * default_c_bits		umask ??�rwxn
1006 */
1007int
1008AclUmask(u, str, errp)
1009struct acluser *u;
1010char *str;
1011char **errp;
1012{
1013  char mode[16];
1014  char *av[3];
1015  char *p, c = '\0';
1016
1017  /* split str into user and bits section. */
1018  for (p = str; *p; p++)
1019    if ((c = *p) == '+' || c == '-')
1020      break;
1021  if (!*p)
1022    {
1023      *errp = "Bad argument. Should be ``[user[,user...]{+|-}rwxn''.";
1024      return -1;
1025    }
1026  strncpy(mode, p, 15);
1027  mode[15] = '\0';
1028  *p = '\0';
1029
1030  /* construct argument vector */
1031  if (!strcmp("??", str))
1032    {
1033      str++;
1034      av[2] = "?";
1035    }
1036  else
1037    av[2] = "#";
1038  av[1] = mode;
1039  av[0] = *str ? str : "*";
1040  /* call UsersAcl */
1041  if (UsersAcl(u, 3, av))
1042    {
1043      *errp = "UsersAcl failed. Hmmm.";
1044      *p = c;
1045      return -1;
1046    }
1047  *p = c;
1048  return 0;
1049}
1050
1051void
1052AclWinSwap(a, b)
1053int a, b;
1054{
1055  debug2("AclWinSwap(%d, %d) NOP.\n", a, b);
1056}
1057
1058struct acluser *EffectiveAclUser = NULL;	/* hook for AT command permission */
1059
1060int
1061AclCheckPermWin(u, mode, w)
1062struct acluser *u;
1063int mode;
1064struct win *w;
1065{
1066  int ok;
1067
1068  if (mode < 0 || mode >= ACL_BITS_PER_WIN)
1069    return -1;
1070  if (EffectiveAclUser)
1071    {
1072      debug1("AclCheckPermWin: WARNING user %s overridden!\n", u->u_name);
1073      u = EffectiveAclUser;
1074    }
1075  ok = ACLBYTE(w->w_userbits[mode], u->u_id) & ACLBIT(u->u_id);
1076  debug3("AclCheckPermWin(%s, %d, %d) = ", u->u_name, mode, w->w_number);
1077
1078  if (!ok)
1079    {
1080      struct aclusergroup **g = &u->u_group;
1081      struct acluser *saved_eff = EffectiveAclUser;
1082
1083      EffectiveAclUser = NULL;
1084      while (*g)
1085        {
1086	  if (!AclCheckPermWin((*g)->u, mode, w))
1087	    break;
1088	  g = &(*g)->next;
1089	}
1090      EffectiveAclUser = saved_eff;
1091      if (*g)
1092        ok = 1;
1093    }
1094  debug1("%d\n", !ok);
1095  return !ok;
1096}
1097
1098int
1099AclCheckPermCmd(u, mode, c)
1100struct acluser *u;
1101int mode;
1102struct comm *c;
1103{
1104  int ok;
1105
1106  if (mode < 0 || mode >= ACL_BITS_PER_CMD)
1107    return -1;
1108  if (EffectiveAclUser)
1109    {
1110      debug1("AclCheckPermCmd: WARNING user %s overridden!\n", u->u_name);
1111      u = EffectiveAclUser;
1112    }
1113  ok = ACLBYTE(c->userbits[mode], u->u_id) & ACLBIT(u->u_id);
1114  debug3("AclCheckPermCmd(%s %d %s) = ", u->u_name, mode, c->name);
1115  if (!ok)
1116    {
1117      struct aclusergroup **g = &u->u_group;
1118      struct acluser *saved_eff = EffectiveAclUser;
1119
1120      EffectiveAclUser = NULL;
1121      while (*g)
1122        {
1123          if (!AclCheckPermCmd((*g)->u, mode, c))
1124            break;
1125          g = &(*g)->next;
1126        }
1127      EffectiveAclUser = saved_eff;
1128      if (*g)
1129        ok = 1;
1130    }
1131  debug1("%d\n", !ok);
1132  return !ok;
1133}
1134
1135#endif /* MULTIUSER */
1136