Fix canvas.split on non-fore situation.
[screen-lua.git] / src / acls.c
bloba14552f0edadc364c873874991a8eedf6ca672e6
1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
31 #include "config.h"
34 /* XXX: WHY IS THIS HERE?? :XXX */
36 #ifdef CHECKLOGIN
37 # ifdef _SEQUENT_
38 # include <stdio.h> /* needed by <pwd.h> */
39 # endif /* _SEQUENT_ */
40 # include <pwd.h>
41 # ifdef SHADOWPW
42 # include <shadow.h>
43 # endif /* SHADOWPW */
44 #endif /* CHECKLOGIN */
46 #ifndef NOSYSLOG
47 # include <syslog.h>
48 #endif
50 #include "screen.h" /* includes acls.h */
51 #include "extern.h"
54 /************************************************************************
55 * user managing code, this does not really belong into the acl stuff *
56 ************************************************************************/
58 extern struct comm comms[];
59 extern struct win *windows, *wtab[];
60 extern char NullStr[];
61 extern char SockPath[];
62 extern struct display *display, *displays;
63 struct acluser *users;
65 #ifdef MULTIUSER
66 int maxusercount = 0; /* used in process.c: RC_MONITOR, RC_SILENCE */
68 /* record given user ids here */
69 static AclBits userbits;
72 * rights a new unknown user will have on windows and cmds.
73 * These are changed by a "umask ?-..." command:
75 static char default_w_bit[ACL_BITS_PER_WIN] =
77 1, /* EXEC */
78 1, /* WRITE */
79 1 /* READ */
82 static char default_c_bit[ACL_BITS_PER_CMD] =
84 0 /* EXEC */
87 /* rights of all users per newly created window */
89 * are now stored per user (umask)
90 * static AclBits default_w_userbits[ACL_BITS_PER_WIN];
91 * static AclBits default_c_userbits[ACL_BITS_PER_CMD];
94 static int GrowBitfield __P((AclBits *, int, int, int));
95 static struct aclusergroup **FindGroupPtr __P((struct aclusergroup **, struct acluser *, int));
96 static int AclSetPermCmd __P((struct acluser *, char *, struct comm *));
97 static int AclSetPermWin __P((struct acluser *, struct acluser *, char *, struct win *));
98 static int UserAcl __P((struct acluser *, struct acluser **, int, char **));
99 static int UserAclCopy __P((struct acluser **, struct acluser **));
102 static int
103 GrowBitfield(bfp, len, delta, defaultbit)
104 AclBits *bfp;
105 int len, delta, defaultbit;
107 AclBits n, o = *bfp;
108 int i;
110 if (!(n = (AclBits)calloc(1, (unsigned long)(&ACLBYTE((char *)0, len + delta + 1)))))
111 return -1;
112 for (i = 0; i < (len + delta); i++)
114 if (((i < len) && (ACLBIT(i) & ACLBYTE(o, i))) ||
115 ((i >= len) && (defaultbit)))
116 ACLBYTE(n, i) |= ACLBIT(i);
118 if (len)
119 free((char *)o);
120 *bfp = n;
121 return 0;
124 #endif /* MULTIUSER */
127 * Returns an nonzero Address. Its contents is either a User-ptr,
128 * or NULL which may be replaced by a User-ptr to create the entry.
130 struct acluser **
131 FindUserPtr(name)
132 char *name;
134 struct acluser **u;
136 for (u = &users; *u; u = &(*u)->u_next)
137 if (!strcmp((*u)->u_name, name))
138 break;
139 #ifdef MULTIUSER
140 debug3("FindUserPtr %s %sfound, id %d\n", name, (*u)?"":"not ",
141 (*u)?(*u)->u_id:-1);
142 #else /* MULTIUSER */
143 debug2("FindUserPtr %s %sfound\n", name, (*u)?"":"not ");
144 #endif /* MULTIUSER */
145 return u;
148 int DefaultEsc = -1; /* initialised by screen.c:main() */
149 int DefaultMetaEsc = -1;
152 * Add a new user. His password may be NULL or "" if none. His name must not
153 * be "none", as this represents the NULL-pointer when dealing with groups.
154 * He has default rights, determined by umask.
157 UserAdd(name, pass, up)
158 char *name, *pass;
159 struct acluser **up;
161 #ifdef MULTIUSER
162 int j;
163 #endif
165 if (!up)
166 up = FindUserPtr(name);
167 if (*up)
169 if (pass)
170 (*up)->u_password = SaveStr(pass);
171 return 1; /* he is already there */
173 if (strcmp("none", name)) /* "none" is a reserved word */
174 *up = (struct acluser *)calloc(1, sizeof(struct acluser));
175 if (!*up)
176 return -1; /* he still does not exist */
177 #ifdef COPY_PASTE
178 (*up)->u_plop.buf = NULL;
179 (*up)->u_plop.len = 0;
180 # ifdef ENCODINGS
181 (*up)->u_plop.enc = 0;
182 # endif
183 #endif
184 (*up)->u_Esc = DefaultEsc;
185 (*up)->u_MetaEsc = DefaultMetaEsc;
186 strncpy((*up)->u_name, name, 20);
187 (*up)->u_password = NULL;
188 if (pass)
189 (*up)->u_password = SaveStr(pass);
190 if (!(*up)->u_password)
191 (*up)->u_password = NullStr;
192 (*up)->u_detachwin = -1;
193 (*up)->u_detachotherwin = -1;
195 #ifdef MULTIUSER
196 (*up)->u_group = NULL;
197 /* now find an unused index */
198 for ((*up)->u_id = 0; (*up)->u_id < maxusercount; (*up)->u_id++)
199 if (!(ACLBIT((*up)->u_id) & ACLBYTE(userbits, (*up)->u_id)))
200 break;
201 debug2("UserAdd %s id %d\n", name, (*up)->u_id);
202 if ((*up)->u_id == maxusercount)
204 int j;
205 struct win *w;
206 struct acluser *u;
208 debug2("growing all bitfields %d += %d\n", maxusercount, USER_CHUNK);
209 /* the bitfields are full, grow a chunk */
210 /* first, the used_uid_indicator: */
211 if (GrowBitfield(&userbits, maxusercount, USER_CHUNK, 0))
213 free((char *)*up); *up = NULL; return -1;
215 /* second, default command bits */
216 /* (only if we generate commands dynamically) */
218 for (j = 0; j < ACL_BITS_PER_CMD; j++)
219 if (GrowBitfield(&default_c_userbits[j], maxusercount, USER_CHUNK,
220 default_c_bit[j]))
222 free((char *)*up); *up = NULL; return -1;
225 /* third, the bits for each commands */
226 for (j = 0; j <= RC_LAST; j++)
228 int i;
230 for (i = 0; i < ACL_BITS_PER_CMD; i++)
231 if (GrowBitfield(&comms[j].userbits[i], maxusercount, USER_CHUNK,
232 default_c_bit[i]))
234 free((char *)*up); *up = NULL; return -1;
237 /* fourth, default window creation bits per user */
238 for (u = users; u != *up; u = u->u_next)
240 for (j = 0; j < ACL_BITS_PER_WIN; j++)
242 if (GrowBitfield(&u->u_umask_w_bits[j], maxusercount, USER_CHUNK,
243 default_w_bit[j]))
245 free((char *)*up); *up = NULL; return -1;
250 /* fifth, the bits for each window */
251 /* keep these in sync with NewWindowAcl() */
252 for (w = windows; w; w = w->w_next)
254 /* five a: the access control list */
255 for (j = 0; j < ACL_BITS_PER_WIN; j++)
256 if (GrowBitfield(&w->w_userbits[j], maxusercount, USER_CHUNK,
257 default_w_bit[j]))
259 free((char *)*up); *up = NULL; return -1;
261 /* five b: the activity notify list */
262 /* five c: the silence notify list */
263 if (GrowBitfield(&w->w_mon_notify, maxusercount, USER_CHUNK, 0) ||
264 GrowBitfield(&w->w_lio_notify, maxusercount, USER_CHUNK, 0))
266 free((char *)*up); *up = NULL; return -1;
269 maxusercount += USER_CHUNK;
272 /* mark the user-entry as "in-use" */
273 ACLBYTE(userbits, (*up)->u_id) |= ACLBIT((*up)->u_id);
275 /* user id 0 is the session creator, he has all rights */
276 if ((*up)->u_id == 0)
277 AclSetPerm(NULL, *up, "+a", "#?");
279 /* user nobody has a fixed set of rights: */
280 if (!strcmp((*up)->u_name, "nobody"))
282 AclSetPerm(NULL, *up, "-rwx", "#?");
283 AclSetPerm(NULL, *up, "+x", "su");
284 AclSetPerm(NULL, *up, "+x", "detach");
285 AclSetPerm(NULL, *up, "+x", "displays");
286 AclSetPerm(NULL, *up, "+x", "version");
290 * Create his umask:
291 * Give default_w_bit's for all users,
292 * but allow himself everything on "his" windows.
294 for (j = 0; j < ACL_BITS_PER_WIN; j++)
296 if (GrowBitfield(&(*up)->u_umask_w_bits[j], 0, maxusercount,
297 default_w_bit[j]))
299 free((char *)*up); *up = NULL; return -1;
301 ACLBYTE((*up)->u_umask_w_bits[j], (*up)->u_id) |= ACLBIT((*up)->u_id);
303 #else /* MULTIUSER */
304 debug1("UserAdd %s\n", name);
305 #endif /* MULTIUSER */
306 return 0;
309 #if 0
310 /* change user's password */
311 int
312 UserSetPass(name, pass, up)
313 char *name, *pass;
314 struct acluser **up;
316 if (!up)
317 up = FindUserPtr(name);
318 if (!*up)
319 return UserAdd(name, pass, up);
320 if (!strcmp(name, "nobody")) /* he remains without password */
321 return -1;
322 strncpy((*up)->u_password, pass ? pass : "", 20);
323 (*up)->u_password[20] = '\0';
324 return 0;
326 #endif
329 * Remove a user from the list.
330 * Destroy all his permissions and completely detach him from the session.
332 int
333 UserDel(name, up)
334 char *name;
335 struct acluser **up;
337 struct acluser *u;
338 #ifdef MULTIUSER
339 int i;
340 #endif
341 struct display *old, *next;
343 if (!up)
344 up = FindUserPtr(name);
345 if (!(u = *up))
346 return -1; /* he who does not exist cannot be removed */
347 old = display;
348 for (display = displays; display; display = next)
350 next = display->d_next; /* read the next ptr now, Detach may zap it. */
351 if (D_user != u)
352 continue;
353 if (display == old)
354 old = NULL;
355 Detach(D_REMOTE);
357 display = old;
358 *up = u->u_next;
360 #ifdef MULTIUSER
361 for (up = &users; *up; up = &(*up)->u_next)
363 /* unlink all group references to this user */
364 struct aclusergroup **g = &(*up)->u_group;
366 while (*g)
368 if ((*g)->u == u)
370 struct aclusergroup *next = (*g)->next;
372 free((char *)(*g));
373 *g = next;
375 else
376 g = &(*g)->next;
379 ACLBYTE(userbits, u->u_id) &= ~ACLBIT(u->u_id);
380 /* restore the bits in his slot to default: */
381 AclSetPerm(NULL, u, default_w_bit[ACL_READ] ? "+r" : "-r", "#");
382 AclSetPerm(NULL, u, default_w_bit[ACL_WRITE]? "+w" : "-w", "#");
383 AclSetPerm(NULL, u, default_w_bit[ACL_EXEC] ? "+x" : "-x", "#");
384 AclSetPerm(NULL, u, default_c_bit[ACL_EXEC] ? "+x" : "-x", "?");
385 for (i = 0; i < ACL_BITS_PER_WIN; i++)
386 free((char *)u->u_umask_w_bits[i]);
387 #endif /* MULTIUSER */
388 debug1("FREEING user structure for %s\n", u->u_name);
389 #ifdef COPY_PASTE
390 UserFreeCopyBuffer(u);
391 #endif
392 #ifdef SCRIPT
393 broker_inv_obj(u);
394 #endif
395 free((char *)u);
396 if (!users)
398 debug("Last user deleted. Feierabend.\n");
399 Finit(0); /* Destroying whole session. Noone could ever attach again. */
401 return 0;
405 #ifdef COPY_PASTE
408 * returns 0 if the copy buffer was really deleted.
409 * Also removes any references into the users copybuffer
412 UserFreeCopyBuffer(u)
413 struct acluser *u;
415 struct win *w;
416 struct paster *pa;
418 if (!u->u_plop.buf)
419 return 1;
420 for (w = windows; w; w = w->w_next)
422 pa = &w->w_paster;
423 if (pa->pa_pasteptr >= u->u_plop.buf &&
424 pa->pa_pasteptr - u->u_plop.buf < u->u_plop.len)
425 FreePaster(pa);
427 free((char *)u->u_plop.buf);
428 u->u_plop.len = 0;
429 u->u_plop.buf = 0;
430 return 0;
432 #endif /* COPY_PASTE */
434 #ifdef MULTIUSER
436 * Traverses group nodes. It searches for a node that references user u.
437 * If recursive is true, nodes found in the users are also searched using
438 * depth first method. If none of the nodes references u, the address of
439 * the last next pointer is returned. This address will contain NULL.
441 static struct aclusergroup **
442 FindGroupPtr(gp, u, recursive)
443 struct aclusergroup **gp;
444 struct acluser *u;
445 int recursive;
447 struct aclusergroup **g;
449 ASSERT(recursive < 1000); /* Ouch, cycle detection failed */
450 while (*gp)
452 if ((*gp)->u == u)
453 return gp; /* found him here. */
454 if (recursive &&
455 *(g = FindGroupPtr(&(*gp)->u->u_group, u, recursive + 1)))
456 return g; /* found him there. */
457 gp = &(*gp)->next;
459 return gp; /* *gp is NULL */
463 * Returns nonzero if failed or already linked.
464 * Both users are created on demand.
465 * Cyclic links are prevented.
468 AclLinkUser(from, to)
469 char *from, *to;
471 struct acluser **u1, **u2;
472 struct aclusergroup **g;
474 if (!*(u1 = FindUserPtr(from)) && UserAdd(from, NULL, u1))
475 return -1;
476 if (!*(u2 = FindUserPtr(to)) && UserAdd(to, NULL, u2))
477 return -1; /* hmm, could not find both users. */
479 if (*FindGroupPtr(&(*u2)->u_group, *u1, 1))
480 return 1; /* cyclic link detected! */
481 if (*(g = FindGroupPtr(&(*u1)->u_group, *u2, 0)))
482 return 2; /* aha, we are already linked! */
484 if (!(*g = (struct aclusergroup *)malloc(sizeof(struct aclusergroup))))
485 return -1; /* Could not alloc link. Poor screen */
486 (*g)->u = (*u2);
487 (*g)->next = NULL;
488 return 0;
492 * The user pointer stored at *up will be substituted by a pointer
493 * to the named user's structure, if passwords match.
494 * returns NULL if successfull, an static error string otherwise
496 char *
497 DoSu(up, name, pw1, pw2)
498 struct acluser **up;
499 char *name, *pw1, *pw2;
501 struct acluser *u;
502 int sorry = 0;
504 if (!(u = *FindUserPtr(name)))
505 sorry++;
506 else
508 #ifdef CHECKLOGIN
509 struct passwd *pp;
510 #ifdef SHADOWPW
511 struct spwd *ss;
512 int t, c;
513 #endif
514 char *pass = "";
516 if (!(pp = getpwnam(name)))
518 debug1("getpwnam(\"%s\") failed\n", name);
519 if (!(pw1 && *pw1 && *pw1 != '\377'))
521 debug("no unix account, no screen passwd\n");
522 sorry++;
525 else
526 pass = pp->pw_passwd;
527 #ifdef SHADOWPW
528 for (t = 0; t < 13; t++)
530 c = pass[t];
531 if (!(c == '.' || c == '/' ||
532 (c >= '0' && c <= '9') ||
533 (c >= 'a' && c <= 'z') ||
534 (c >= 'A' && c <= 'Z')))
535 break;
537 if (t < 13)
539 if (!(ss = getspnam(name)))
541 debug1("getspnam(\"%s\") failed\n", name);
542 sorry++;
544 else
545 pass = ss->sp_pwdp;
547 #endif /* SHADOWPW */
549 if (pw2 && *pw2 && *pw2 != '\377') /* provided a system password */
551 if (!*pass || /* but needed none */
552 strcmp(crypt(pw2, pass), pass))
554 debug("System password mismatch\n");
555 sorry++;
558 else /* no pasword provided */
559 if (*pass) /* but need one */
560 sorry++;
561 #endif
562 if (pw1 && *pw1 && *pw1 != '\377') /* provided a screen password */
564 if (!*u->u_password || /* but needed none */
565 strcmp(crypt(pw1, u->u_password), u->u_password))
567 debug("screen password mismatch\n");
568 sorry++;
571 else /* no pasword provided */
572 if (*u->u_password) /* but need one */
573 sorry++;
576 debug2("syslog(LOG_NOTICE, \"screen %s: \"su %s\" ", SockPath, name);
577 debug2("%s for \"%s\"\n", sorry ? "failed" : "succeded", (*up)->u_name);
578 #ifndef NOSYSLOG
579 # ifdef BSD_42
580 openlog("screen", LOG_PID);
581 # else
582 openlog("screen", LOG_PID, LOG_AUTH);
583 # endif /* BSD_42 */
584 syslog(LOG_NOTICE, "%s: \"su %s\" %s for \"%s\"", SockPath, name,
585 sorry ? "failed" : "succeded", (*up)->u_name);
586 closelog();
587 #else
588 debug("NOT LOGGED.\n");
589 #endif /* NOSYSLOG */
591 if (sorry)
592 return "Sorry.";
593 else
594 *up = u; /* substitute user now */
595 return NULL;
597 #endif /* MULTIUSER */
599 /************************************************************************
600 * end of user managing code *
601 ************************************************************************/
604 #ifdef MULTIUSER
606 /* This gives the users default rights to the new window w created by u */
608 NewWindowAcl(w, u)
609 struct win *w;
610 struct acluser *u;
612 int i, j;
614 debug2("NewWindowAcl %s's umask_w_bits for window %d\n",
615 u ? u->u_name : "everybody", w->w_number);
617 /* keep these in sync with UserAdd part five. */
618 if (GrowBitfield(&w->w_mon_notify, 0, maxusercount, 0) ||
619 GrowBitfield(&w->w_lio_notify, 0, maxusercount, 0))
620 return -1;
621 for (j = 0; j < ACL_BITS_PER_WIN; j++)
623 /* we start with len 0 for the new bitfield size and add maxusercount */
624 if (GrowBitfield(&w->w_userbits[j], 0, maxusercount, 0))
626 while (--j >= 0)
627 free((char *)w->w_userbits[j]);
628 free((char *)w->w_mon_notify);
629 free((char *)w->w_lio_notify);
630 return -1;
632 for (i = 0; i < maxusercount; i++)
633 if (u ? (ACLBIT(i) & ACLBYTE(u->u_umask_w_bits[j], i)) :
634 default_w_bit[j])
635 ACLBYTE(w->w_userbits[j], i) |= ACLBIT(i);
637 return 0;
640 void
641 FreeWindowAcl(w)
642 struct win *w;
644 int i;
646 for (i = 0; i < ACL_BITS_PER_WIN; i++)
647 free((char *)w->w_userbits[i]);
648 free((char *)w->w_mon_notify);
649 free((char *)w->w_lio_notify);
653 /* if mode starts with '-' we remove the users exec bit for cmd */
655 * NOTE: before you make this function look the same as
656 * AclSetPermWin, try to merge both functions.
658 static int
659 AclSetPermCmd(u, mode, cmd)
660 struct acluser *u;
661 char *mode;
662 struct comm *cmd;
664 int neg = 0;
665 char *m = mode;
667 while (*m)
669 switch (*m++)
671 case '-':
672 neg = 1;
673 continue;
674 case '+':
675 neg = 0;
676 continue;
677 case 'a':
678 case 'e':
679 case 'x':
680 /* debug3("AclSetPermCmd %s %s %s\n", u->u_name, mode, cmd->name); */
681 if (neg)
682 ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) &= ~ACLBIT(u->u_id);
683 else
684 ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) |= ACLBIT(u->u_id);
685 break;
686 case 'r':
687 case 'w':
688 break;
689 default:
690 return -1;
693 return 0;
696 /* mode strings of the form +rwx -w+rx r -wx are parsed and evaluated */
698 * aclchg nerd -w+w 2
699 * releases a writelock on window 2 held by user nerd.
700 * Letter n allows network access on a window.
701 * uu should be NULL, except if you want to change his umask.
703 static int
704 AclSetPermWin(uu, u, mode, win)
705 struct acluser *u, *uu;
706 char *mode;
707 struct win *win;
709 int neg = 0;
710 int bit, bits;
711 AclBits *bitarray;
712 char *m = mode;
714 if (uu)
716 debug3("AclSetPermWin %s UMASK %s %s\n", uu->u_name, u->u_name, mode);
717 bitarray = uu->u_umask_w_bits;
719 else
721 ASSERT(win);
722 bitarray = win->w_userbits;
723 debug3("AclSetPermWin %s %s %d\n", u->u_name, mode, win->w_number);
726 while (*m)
728 switch (*m++)
730 case '-':
731 neg = 1;
732 continue;
733 case '+':
734 neg = 0;
735 continue;
736 case 'r':
737 bits = (1 << ACL_READ);
738 break;
739 case 'w':
740 bits = (1 << ACL_WRITE);
741 break;
742 case 'x':
743 bits = (1 << ACL_EXEC);
744 break;
745 case 'a':
746 bits = (1 << ACL_BITS_PER_WIN) - 1;
747 break;
748 default:
749 return -1;
751 for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
753 if (!(bits & (1 << bit)))
754 continue;
755 if (neg)
756 ACLBYTE(bitarray[bit], u->u_id) &= ~ACLBIT(u->u_id);
757 else
758 ACLBYTE(bitarray[bit], u->u_id) |= ACLBIT(u->u_id);
759 if (!uu && (win->w_wlockuser == u) && neg && (bit == ACL_WRITE))
761 debug2("%s lost writelock on win %d\n", u->u_name, win->w_number);
762 win->w_wlockuser = NULL;
763 if (win->w_wlock == WLOCK_ON)
764 win->w_wlock = WLOCK_AUTO;
768 if (uu && u->u_name[0] == '?' && u->u_name[1] == '\0')
771 * It is Mr. '?', the unknown user. He deserves special treatment as
772 * he defines the defaults. Sorry, this is global, not per user.
774 if (win)
776 debug1("AclSetPermWin: default_w_bits '%s'.\n", mode);
777 for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
778 default_w_bit[bit] =
779 (ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0;
781 else
784 * Hack. I do not want to duplicate all the above code for
785 * AclSetPermCmd. This asumes that there are not more bits
786 * per cmd than per win.
788 debug1("AclSetPermWin: default_c_bits '%s'.\n", mode);
789 for (bit = 0; bit < ACL_BITS_PER_CMD; bit++)
790 default_c_bit[bit] =
791 (ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0;
793 UserDel(u->u_name, NULL);
795 return 0;
799 * String is broken down into comand and window names, mode applies
800 * A command name matches first, so do not use these as window names.
801 * uu should be NULL, except if you want to change his umask.
804 AclSetPerm(uu, u, mode, s)
805 struct acluser *uu, *u;
806 char *mode, *s;
808 struct win *w;
809 int i;
810 char *p, ch;
812 debug3("AclSetPerm(uu, user '%s', mode '%s', object '%s')\n",
813 u->u_name, mode, s);
814 while (*s)
816 switch (*s)
818 case '*': /* all windows and all commands */
819 return AclSetPerm(uu, u, mode, "#?");
820 case '#':
821 if (uu) /* window umask or .. */
822 AclSetPermWin(uu, u, mode, (struct win *)1);
823 else /* .. or all windows */
824 for (w = windows; w; w = w->w_next)
825 AclSetPermWin((struct acluser *)0, u, mode, w);
826 s++;
827 break;
828 case '?':
829 if (uu) /* command umask or .. */
830 AclSetPermWin(uu, u, mode, (struct win *)0);
831 else /* .. or all commands */
832 for (i = 0; i <= RC_LAST; i++)
833 AclSetPermCmd(u, mode, &comms[i]);
834 s++;
835 break;
836 default:
837 for (p = s; *p && *p != ' ' && *p != '\t' && *p != ','; p++)
839 if ((ch = *p))
840 *p++ = '\0';
841 if ((i = FindCommnr(s)) != RC_ILLEGAL)
842 AclSetPermCmd(u, mode, &comms[i]);
843 else if (((i = WindowByNoN(s)) >= 0) && wtab[i])
844 AclSetPermWin((struct acluser *)0, u, mode, wtab[i]);
845 else
846 /* checking group name */
847 return -1;
848 if (ch)
849 p[-1] = ch;
850 s = p;
853 return 0;
857 * Generic ACL Manager:
859 * This handles acladd and aclchg identical.
860 * With 2 or 4 parameters, the second parameter is a password.
861 * With 3 or 4 parameters the last two parameters specify the permissions
862 * else user is added with full permissions.
863 * With 1 parameter the users permissions are copied from user *argv.
864 * Unlike the other cases, u->u_name should not match *argv here.
865 * uu should be NULL, except if you want to change his umask.
867 static int
868 UserAcl(uu, u, argc, argv)
869 struct acluser *uu, **u;
870 int argc;
871 char **argv;
873 if ((*u && !strcmp((*u)->u_name, "nobody")) ||
874 (argc > 1 && !strcmp(argv[0], "nobody")))
875 return -1; /* do not change nobody! */
877 switch (argc)
879 case 1+1+2:
880 debug2("UserAcl: user '%s', password '%s':", argv[0], argv[1]);
881 return (UserAdd(argv[0], argv[1], u) < 0) ||
882 AclSetPerm(uu, *u, argv[2], argv[3]);
883 case 1+2:
884 debug1("UserAcl: user '%s', no password:", argv[0]);
885 return (UserAdd(argv[0], NULL, u) < 0) ||
886 AclSetPerm(uu, *u, argv[1], argv[2]);
887 case 1+1:
888 debug2("UserAcl: user '%s', password '%s'\n", argv[0], argv[1]);
889 return UserAdd(argv[0], argv[1], u) < 0;
890 case 1:
891 debug1("UserAcl: user '%s', no password:", argv[0]);
892 return (UserAdd(argv[0], NULL, u) < 0) ||
893 AclSetPerm(uu, *u, "+a", "#?");
894 default:
895 return -1;
899 static int
900 UserAclCopy(to_up, from_up)
901 struct acluser **to_up, **from_up;
903 struct win *w;
904 int i, j, to_id, from_id;
906 if (!*to_up || !*from_up)
907 return -1;
908 debug2("UserAclCopy: from user '%s' to user '%s'\n",
909 (*from_up)->u_name, (*to_up)->u_name);
910 if ((to_id = (*to_up)->u_id) == (from_id = (*from_up)->u_id))
911 return -1;
912 for (w = windows; w; w = w->w_next)
914 for (i = 0; i < ACL_BITS_PER_WIN; i++)
916 if (ACLBYTE(w->w_userbits[i], from_id) & ACLBIT(from_id))
917 ACLBYTE(w->w_userbits[i], to_id) |= ACLBIT(to_id);
918 else
920 ACLBYTE(w->w_userbits[i], to_id) &= ~ACLBIT(to_id);
921 if ((w->w_wlockuser == *to_up) && (i == ACL_WRITE))
923 debug2("%s lost wlock on win %d\n",
924 (*to_up)->u_name, w->w_number);
925 w->w_wlockuser = NULL;
926 if (w->w_wlock == WLOCK_ON)
927 w->w_wlock = WLOCK_AUTO;
932 for (j = 0; j <= RC_LAST; j++)
934 for (i = 0; i < ACL_BITS_PER_CMD; i++)
936 if (ACLBYTE(comms[j].userbits[i], from_id) & ACLBIT(from_id))
937 ACLBYTE(comms[j].userbits[i], to_id) |= ACLBIT(to_id);
938 else
939 ACLBYTE(comms[j].userbits[i], to_id) &= ~ACLBIT(to_id);
943 return 0;
947 * Syntax:
948 * user [password] [+rwx #?]
949 * * [password] [+rwx #?]
950 * user1,user2,user3 [password] [+rwx #?]
951 * user1,user2,user3=user
952 * uu should be NULL, except if you want to change his umask.
955 UsersAcl(uu, argc, argv)
956 struct acluser *uu;
957 int argc;
958 char **argv;
960 char *s;
961 int r;
962 struct acluser **cf_u = NULL;
964 if (argc == 1)
966 char *p = NULL;
968 s = argv[0];
969 while (*s)
970 if (*s++ == '=') p = s;
971 if (p)
973 p[-1] = '\0';
974 cf_u = FindUserPtr(p);
978 if (argv[0][0] == '*' && argv[0][1] == '\0')
980 struct acluser **u;
982 debug("all users acls.\n");
983 for (u = &users; *u; u = &(*u)->u_next)
984 if (strcmp("nobody", (*u)->u_name) &&
985 ((cf_u) ?
986 ((r = UserAclCopy(u, cf_u)) < 0) :
987 ((r = UserAcl(uu, u, argc, argv)) < 0)))
988 return -1;
989 return 0;
994 for (s = argv[0]; *s && *s!=' ' && *s!='\t' && *s!=',' && *s!='='; s++)
996 *s ? (*s++ = '\0') : (*s = '\0');
997 debug2("UsersAcl(uu, \"%s\", argc=%d)\n", argv[0], argc);
998 if ((cf_u) ?
999 ((r = UserAclCopy(FindUserPtr(argv[0]), cf_u)) < 0) :
1000 ((r = UserAcl(uu, FindUserPtr(argv[0]), argc, argv)) < 0))
1001 return -1;
1002 } while (*(argv[0] = s));
1003 return 0;
1007 * Preprocess argments, so that umask can be set with UsersAcl
1009 * all current users umask ±rwxn
1010 * one specific user umask user1±rwxn
1011 * several users umask user1,user2,...±rwxn
1012 * default_w_bits umask ?±rwxn
1013 * default_c_bits umask ??±rwxn
1015 int
1016 AclUmask(u, str, errp)
1017 struct acluser *u;
1018 char *str;
1019 char **errp;
1021 char mode[16];
1022 char *av[3];
1023 char *p, c = '\0';
1025 /* split str into user and bits section. */
1026 for (p = str; *p; p++)
1027 if ((c = *p) == '+' || c == '-')
1028 break;
1029 if (!*p)
1031 *errp = "Bad argument. Should be ``[user[,user...]{+|-}rwxn''.";
1032 return -1;
1034 strncpy(mode, p, 15);
1035 mode[15] = '\0';
1036 *p = '\0';
1038 /* construct argument vector */
1039 if (!strcmp("??", str))
1041 str++;
1042 av[2] = "?";
1044 else
1045 av[2] = "#";
1046 av[1] = mode;
1047 av[0] = *str ? str : "*";
1048 /* call UsersAcl */
1049 if (UsersAcl(u, 3, av))
1051 *errp = "UsersAcl failed. Hmmm.";
1052 *p = c;
1053 return -1;
1055 *p = c;
1056 return 0;
1059 void
1060 AclWinSwap(a, b)
1061 int a, b;
1063 debug2("AclWinSwap(%d, %d) NOP.\n", a, b);
1066 struct acluser *EffectiveAclUser = NULL; /* hook for AT command permission */
1068 int
1069 AclCheckPermWin(u, mode, w)
1070 struct acluser *u;
1071 int mode;
1072 struct win *w;
1074 int ok;
1076 if (mode < 0 || mode >= ACL_BITS_PER_WIN)
1077 return -1;
1078 if (EffectiveAclUser)
1080 debug1("AclCheckPermWin: WARNING user %s overridden!\n", u->u_name);
1081 u = EffectiveAclUser;
1083 ok = ACLBYTE(w->w_userbits[mode], u->u_id) & ACLBIT(u->u_id);
1084 debug3("AclCheckPermWin(%s, %d, %d) = ", u->u_name, mode, w->w_number);
1086 if (!ok)
1088 struct aclusergroup **g = &u->u_group;
1089 struct acluser *saved_eff = EffectiveAclUser;
1091 EffectiveAclUser = NULL;
1092 while (*g)
1094 if (!AclCheckPermWin((*g)->u, mode, w))
1095 break;
1096 g = &(*g)->next;
1098 EffectiveAclUser = saved_eff;
1099 if (*g)
1100 ok = 1;
1102 debug1("%d\n", !ok);
1103 return !ok;
1106 int
1107 AclCheckPermCmd(u, mode, c)
1108 struct acluser *u;
1109 int mode;
1110 struct comm *c;
1112 int ok;
1114 if (mode < 0 || mode >= ACL_BITS_PER_CMD)
1115 return -1;
1116 if (EffectiveAclUser)
1118 debug1("AclCheckPermCmd: WARNING user %s overridden!\n", u->u_name);
1119 u = EffectiveAclUser;
1121 ok = ACLBYTE(c->userbits[mode], u->u_id) & ACLBIT(u->u_id);
1122 debug3("AclCheckPermCmd(%s %d %s) = ", u->u_name, mode, c->name);
1123 if (!ok)
1125 struct aclusergroup **g = &u->u_group;
1126 struct acluser *saved_eff = EffectiveAclUser;
1128 EffectiveAclUser = NULL;
1129 while (*g)
1131 if (!AclCheckPermCmd((*g)->u, mode, c))
1132 break;
1133 g = &(*g)->next;
1135 EffectiveAclUser = saved_eff;
1136 if (*g)
1137 ok = 1;
1139 debug1("%d\n", !ok);
1140 return !ok;
1143 #endif /* MULTIUSER */