~dannf/ubuntu/saucy/screen/lp1213278-from-debian

1 by Nathaniel McCallum
Import upstream version 4.0.2
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
53
extern struct comm comms[];
54
extern struct win *windows, *wtab[];
55
extern char NullStr[];
56
extern char SockPath[];
57
extern struct display *display, *displays;
58
struct acluser *users;
59
60
#ifdef MULTIUSER
61
int maxusercount = 0;	/* used in process.c: RC_MONITOR, RC_SILENCE */
62
63
/* record given user ids here */
64
static 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
 */
70
static char default_w_bit[ACL_BITS_PER_WIN] = 
71
{ 
72
  1,	/* EXEC */
73
  1, 	/* WRITE */
74
  1 	/* READ */
75
};
76
77
static 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
89
static int GrowBitfield __P((AclBits *, int, int, int));
90
static struct aclusergroup **FindGroupPtr __P((struct aclusergroup **, struct acluser *, int));
91
static int AclSetPermCmd __P((struct acluser *, char *, struct comm *));
92
static int AclSetPermWin __P((struct acluser *, struct acluser *, char *, struct win *));
93
static int UserAcl __P((struct acluser *, struct acluser **, int, char **));
94
static int UserAclCopy __P((struct acluser **, struct acluser **));
95
96
97
static int
98
GrowBitfield(bfp, len, delta, defaultbit)
99
AclBits *bfp;
100
int 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
 */
125
struct acluser **
126
FindUserPtr(name)
127
char *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
143
int DefaultEsc = -1;		/* initialised by screen.c:main() */
144
int 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
 */
151
int
152
UserAdd(name, pass, up)
153
char *name, *pass;
154
struct 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 */
306
int 
307
UserSetPass(name, pass, up)
308
char *name, *pass;
309
struct 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
 */
327
int 
328
UserDel(name, up)
329
char *name;
330
struct 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
 */
403
int
404
UserFreeCopyBuffer(u)
405
struct 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
 */ 
433
static struct aclusergroup **
434
FindGroupPtr(gp, u, recursive)
435
struct aclusergroup **gp;
436
struct acluser *u;
437
int 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
 */
459
int
460
AclLinkUser(from, to)
461
char *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
 */
488
char *
489
DoSu(up, name, pw1, pw2)
490
struct acluser **up;
491
char *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 */
599
int
600
NewWindowAcl(w, u)
601
struct win *w;
602
struct 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
632
void
633
FreeWindowAcl(w)
634
struct 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
 */
650
static int
651
AclSetPermCmd(u, mode, cmd)
652
struct acluser *u;
653
char *mode;
654
struct 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
 */
695
static int
696
AclSetPermWin(uu, u, mode, win)
697
struct acluser *u, *uu;
698
char *mode;
699
struct 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
 */
795
int
796
AclSetPerm(uu, u, mode, s)
797
struct acluser *uu, *u;
798
char *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
 */
859
static int
860
UserAcl(uu, u, argc, argv)
861
struct acluser *uu, **u;
862
int argc;
863
char **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
891
static int
892
UserAclCopy(to_up, from_up)
893
struct 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
 */
946
int
947
UsersAcl(uu, argc, argv)
948
struct acluser *uu;
949
int argc;
950
char **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
 */
1007
int 
1008
AclUmask(u, str, errp)
1009
struct acluser *u;
1010
char *str;
1011
char **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
1051
void
1052
AclWinSwap(a, b)
1053
int a, b;
1054
{
1055
  debug2("AclWinSwap(%d, %d) NOP.\n", a, b);
1056
}
1057
1058
struct acluser *EffectiveAclUser = NULL;	/* hook for AT command permission */
1059
1060
int 
1061
AclCheckPermWin(u, mode, w)
1062
struct acluser *u;
1063
int mode;
1064
struct 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
1098
int 
1099
AclCheckPermCmd(u, mode, c)
1100
struct acluser *u;
1101
int mode;
1102
struct 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 */