Start converting to GPL v3+ (ref: ticket #23900)
[screen-lua.git] / src / acls.c
blob90e74f3121e8063ddb7eee696873c07549caa142
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
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 3, or (at your option)
9 * any later version.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, see
18 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 ****************************************************************
24 #include <sys/types.h>
26 #include "config.h"
29 /* XXX: WHY IS THIS HERE?? :XXX */
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 */
41 #ifndef NOSYSLOG
42 # include <syslog.h>
43 #endif
45 #include "screen.h" /* includes acls.h */
46 #include "extern.h"
49 /************************************************************************
50 * user managing code, this does not really belong into the acl stuff *
51 ************************************************************************/
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;
60 #ifdef MULTIUSER
61 int maxusercount = 0; /* used in process.c: RC_MONITOR, RC_SILENCE */
63 /* record given user ids here */
64 static AclBits userbits;
67 * rights a new unknown user will have on windows and cmds.
68 * These are changed by a "umask ?-..." command:
70 static char default_w_bit[ACL_BITS_PER_WIN] =
72 1, /* EXEC */
73 1, /* WRITE */
74 1 /* READ */
77 static char default_c_bit[ACL_BITS_PER_CMD] =
79 0 /* EXEC */
82 /* rights of all users per newly created window */
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];
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 **));
97 static int
98 GrowBitfield(bfp, len, delta, defaultbit)
99 AclBits *bfp;
100 int len, delta, defaultbit;
102 AclBits n, o = *bfp;
103 int i;
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++)
109 if (((i < len) && (ACLBIT(i) & ACLBYTE(o, i))) ||
110 ((i >= len) && (defaultbit)))
111 ACLBYTE(n, i) |= ACLBIT(i);
113 if (len)
114 free((char *)o);
115 *bfp = n;
116 return 0;
119 #endif /* MULTIUSER */
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.
125 struct acluser **
126 FindUserPtr(name)
127 char *name;
129 struct acluser **u;
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;
143 int DefaultEsc = -1; /* initialised by screen.c:main() */
144 int DefaultMetaEsc = -1;
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.
152 UserAdd(name, pass, up)
153 char *name, *pass;
154 struct acluser **up;
156 #ifdef MULTIUSER
157 int j;
158 #endif
160 if (!up)
161 up = FindUserPtr(name);
162 if (*up)
164 if (pass)
165 (*up)->u_password = SaveStr(pass);
166 return 1; /* he is already there */
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;
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)
199 int j;
200 struct win *w;
201 struct acluser *u;
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))
208 free((char *)*up); *up = NULL; return -1;
210 /* second, default command bits */
211 /* (only if we generate commands dynamically) */
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]))
217 free((char *)*up); *up = NULL; return -1;
220 /* third, the bits for each commands */
221 for (j = 0; j <= RC_LAST; j++)
223 int i;
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]))
229 free((char *)*up); *up = NULL; return -1;
232 /* fourth, default window creation bits per user */
233 for (u = users; u != *up; u = u->u_next)
235 for (j = 0; j < ACL_BITS_PER_WIN; j++)
237 if (GrowBitfield(&u->u_umask_w_bits[j], maxusercount, USER_CHUNK,
238 default_w_bit[j]))
240 free((char *)*up); *up = NULL; return -1;
245 /* fifth, the bits for each window */
246 /* keep these in sync with NewWindowAcl() */
247 for (w = windows; w; w = w->w_next)
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]))
254 free((char *)*up); *up = NULL; return -1;
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))
261 free((char *)*up); *up = NULL; return -1;
264 maxusercount += USER_CHUNK;
267 /* mark the user-entry as "in-use" */
268 ACLBYTE(userbits, (*up)->u_id) |= ACLBIT((*up)->u_id);
270 /* user id 0 is the session creator, he has all rights */
271 if ((*up)->u_id == 0)
272 AclSetPerm(NULL, *up, "+a", "#?");
274 /* user nobody has a fixed set of rights: */
275 if (!strcmp((*up)->u_name, "nobody"))
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");
285 * Create his umask:
286 * Give default_w_bit's for all users,
287 * but allow himself everything on "his" windows.
289 for (j = 0; j < ACL_BITS_PER_WIN; j++)
291 if (GrowBitfield(&(*up)->u_umask_w_bits[j], 0, maxusercount,
292 default_w_bit[j]))
294 free((char *)*up); *up = NULL; return -1;
296 ACLBYTE((*up)->u_umask_w_bits[j], (*up)->u_id) |= ACLBIT((*up)->u_id);
298 #else /* MULTIUSER */
299 debug1("UserAdd %s\n", name);
300 #endif /* MULTIUSER */
301 return 0;
304 #if 0
305 /* change user's password */
306 int
307 UserSetPass(name, pass, up)
308 char *name, *pass;
309 struct acluser **up;
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;
321 #endif
324 * Remove a user from the list.
325 * Destroy all his permissions and completely detach him from the session.
327 int
328 UserDel(name, up)
329 char *name;
330 struct acluser **up;
332 struct acluser *u;
333 #ifdef MULTIUSER
334 int i;
335 #endif
336 struct display *old, *next;
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)
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);
352 display = old;
353 *up = u->u_next;
355 #ifdef MULTIUSER
356 for (up = &users; *up; up = &(*up)->u_next)
358 /* unlink all group references to this user */
359 struct aclusergroup **g = &(*up)->u_group;
361 while (*g)
363 if ((*g)->u == u)
365 struct aclusergroup *next = (*g)->next;
367 free((char *)(*g));
368 *g = next;
370 else
371 g = &(*g)->next;
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)
390 debug("Last user deleted. Feierabend.\n");
391 Finit(0); /* Destroying whole session. Noone could ever attach again. */
393 return 0;
397 #ifdef COPY_PASTE
400 * returns 0 if the copy buffer was really deleted.
401 * Also removes any references into the users copybuffer
404 UserFreeCopyBuffer(u)
405 struct acluser *u;
407 struct win *w;
408 struct paster *pa;
410 if (!u->u_plop.buf)
411 return 1;
412 for (w = windows; w; w = w->w_next)
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);
419 free((char *)u->u_plop.buf);
420 u->u_plop.len = 0;
421 u->u_plop.buf = 0;
422 return 0;
424 #endif /* COPY_PASTE */
426 #ifdef MULTIUSER
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.
433 static struct aclusergroup **
434 FindGroupPtr(gp, u, recursive)
435 struct aclusergroup **gp;
436 struct acluser *u;
437 int recursive;
439 struct aclusergroup **g;
441 ASSERT(recursive < 1000); /* Ouch, cycle detection failed */
442 while (*gp)
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;
451 return gp; /* *gp is NULL */
455 * Returns nonzero if failed or already linked.
456 * Both users are created on demand.
457 * Cyclic links are prevented.
460 AclLinkUser(from, to)
461 char *from, *to;
463 struct acluser **u1, **u2;
464 struct aclusergroup **g;
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. */
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! */
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;
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
488 char *
489 DoSu(up, name, pw1, pw2)
490 struct acluser **up;
491 char *name, *pw1, *pw2;
493 struct acluser *u;
494 int sorry = 0;
496 if (!(u = *FindUserPtr(name)))
497 sorry++;
498 else
500 #ifdef CHECKLOGIN
501 struct passwd *pp;
502 #ifdef SHADOWPW
503 struct spwd *ss;
504 int t, c;
505 #endif
506 char *pass = "";
508 if (!(pp = getpwnam(name)))
510 debug1("getpwnam(\"%s\") failed\n", name);
511 if (!(pw1 && *pw1 && *pw1 != '\377'))
513 debug("no unix account, no screen passwd\n");
514 sorry++;
517 else
518 pass = pp->pw_passwd;
519 #ifdef SHADOWPW
520 for (t = 0; t < 13; t++)
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;
529 if (t < 13)
531 if (!(ss = getspnam(name)))
533 debug1("getspnam(\"%s\") failed\n", name);
534 sorry++;
536 else
537 pass = ss->sp_pwdp;
539 #endif /* SHADOWPW */
541 if (pw2 && *pw2 && *pw2 != '\377') /* provided a system password */
543 if (!*pass || /* but needed none */
544 strcmp(crypt(pw2, pass), pass))
546 debug("System password mismatch\n");
547 sorry++;
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 */
556 if (!*u->u_password || /* but needed none */
557 strcmp(crypt(pw1, u->u_password), u->u_password))
559 debug("screen password mismatch\n");
560 sorry++;
563 else /* no pasword provided */
564 if (*u->u_password) /* but need one */
565 sorry++;
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 */
583 if (sorry)
584 return "Sorry.";
585 else
586 *up = u; /* substitute user now */
587 return NULL;
589 #endif /* MULTIUSER */
591 /************************************************************************
592 * end of user managing code *
593 ************************************************************************/
596 #ifdef MULTIUSER
598 /* This gives the users default rights to the new window w created by u */
600 NewWindowAcl(w, u)
601 struct win *w;
602 struct acluser *u;
604 int i, j;
606 debug2("NewWindowAcl %s's umask_w_bits for window %d\n",
607 u ? u->u_name : "everybody", w->w_number);
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++)
615 /* we start with len 0 for the new bitfield size and add maxusercount */
616 if (GrowBitfield(&w->w_userbits[j], 0, maxusercount, 0))
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;
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);
629 return 0;
632 void
633 FreeWindowAcl(w)
634 struct win *w;
636 int i;
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);
645 /* if mode starts with '-' we remove the users exec bit for cmd */
647 * NOTE: before you make this function look the same as
648 * AclSetPermWin, try to merge both functions.
650 static int
651 AclSetPermCmd(u, mode, cmd)
652 struct acluser *u;
653 char *mode;
654 struct comm *cmd;
656 int neg = 0;
657 char *m = mode;
659 while (*m)
661 switch (*m++)
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;
685 return 0;
688 /* mode strings of the form +rwx -w+rx r -wx are parsed and evaluated */
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.
695 static int
696 AclSetPermWin(uu, u, mode, win)
697 struct acluser *u, *uu;
698 char *mode;
699 struct win *win;
701 int neg = 0;
702 int bit, bits;
703 AclBits *bitarray;
704 char *m = mode;
706 if (uu)
708 debug3("AclSetPermWin %s UMASK %s %s\n", uu->u_name, u->u_name, mode);
709 bitarray = uu->u_umask_w_bits;
711 else
713 ASSERT(win);
714 bitarray = win->w_userbits;
715 debug3("AclSetPermWin %s %s %d\n", u->u_name, mode, win->w_number);
718 while (*m)
720 switch (*m++)
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;
743 for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
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))
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;
760 if (uu && u->u_name[0] == '?' && u->u_name[1] == '\0')
763 * It is Mr. '?', the unknown user. He deserves special treatment as
764 * he defines the defaults. Sorry, this is global, not per user.
766 if (win)
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;
773 else
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.
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;
785 UserDel(u->u_name, NULL);
787 return 0;
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.
796 AclSetPerm(uu, u, mode, s)
797 struct acluser *uu, *u;
798 char *mode, *s;
800 struct win *w;
801 int i;
802 char *p, ch;
804 debug3("AclSetPerm(uu, user '%s', mode '%s', object '%s')\n",
805 u->u_name, mode, s);
806 while (*s)
808 switch (*s)
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++)
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;
845 return 0;
849 * Generic ACL Manager:
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.
859 static int
860 UserAcl(uu, u, argc, argv)
861 struct acluser *uu, **u;
862 int argc;
863 char **argv;
865 if ((*u && !strcmp((*u)->u_name, "nobody")) ||
866 (argc > 1 && !strcmp(argv[0], "nobody")))
867 return -1; /* do not change nobody! */
869 switch (argc)
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;
891 static int
892 UserAclCopy(to_up, from_up)
893 struct acluser **to_up, **from_up;
895 struct win *w;
896 int i, j, to_id, from_id;
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)
906 for (i = 0; i < ACL_BITS_PER_WIN; i++)
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
912 ACLBYTE(w->w_userbits[i], to_id) &= ~ACLBIT(to_id);
913 if ((w->w_wlockuser == *to_up) && (i == ACL_WRITE))
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;
924 for (j = 0; j <= RC_LAST; j++)
926 for (i = 0; i < ACL_BITS_PER_CMD; i++)
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);
935 return 0;
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.
947 UsersAcl(uu, argc, argv)
948 struct acluser *uu;
949 int argc;
950 char **argv;
952 char *s;
953 int r;
954 struct acluser **cf_u = NULL;
956 if (argc == 1)
958 char *p = NULL;
960 s = argv[0];
961 while (*s)
962 if (*s++ == '=') p = s;
963 if (p)
965 p[-1] = '\0';
966 cf_u = FindUserPtr(p);
970 if (argv[0][0] == '*' && argv[0][1] == '\0')
972 struct acluser **u;
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;
986 for (s = argv[0]; *s && *s!=' ' && *s!='\t' && *s!=',' && *s!='='; s++)
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;
999 * Preprocess argments, so that umask can be set with UsersAcl
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
1007 int
1008 AclUmask(u, str, errp)
1009 struct acluser *u;
1010 char *str;
1011 char **errp;
1013 char mode[16];
1014 char *av[3];
1015 char *p, c = '\0';
1017 /* split str into user and bits section. */
1018 for (p = str; *p; p++)
1019 if ((c = *p) == '+' || c == '-')
1020 break;
1021 if (!*p)
1023 *errp = "Bad argument. Should be ``[user[,user...]{+|-}rwxn''.";
1024 return -1;
1026 strncpy(mode, p, 15);
1027 mode[15] = '\0';
1028 *p = '\0';
1030 /* construct argument vector */
1031 if (!strcmp("??", str))
1033 str++;
1034 av[2] = "?";
1036 else
1037 av[2] = "#";
1038 av[1] = mode;
1039 av[0] = *str ? str : "*";
1040 /* call UsersAcl */
1041 if (UsersAcl(u, 3, av))
1043 *errp = "UsersAcl failed. Hmmm.";
1044 *p = c;
1045 return -1;
1047 *p = c;
1048 return 0;
1051 void
1052 AclWinSwap(a, b)
1053 int a, b;
1055 debug2("AclWinSwap(%d, %d) NOP.\n", a, b);
1058 struct acluser *EffectiveAclUser = NULL; /* hook for AT command permission */
1060 int
1061 AclCheckPermWin(u, mode, w)
1062 struct acluser *u;
1063 int mode;
1064 struct win *w;
1066 int ok;
1068 if (mode < 0 || mode >= ACL_BITS_PER_WIN)
1069 return -1;
1070 if (EffectiveAclUser)
1072 debug1("AclCheckPermWin: WARNING user %s overridden!\n", u->u_name);
1073 u = EffectiveAclUser;
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);
1078 if (!ok)
1080 struct aclusergroup **g = &u->u_group;
1081 struct acluser *saved_eff = EffectiveAclUser;
1083 EffectiveAclUser = NULL;
1084 while (*g)
1086 if (!AclCheckPermWin((*g)->u, mode, w))
1087 break;
1088 g = &(*g)->next;
1090 EffectiveAclUser = saved_eff;
1091 if (*g)
1092 ok = 1;
1094 debug1("%d\n", !ok);
1095 return !ok;
1098 int
1099 AclCheckPermCmd(u, mode, c)
1100 struct acluser *u;
1101 int mode;
1102 struct comm *c;
1104 int ok;
1106 if (mode < 0 || mode >= ACL_BITS_PER_CMD)
1107 return -1;
1108 if (EffectiveAclUser)
1110 debug1("AclCheckPermCmd: WARNING user %s overridden!\n", u->u_name);
1111 u = EffectiveAclUser;
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)
1117 struct aclusergroup **g = &u->u_group;
1118 struct acluser *saved_eff = EffectiveAclUser;
1120 EffectiveAclUser = NULL;
1121 while (*g)
1123 if (!AclCheckPermCmd((*g)->u, mode, c))
1124 break;
1125 g = &(*g)->next;
1127 EffectiveAclUser = saved_eff;
1128 if (*g)
1129 ok = 1;
1131 debug1("%d\n", !ok);
1132 return !ok;
1135 #endif /* MULTIUSER */