Get rid of compile-time warnings.
[screen-lua.git] / src / acls.c
blobe728bb83617eae05174c37547cfea44c19482d40
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 "config.h"
31 #include <sys/types.h>
33 /* XXX: WHY IS THIS HERE?? :XXX */
35 #ifdef CHECKLOGIN
36 # ifdef _SEQUENT_
37 # include <stdio.h> /* needed by <pwd.h> */
38 # endif /* _SEQUENT_ */
39 # include <pwd.h>
40 # ifdef SHADOWPW
41 # include <shadow.h>
42 # endif /* SHADOWPW */
43 #endif /* CHECKLOGIN */
45 #ifndef NOSYSLOG
46 # include <syslog.h>
47 #endif
49 #include "screen.h" /* includes acls.h */
50 #include "extern.h"
53 /************************************************************************
54 * user managing code, this does not really belong into the acl stuff *
55 ************************************************************************/
57 extern struct comm comms[];
58 extern struct win *windows, **wtab;
59 extern char NullStr[];
60 extern char SockPath[];
61 extern struct display *display, *displays;
62 struct acluser *users;
64 #ifdef MULTIUSER
65 int maxusercount = 0; /* used in process.c: RC_MONITOR, RC_SILENCE */
67 /* record given user ids here */
68 static AclBits userbits;
71 * rights a new unknown user will have on windows and cmds.
72 * These are changed by a "umask ?-..." command:
74 static char default_w_bit[ACL_BITS_PER_WIN] =
76 1, /* EXEC */
77 1, /* WRITE */
78 1 /* READ */
81 static char default_c_bit[ACL_BITS_PER_CMD] =
83 0 /* EXEC */
86 /* rights of all users per newly created window */
88 * are now stored per user (umask)
89 * static AclBits default_w_userbits[ACL_BITS_PER_WIN];
90 * static AclBits default_c_userbits[ACL_BITS_PER_CMD];
93 static int GrowBitfield __P((AclBits *, int, int, int));
94 static struct aclusergroup **FindGroupPtr __P((struct aclusergroup **, struct acluser *, int));
95 static int AclSetPermCmd __P((struct acluser *, char *, struct comm *));
96 static int AclSetPermWin __P((struct acluser *, struct acluser *, char *, struct win *));
97 static int UserAcl __P((struct acluser *, struct acluser **, int, char **));
98 static int UserAclCopy __P((struct acluser **, struct acluser **));
101 static int
102 GrowBitfield(bfp, len, delta, defaultbit)
103 AclBits *bfp;
104 int len, delta, defaultbit;
106 AclBits n, o = *bfp;
107 int i;
109 if (!(n = (AclBits)calloc(1, (unsigned long)(&ACLBYTE((char *)0, len + delta + 1)))))
110 return -1;
111 for (i = 0; i < (len + delta); i++)
113 if (((i < len) && (ACLBIT(i) & ACLBYTE(o, i))) ||
114 ((i >= len) && (defaultbit)))
115 ACLBYTE(n, i) |= ACLBIT(i);
117 if (len)
118 free((char *)o);
119 *bfp = n;
120 return 0;
123 #endif /* MULTIUSER */
126 * Returns an nonzero Address. Its contents is either a User-ptr,
127 * or NULL which may be replaced by a User-ptr to create the entry.
129 struct acluser **
130 FindUserPtr(name)
131 char *name;
133 struct acluser **u;
135 for (u = &users; *u; u = &(*u)->u_next)
136 if (!strcmp((*u)->u_name, name))
137 break;
138 #ifdef MULTIUSER
139 debug3("FindUserPtr %s %sfound, id %d\n", name, (*u)?"":"not ",
140 (*u)?(*u)->u_id:-1);
141 #else /* MULTIUSER */
142 debug2("FindUserPtr %s %sfound\n", name, (*u)?"":"not ");
143 #endif /* MULTIUSER */
144 return u;
147 int DefaultEsc = -1; /* initialised by screen.c:main() */
148 int DefaultMetaEsc = -1;
151 * Add a new user. His password may be NULL or "" if none. His name must not
152 * be "none", as this represents the NULL-pointer when dealing with groups.
153 * He has default rights, determined by umask.
156 UserAdd(name, pass, up)
157 char *name, *pass;
158 struct acluser **up;
160 #ifdef MULTIUSER
161 int j;
162 #endif
164 if (!up)
165 up = FindUserPtr(name);
166 if (*up)
168 if (pass)
169 (*up)->u_password = SaveStr(pass);
170 return 1; /* he is already there */
172 if (strcmp("none", name)) /* "none" is a reserved word */
173 *up = (struct acluser *)calloc(1, sizeof(struct acluser));
174 if (!*up)
175 return -1; /* he still does not exist */
176 #ifdef COPY_PASTE
177 (*up)->u_plop.buf = NULL;
178 (*up)->u_plop.len = 0;
179 # ifdef ENCODINGS
180 (*up)->u_plop.enc = 0;
181 # endif
182 #endif
183 (*up)->u_Esc = DefaultEsc;
184 (*up)->u_MetaEsc = DefaultMetaEsc;
185 strncpy((*up)->u_name, name, 20);
186 (*up)->u_password = NULL;
187 if (pass)
188 (*up)->u_password = SaveStr(pass);
189 if (!(*up)->u_password)
190 (*up)->u_password = NullStr;
191 (*up)->u_detachwin = -1;
192 (*up)->u_detachotherwin = -1;
194 #ifdef MULTIUSER
195 (*up)->u_group = NULL;
196 /* now find an unused index */
197 for ((*up)->u_id = 0; (*up)->u_id < maxusercount; (*up)->u_id++)
198 if (!(ACLBIT((*up)->u_id) & ACLBYTE(userbits, (*up)->u_id)))
199 break;
200 debug2("UserAdd %s id %d\n", name, (*up)->u_id);
201 if ((*up)->u_id == maxusercount)
203 int j;
204 struct win *w;
205 struct acluser *u;
207 debug2("growing all bitfields %d += %d\n", maxusercount, USER_CHUNK);
208 /* the bitfields are full, grow a chunk */
209 /* first, the used_uid_indicator: */
210 if (GrowBitfield(&userbits, maxusercount, USER_CHUNK, 0))
212 free((char *)*up); *up = NULL; return -1;
214 /* second, default command bits */
215 /* (only if we generate commands dynamically) */
217 for (j = 0; j < ACL_BITS_PER_CMD; j++)
218 if (GrowBitfield(&default_c_userbits[j], maxusercount, USER_CHUNK,
219 default_c_bit[j]))
221 free((char *)*up); *up = NULL; return -1;
224 /* third, the bits for each commands */
225 for (j = 0; j <= RC_LAST; j++)
227 int i;
229 for (i = 0; i < ACL_BITS_PER_CMD; i++)
230 if (GrowBitfield(&comms[j].userbits[i], maxusercount, USER_CHUNK,
231 default_c_bit[i]))
233 free((char *)*up); *up = NULL; return -1;
236 /* fourth, default window creation bits per user */
237 for (u = users; u != *up; u = u->u_next)
239 for (j = 0; j < ACL_BITS_PER_WIN; j++)
241 if (GrowBitfield(&u->u_umask_w_bits[j], maxusercount, USER_CHUNK,
242 default_w_bit[j]))
244 free((char *)*up); *up = NULL; return -1;
249 /* fifth, the bits for each window */
250 /* keep these in sync with NewWindowAcl() */
251 for (w = windows; w; w = w->w_next)
253 /* five a: the access control list */
254 for (j = 0; j < ACL_BITS_PER_WIN; j++)
255 if (GrowBitfield(&w->w_userbits[j], maxusercount, USER_CHUNK,
256 default_w_bit[j]))
258 free((char *)*up); *up = NULL; return -1;
260 /* five b: the activity notify list */
261 /* five c: the silence notify list */
262 if (GrowBitfield(&w->w_mon_notify, maxusercount, USER_CHUNK, 0) ||
263 GrowBitfield(&w->w_lio_notify, maxusercount, USER_CHUNK, 0))
265 free((char *)*up); *up = NULL; return -1;
268 maxusercount += USER_CHUNK;
271 /* mark the user-entry as "in-use" */
272 ACLBYTE(userbits, (*up)->u_id) |= ACLBIT((*up)->u_id);
274 /* user id 0 is the session creator, he has all rights */
275 if ((*up)->u_id == 0)
276 AclSetPerm(NULL, *up, "+a", "#?");
278 /* user nobody has a fixed set of rights: */
279 if (!strcmp((*up)->u_name, "nobody"))
281 AclSetPerm(NULL, *up, "-rwx", "#?");
282 AclSetPerm(NULL, *up, "+x", "su");
283 AclSetPerm(NULL, *up, "+x", "detach");
284 AclSetPerm(NULL, *up, "+x", "displays");
285 AclSetPerm(NULL, *up, "+x", "version");
289 * Create his umask:
290 * Give default_w_bit's for all users,
291 * but allow himself everything on "his" windows.
293 for (j = 0; j < ACL_BITS_PER_WIN; j++)
295 if (GrowBitfield(&(*up)->u_umask_w_bits[j], 0, maxusercount,
296 default_w_bit[j]))
298 free((char *)*up); *up = NULL; return -1;
300 ACLBYTE((*up)->u_umask_w_bits[j], (*up)->u_id) |= ACLBIT((*up)->u_id);
302 #else /* MULTIUSER */
303 debug1("UserAdd %s\n", name);
304 #endif /* MULTIUSER */
305 return 0;
308 #if 0
309 /* change user's password */
310 int
311 UserSetPass(name, pass, up)
312 char *name, *pass;
313 struct acluser **up;
315 if (!up)
316 up = FindUserPtr(name);
317 if (!*up)
318 return UserAdd(name, pass, up);
319 if (!strcmp(name, "nobody")) /* he remains without password */
320 return -1;
321 strncpy((*up)->u_password, pass ? pass : "", 20);
322 (*up)->u_password[20] = '\0';
323 return 0;
325 #endif
328 * Remove a user from the list.
329 * Destroy all his permissions and completely detach him from the session.
331 int
332 UserDel(name, up)
333 char *name;
334 struct acluser **up;
336 struct acluser *u;
337 #ifdef MULTIUSER
338 int i;
339 #endif
340 struct display *old, *next;
342 if (!up)
343 up = FindUserPtr(name);
344 if (!(u = *up))
345 return -1; /* he who does not exist cannot be removed */
346 old = display;
347 for (display = displays; display; display = next)
349 next = display->d_next; /* read the next ptr now, Detach may zap it. */
350 if (D_user != u)
351 continue;
352 if (display == old)
353 old = NULL;
354 Detach(D_REMOTE);
356 display = old;
357 *up = u->u_next;
359 #ifdef MULTIUSER
360 for (up = &users; *up; up = &(*up)->u_next)
362 /* unlink all group references to this user */
363 struct aclusergroup **g = &(*up)->u_group;
365 while (*g)
367 if ((*g)->u == u)
369 struct aclusergroup *next = (*g)->next;
371 free((char *)(*g));
372 *g = next;
374 else
375 g = &(*g)->next;
378 ACLBYTE(userbits, u->u_id) &= ~ACLBIT(u->u_id);
379 /* restore the bits in his slot to default: */
380 AclSetPerm(NULL, u, default_w_bit[ACL_READ] ? "+r" : "-r", "#");
381 AclSetPerm(NULL, u, default_w_bit[ACL_WRITE]? "+w" : "-w", "#");
382 AclSetPerm(NULL, u, default_w_bit[ACL_EXEC] ? "+x" : "-x", "#");
383 AclSetPerm(NULL, u, default_c_bit[ACL_EXEC] ? "+x" : "-x", "?");
384 for (i = 0; i < ACL_BITS_PER_WIN; i++)
385 free((char *)u->u_umask_w_bits[i]);
386 #endif /* MULTIUSER */
387 debug1("FREEING user structure for %s\n", u->u_name);
388 #ifdef COPY_PASTE
389 UserFreeCopyBuffer(u);
390 #endif
391 free((char *)u);
392 if (!users)
394 debug("Last user deleted. Feierabend.\n");
395 Finit(0); /* Destroying whole session. Noone could ever attach again. */
397 return 0;
401 #ifdef COPY_PASTE
404 * returns 0 if the copy buffer was really deleted.
405 * Also removes any references into the users copybuffer
408 UserFreeCopyBuffer(u)
409 struct acluser *u;
411 struct win *w;
412 struct paster *pa;
414 if (!u->u_plop.buf)
415 return 1;
416 for (w = windows; w; w = w->w_next)
418 pa = &w->w_paster;
419 if (pa->pa_pasteptr >= u->u_plop.buf &&
420 pa->pa_pasteptr - u->u_plop.buf < u->u_plop.len)
421 FreePaster(pa);
423 free((char *)u->u_plop.buf);
424 u->u_plop.len = 0;
425 u->u_plop.buf = 0;
426 return 0;
428 #endif /* COPY_PASTE */
430 #ifdef MULTIUSER
432 * Traverses group nodes. It searches for a node that references user u.
433 * If recursive is true, nodes found in the users are also searched using
434 * depth first method. If none of the nodes references u, the address of
435 * the last next pointer is returned. This address will contain NULL.
437 static struct aclusergroup **
438 FindGroupPtr(gp, u, recursive)
439 struct aclusergroup **gp;
440 struct acluser *u;
441 int recursive;
443 struct aclusergroup **g;
445 ASSERT(recursive < 1000); /* Ouch, cycle detection failed */
446 while (*gp)
448 if ((*gp)->u == u)
449 return gp; /* found him here. */
450 if (recursive &&
451 *(g = FindGroupPtr(&(*gp)->u->u_group, u, recursive + 1)))
452 return g; /* found him there. */
453 gp = &(*gp)->next;
455 return gp; /* *gp is NULL */
459 * Returns nonzero if failed or already linked.
460 * Both users are created on demand.
461 * Cyclic links are prevented.
464 AclLinkUser(from, to)
465 char *from, *to;
467 struct acluser **u1, **u2;
468 struct aclusergroup **g;
470 if (!*(u1 = FindUserPtr(from)) && UserAdd(from, NULL, u1))
471 return -1;
472 if (!*(u2 = FindUserPtr(to)) && UserAdd(to, NULL, u2))
473 return -1; /* hmm, could not find both users. */
475 if (*FindGroupPtr(&(*u2)->u_group, *u1, 1))
476 return 1; /* cyclic link detected! */
477 if (*(g = FindGroupPtr(&(*u1)->u_group, *u2, 0)))
478 return 2; /* aha, we are already linked! */
480 if (!(*g = (struct aclusergroup *)malloc(sizeof(struct aclusergroup))))
481 return -1; /* Could not alloc link. Poor screen */
482 (*g)->u = (*u2);
483 (*g)->next = NULL;
484 return 0;
488 * The user pointer stored at *up will be substituted by a pointer
489 * to the named user's structure, if passwords match.
490 * returns NULL if successfull, an static error string otherwise
492 char *
493 DoSu(up, name, pw1, pw2)
494 struct acluser **up;
495 char *name, *pw1, *pw2;
497 struct acluser *u;
498 int sorry = 0;
500 if (!(u = *FindUserPtr(name)))
501 sorry++;
502 else
504 #ifdef CHECKLOGIN
505 struct passwd *pp;
506 #ifdef SHADOWPW
507 struct spwd *ss;
508 int t, c;
509 #endif
510 char *pass = "";
512 if (!(pp = getpwnam(name)))
514 debug1("getpwnam(\"%s\") failed\n", name);
515 if (!(pw1 && *pw1 && *pw1 != '\377'))
517 debug("no unix account, no screen passwd\n");
518 sorry++;
521 else
522 pass = pp->pw_passwd;
523 #ifdef SHADOWPW
524 for (t = 0; t < 13; t++)
526 c = pass[t];
527 if (!(c == '.' || c == '/' ||
528 (c >= '0' && c <= '9') ||
529 (c >= 'a' && c <= 'z') ||
530 (c >= 'A' && c <= 'Z')))
531 break;
533 if (t < 13)
535 if (!(ss = getspnam(name)))
537 debug1("getspnam(\"%s\") failed\n", name);
538 sorry++;
540 else
541 pass = ss->sp_pwdp;
543 #endif /* SHADOWPW */
545 if (pw2 && *pw2 && *pw2 != '\377') /* provided a system password */
547 if (!*pass || /* but needed none */
548 strcmp(crypt(pw2, pass), pass))
550 debug("System password mismatch\n");
551 sorry++;
554 else /* no pasword provided */
555 if (*pass) /* but need one */
556 sorry++;
557 #endif
558 if (pw1 && *pw1 && *pw1 != '\377') /* provided a screen password */
560 if (!*u->u_password || /* but needed none */
561 strcmp(crypt(pw1, u->u_password), u->u_password))
563 debug("screen password mismatch\n");
564 sorry++;
567 else /* no pasword provided */
568 if (*u->u_password) /* but need one */
569 sorry++;
572 debug2("syslog(LOG_NOTICE, \"screen %s: \"su %s\" ", SockPath, name);
573 debug2("%s for \"%s\"\n", sorry ? "failed" : "succeded", (*up)->u_name);
574 #ifndef NOSYSLOG
575 # ifdef BSD_42
576 openlog("screen", LOG_PID);
577 # else
578 openlog("screen", LOG_PID, LOG_AUTH);
579 # endif /* BSD_42 */
580 syslog(LOG_NOTICE, "%s: \"su %s\" %s for \"%s\"", SockPath, name,
581 sorry ? "failed" : "succeded", (*up)->u_name);
582 closelog();
583 #else
584 debug("NOT LOGGED.\n");
585 #endif /* NOSYSLOG */
587 if (sorry)
588 return "Sorry.";
589 else
590 *up = u; /* substitute user now */
591 return NULL;
593 #endif /* MULTIUSER */
595 /************************************************************************
596 * end of user managing code *
597 ************************************************************************/
600 #ifdef MULTIUSER
602 /* This gives the users default rights to the new window w created by u */
604 NewWindowAcl(w, u)
605 struct win *w;
606 struct acluser *u;
608 int i, j;
610 debug2("NewWindowAcl %s's umask_w_bits for window %d\n",
611 u ? u->u_name : "everybody", w->w_number);
613 /* keep these in sync with UserAdd part five. */
614 if (GrowBitfield(&w->w_mon_notify, 0, maxusercount, 0) ||
615 GrowBitfield(&w->w_lio_notify, 0, maxusercount, 0))
616 return -1;
617 for (j = 0; j < ACL_BITS_PER_WIN; j++)
619 /* we start with len 0 for the new bitfield size and add maxusercount */
620 if (GrowBitfield(&w->w_userbits[j], 0, maxusercount, 0))
622 while (--j >= 0)
623 free((char *)w->w_userbits[j]);
624 free((char *)w->w_mon_notify);
625 free((char *)w->w_lio_notify);
626 return -1;
628 for (i = 0; i < maxusercount; i++)
629 if (u ? (ACLBIT(i) & ACLBYTE(u->u_umask_w_bits[j], i)) :
630 default_w_bit[j])
631 ACLBYTE(w->w_userbits[j], i) |= ACLBIT(i);
633 return 0;
636 void
637 FreeWindowAcl(w)
638 struct win *w;
640 int i;
642 for (i = 0; i < ACL_BITS_PER_WIN; i++)
643 free((char *)w->w_userbits[i]);
644 free((char *)w->w_mon_notify);
645 free((char *)w->w_lio_notify);
649 /* if mode starts with '-' we remove the users exec bit for cmd */
651 * NOTE: before you make this function look the same as
652 * AclSetPermWin, try to merge both functions.
654 static int
655 AclSetPermCmd(u, mode, cmd)
656 struct acluser *u;
657 char *mode;
658 struct comm *cmd;
660 int neg = 0;
661 char *m = mode;
663 while (*m)
665 switch (*m++)
667 case '-':
668 neg = 1;
669 continue;
670 case '+':
671 neg = 0;
672 continue;
673 case 'a':
674 case 'e':
675 case 'x':
676 /* debug3("AclSetPermCmd %s %s %s\n", u->u_name, mode, cmd->name); */
677 if (neg)
678 ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) &= ~ACLBIT(u->u_id);
679 else
680 ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) |= ACLBIT(u->u_id);
681 break;
682 case 'r':
683 case 'w':
684 break;
685 default:
686 return -1;
689 return 0;
692 /* mode strings of the form +rwx -w+rx r -wx are parsed and evaluated */
694 * aclchg nerd -w+w 2
695 * releases a writelock on window 2 held by user nerd.
696 * Letter n allows network access on a window.
697 * uu should be NULL, except if you want to change his umask.
699 static int
700 AclSetPermWin(uu, u, mode, win)
701 struct acluser *u, *uu;
702 char *mode;
703 struct win *win;
705 int neg = 0;
706 int bit, bits;
707 AclBits *bitarray;
708 char *m = mode;
710 if (uu)
712 debug3("AclSetPermWin %s UMASK %s %s\n", uu->u_name, u->u_name, mode);
713 bitarray = uu->u_umask_w_bits;
715 else
717 ASSERT(win);
718 bitarray = win->w_userbits;
719 debug3("AclSetPermWin %s %s %d\n", u->u_name, mode, win->w_number);
722 while (*m)
724 switch (*m++)
726 case '-':
727 neg = 1;
728 continue;
729 case '+':
730 neg = 0;
731 continue;
732 case 'r':
733 bits = (1 << ACL_READ);
734 break;
735 case 'w':
736 bits = (1 << ACL_WRITE);
737 break;
738 case 'x':
739 bits = (1 << ACL_EXEC);
740 break;
741 case 'a':
742 bits = (1 << ACL_BITS_PER_WIN) - 1;
743 break;
744 default:
745 return -1;
747 for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
749 if (!(bits & (1 << bit)))
750 continue;
751 if (neg)
752 ACLBYTE(bitarray[bit], u->u_id) &= ~ACLBIT(u->u_id);
753 else
754 ACLBYTE(bitarray[bit], u->u_id) |= ACLBIT(u->u_id);
755 if (!uu && (win->w_wlockuser == u) && neg && (bit == ACL_WRITE))
757 debug2("%s lost writelock on win %d\n", u->u_name, win->w_number);
758 win->w_wlockuser = NULL;
759 if (win->w_wlock == WLOCK_ON)
760 win->w_wlock = WLOCK_AUTO;
764 if (uu && u->u_name[0] == '?' && u->u_name[1] == '\0')
767 * It is Mr. '?', the unknown user. He deserves special treatment as
768 * he defines the defaults. Sorry, this is global, not per user.
770 if (win)
772 debug1("AclSetPermWin: default_w_bits '%s'.\n", mode);
773 for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
774 default_w_bit[bit] =
775 (ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0;
777 else
780 * Hack. I do not want to duplicate all the above code for
781 * AclSetPermCmd. This asumes that there are not more bits
782 * per cmd than per win.
784 debug1("AclSetPermWin: default_c_bits '%s'.\n", mode);
785 for (bit = 0; bit < ACL_BITS_PER_CMD; bit++)
786 default_c_bit[bit] =
787 (ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0;
789 UserDel(u->u_name, NULL);
791 return 0;
795 * String is broken down into comand and window names, mode applies
796 * A command name matches first, so do not use these as window names.
797 * uu should be NULL, except if you want to change his umask.
800 AclSetPerm(uu, u, mode, s)
801 struct acluser *uu, *u;
802 char *mode, *s;
804 struct win *w;
805 int i;
806 char *p, ch;
808 debug3("AclSetPerm(uu, user '%s', mode '%s', object '%s')\n",
809 u->u_name, mode, s);
810 while (*s)
812 switch (*s)
814 case '*': /* all windows and all commands */
815 return AclSetPerm(uu, u, mode, "#?");
816 case '#':
817 if (uu) /* window umask or .. */
818 AclSetPermWin(uu, u, mode, (struct win *)1);
819 else /* .. or all windows */
820 for (w = windows; w; w = w->w_next)
821 AclSetPermWin((struct acluser *)0, u, mode, w);
822 s++;
823 break;
824 case '?':
825 if (uu) /* command umask or .. */
826 AclSetPermWin(uu, u, mode, (struct win *)0);
827 else /* .. or all commands */
828 for (i = 0; i <= RC_LAST; i++)
829 AclSetPermCmd(u, mode, &comms[i]);
830 s++;
831 break;
832 default:
833 for (p = s; *p && *p != ' ' && *p != '\t' && *p != ','; p++)
835 if ((ch = *p))
836 *p++ = '\0';
837 if ((i = FindCommnr(s)) != RC_ILLEGAL)
838 AclSetPermCmd(u, mode, &comms[i]);
839 else if (((i = WindowByNoN(s)) >= 0) && wtab[i])
840 AclSetPermWin((struct acluser *)0, u, mode, wtab[i]);
841 else
842 /* checking group name */
843 return -1;
844 if (ch)
845 p[-1] = ch;
846 s = p;
849 return 0;
853 * Generic ACL Manager:
855 * This handles acladd and aclchg identical.
856 * With 2 or 4 parameters, the second parameter is a password.
857 * With 3 or 4 parameters the last two parameters specify the permissions
858 * else user is added with full permissions.
859 * With 1 parameter the users permissions are copied from user *argv.
860 * Unlike the other cases, u->u_name should not match *argv here.
861 * uu should be NULL, except if you want to change his umask.
863 static int
864 UserAcl(uu, u, argc, argv)
865 struct acluser *uu, **u;
866 int argc;
867 char **argv;
869 if ((*u && !strcmp((*u)->u_name, "nobody")) ||
870 (argc > 1 && !strcmp(argv[0], "nobody")))
871 return -1; /* do not change nobody! */
873 switch (argc)
875 case 1+1+2:
876 debug2("UserAcl: user '%s', password '%s':", argv[0], argv[1]);
877 return (UserAdd(argv[0], argv[1], u) < 0) ||
878 AclSetPerm(uu, *u, argv[2], argv[3]);
879 case 1+2:
880 debug1("UserAcl: user '%s', no password:", argv[0]);
881 return (UserAdd(argv[0], NULL, u) < 0) ||
882 AclSetPerm(uu, *u, argv[1], argv[2]);
883 case 1+1:
884 debug2("UserAcl: user '%s', password '%s'\n", argv[0], argv[1]);
885 return UserAdd(argv[0], argv[1], u) < 0;
886 case 1:
887 debug1("UserAcl: user '%s', no password:", argv[0]);
888 return (UserAdd(argv[0], NULL, u) < 0) ||
889 AclSetPerm(uu, *u, "+a", "#?");
890 default:
891 return -1;
895 static int
896 UserAclCopy(to_up, from_up)
897 struct acluser **to_up, **from_up;
899 struct win *w;
900 int i, j, to_id, from_id;
902 if (!*to_up || !*from_up)
903 return -1;
904 debug2("UserAclCopy: from user '%s' to user '%s'\n",
905 (*from_up)->u_name, (*to_up)->u_name);
906 if ((to_id = (*to_up)->u_id) == (from_id = (*from_up)->u_id))
907 return -1;
908 for (w = windows; w; w = w->w_next)
910 for (i = 0; i < ACL_BITS_PER_WIN; i++)
912 if (ACLBYTE(w->w_userbits[i], from_id) & ACLBIT(from_id))
913 ACLBYTE(w->w_userbits[i], to_id) |= ACLBIT(to_id);
914 else
916 ACLBYTE(w->w_userbits[i], to_id) &= ~ACLBIT(to_id);
917 if ((w->w_wlockuser == *to_up) && (i == ACL_WRITE))
919 debug2("%s lost wlock on win %d\n",
920 (*to_up)->u_name, w->w_number);
921 w->w_wlockuser = NULL;
922 if (w->w_wlock == WLOCK_ON)
923 w->w_wlock = WLOCK_AUTO;
928 for (j = 0; j <= RC_LAST; j++)
930 for (i = 0; i < ACL_BITS_PER_CMD; i++)
932 if (ACLBYTE(comms[j].userbits[i], from_id) & ACLBIT(from_id))
933 ACLBYTE(comms[j].userbits[i], to_id) |= ACLBIT(to_id);
934 else
935 ACLBYTE(comms[j].userbits[i], to_id) &= ~ACLBIT(to_id);
939 return 0;
943 * Syntax:
944 * user [password] [+rwx #?]
945 * * [password] [+rwx #?]
946 * user1,user2,user3 [password] [+rwx #?]
947 * user1,user2,user3=user
948 * uu should be NULL, except if you want to change his umask.
951 UsersAcl(uu, argc, argv)
952 struct acluser *uu;
953 int argc;
954 char **argv;
956 char *s;
957 int r;
958 struct acluser **cf_u = NULL;
960 if (argc == 1)
962 char *p = NULL;
964 s = argv[0];
965 while (*s)
966 if (*s++ == '=') p = s;
967 if (p)
969 p[-1] = '\0';
970 cf_u = FindUserPtr(p);
974 if (argv[0][0] == '*' && argv[0][1] == '\0')
976 struct acluser **u;
978 debug("all users acls.\n");
979 for (u = &users; *u; u = &(*u)->u_next)
980 if (strcmp("nobody", (*u)->u_name) &&
981 ((cf_u) ?
982 ((r = UserAclCopy(u, cf_u)) < 0) :
983 ((r = UserAcl(uu, u, argc, argv)) < 0)))
984 return -1;
985 return 0;
990 for (s = argv[0]; *s && *s!=' ' && *s!='\t' && *s!=',' && *s!='='; s++)
992 *s ? (*s++ = '\0') : (*s = '\0');
993 debug2("UsersAcl(uu, \"%s\", argc=%d)\n", argv[0], argc);
994 if ((cf_u) ?
995 ((r = UserAclCopy(FindUserPtr(argv[0]), cf_u)) < 0) :
996 ((r = UserAcl(uu, FindUserPtr(argv[0]), argc, argv)) < 0))
997 return -1;
998 } while (*(argv[0] = s));
999 return 0;
1003 * Preprocess argments, so that umask can be set with UsersAcl
1005 * all current users umask ±rwxn
1006 * one specific user umask user1±rwxn
1007 * several users umask user1,user2,...±rwxn
1008 * default_w_bits umask ?±rwxn
1009 * default_c_bits umask ??±rwxn
1011 int
1012 AclUmask(u, str, errp)
1013 struct acluser *u;
1014 char *str;
1015 char **errp;
1017 char mode[16];
1018 char *av[3];
1019 char *p, c = '\0';
1021 /* split str into user and bits section. */
1022 for (p = str; *p; p++)
1023 if ((c = *p) == '+' || c == '-')
1024 break;
1025 if (!*p)
1027 *errp = "Bad argument. Should be ``[user[,user...]{+|-}rwxn''.";
1028 return -1;
1030 strncpy(mode, p, 15);
1031 mode[15] = '\0';
1032 *p = '\0';
1034 /* construct argument vector */
1035 if (!strcmp("??", str))
1037 str++;
1038 av[2] = "?";
1040 else
1041 av[2] = "#";
1042 av[1] = mode;
1043 av[0] = *str ? str : "*";
1044 /* call UsersAcl */
1045 if (UsersAcl(u, 3, av))
1047 *errp = "UsersAcl failed. Hmmm.";
1048 *p = c;
1049 return -1;
1051 *p = c;
1052 return 0;
1055 void
1056 AclWinSwap(a, b)
1057 int a, b;
1059 debug2("AclWinSwap(%d, %d) NOP.\n", a, b);
1062 struct acluser *EffectiveAclUser = NULL; /* hook for AT command permission */
1064 int
1065 AclCheckPermWin(u, mode, w)
1066 struct acluser *u;
1067 int mode;
1068 struct win *w;
1070 int ok;
1072 if (mode < 0 || mode >= ACL_BITS_PER_WIN)
1073 return -1;
1074 if (EffectiveAclUser)
1076 debug1("AclCheckPermWin: WARNING user %s overridden!\n", u->u_name);
1077 u = EffectiveAclUser;
1079 ok = ACLBYTE(w->w_userbits[mode], u->u_id) & ACLBIT(u->u_id);
1080 debug3("AclCheckPermWin(%s, %d, %d) = ", u->u_name, mode, w->w_number);
1082 if (!ok)
1084 struct aclusergroup **g = &u->u_group;
1085 struct acluser *saved_eff = EffectiveAclUser;
1087 EffectiveAclUser = NULL;
1088 while (*g)
1090 if (!AclCheckPermWin((*g)->u, mode, w))
1091 break;
1092 g = &(*g)->next;
1094 EffectiveAclUser = saved_eff;
1095 if (*g)
1096 ok = 1;
1098 debug1("%d\n", !ok);
1099 return !ok;
1102 int
1103 AclCheckPermCmd(u, mode, c)
1104 struct acluser *u;
1105 int mode;
1106 struct comm *c;
1108 int ok;
1110 if (mode < 0 || mode >= ACL_BITS_PER_CMD)
1111 return -1;
1112 if (EffectiveAclUser)
1114 debug1("AclCheckPermCmd: WARNING user %s overridden!\n", u->u_name);
1115 u = EffectiveAclUser;
1117 ok = ACLBYTE(c->userbits[mode], u->u_id) & ACLBIT(u->u_id);
1118 debug3("AclCheckPermCmd(%s %d %s) = ", u->u_name, mode, c->name);
1119 if (!ok)
1121 struct aclusergroup **g = &u->u_group;
1122 struct acluser *saved_eff = EffectiveAclUser;
1124 EffectiveAclUser = NULL;
1125 while (*g)
1127 if (!AclCheckPermCmd((*g)->u, mode, c))
1128 break;
1129 g = &(*g)->next;
1131 EffectiveAclUser = saved_eff;
1132 if (*g)
1133 ok = 1;
1135 debug1("%d\n", !ok);
1136 return !ok;
1139 #endif /* MULTIUSER */