]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/checktty.c
1 /* checktty.c - linked into login, checks user against /etc/usertty
2 Created 25-Aug-95 by Peter Orbaek <poe@daimi.aau.dk>
3 Fixed by JDS June 1996 to clear lists and close files
5 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
6 - added Native Language Support
10 #include <sys/types.h>
11 #include <sys/param.h>
23 #include <sys/syslog.h>
27 # include <sys/sysmacros.h>
28 # include <linux/major.h>
31 #include "pathnames.h"
33 /* functions in login.c */
34 void badlogin(const char *s
);
36 extern struct hostent hostaddress
;
37 extern char *hostname
;
40 struct hostent hostaddress
;
44 badlogin(const char *s
)
46 printf(_("badlogin: %s\n"), s
);
52 printf(_("sleepexit %d\n"), x
);
57 static gid_t mygroups
[NGROUPS
];
58 static int num_groups
;
62 /* linked list of names */
68 enum State
{ StateUsers
, StateGroups
, StateClasses
};
70 #define CLASSNAMELEN 32
73 struct grplist
*first
;
74 struct ttyclass
*next
;
75 char classname
[CLASSNAMELEN
];
78 struct ttyclass
*ttyclasses
= NULL
;
81 am_in_group(char *group
)
88 for (ge
= mygroups
; ge
< mygroups
+ num_groups
; ge
++) {
89 if (g
->gr_gid
== *ge
) return 1;
96 find_groups(gid_t defgrp
, const char *user
)
98 num_groups
= getgroups(NGROUPS
, mygroups
);
101 static struct ttyclass
*
102 new_class(char *class)
106 tc
= (struct ttyclass
*)malloc(sizeof(struct ttyclass
));
108 printf(_("login: memory low, login may fail\n"));
109 syslog(LOG_WARNING
, _("can't malloc for ttyclass"));
113 tc
->next
= ttyclasses
;
115 strncpy(tc
->classname
, class, CLASSNAMELEN
);
116 tc
->classname
[CLASSNAMELEN
-1] = 0;
122 add_to_class(struct ttyclass
*tc
, char *tty
)
126 if (tc
== NULL
) return;
128 ge
= (struct grplist
*)malloc(sizeof(struct grplist
));
130 printf(_("login: memory low, login may fail\n"));
131 syslog(LOG_WARNING
, _("can't malloc for grplist"));
135 ge
->next
= tc
->first
;
136 strncpy(ge
->name
, tty
, NAMELEN
);
137 ge
->name
[NAMELEN
-1] = 0;
142 /* return true if tty is a pty. Very linux dependent */
144 isapty(const char *tty
)
149 /* avoid snprintf - old systems do not have it */
150 if (strlen(tty
) + 6 > sizeof(devname
))
152 sprintf(devname
, "/dev/%s", tty
);
154 #if defined(__linux__)
155 if((stat(devname
, &stb
) >= 0) && S_ISCHR(stb
.st_mode
)) {
156 int majordev
= major(stb
.st_rdev
);
158 /* this is for linux versions before 1.3: use major 4 */
159 if(majordev
== TTY_MAJOR
&& minor(stb
.st_rdev
) >= 192)
162 #if defined(PTY_SLAVE_MAJOR)
163 /* this is for linux 1.3 and newer: use major 3 */
164 if(majordev
== PTY_SLAVE_MAJOR
)
168 #if defined(UNIX98_PTY_SLAVE_MAJOR) && defined(UNIX98_PTY_MAJOR_COUNT)
169 /* this is for linux 2.1.116 and newer: use majors 136-143 */
170 if(majordev
>= UNIX98_PTY_SLAVE_MAJOR
&&
171 majordev
< UNIX98_PTY_SLAVE_MAJOR
+ UNIX98_PTY_MAJOR_COUNT
)
180 /* match the hostname hn against the pattern pat */
182 hnmatch(const char *hn
, const char *pat
)
184 int x1
, x2
, x3
, x4
, y1
, y2
, y3
, y4
;
185 unsigned long p
, mask
, a
;
189 if ((hn
== NULL
) && (strcmp(pat
, "localhost") == 0)) return 1;
190 if ((hn
== NULL
) || hn
[0] == 0) return 0;
192 if (pat
[0] >= '0' && pat
[0] <= '9') {
193 /* pattern is an IP QUAD address and a mask x.x.x.x/y.y.y.y */
194 sscanf(pat
, "%d.%d.%d.%d/%d.%d.%d.%d", &x1
, &x2
, &x3
, &x4
,
196 p
= (((unsigned long)x1
<<24)+((unsigned long)x2
<<16)
197 +((unsigned long)x3
<<8)+((unsigned long)x4
));
198 mask
= (((unsigned long)y1
<<24)+((unsigned long)y2
<<16)
199 +((unsigned long)y3
<<8)+((unsigned long)y4
));
201 if (!hostaddress
.h_addr_list
|| !hostaddress
.h_addr_list
[0])
204 ha
= (unsigned char *)hostaddress
.h_addr_list
[0];
205 a
= (((unsigned long)ha
[0]<<24)+((unsigned long)ha
[1]<<16)
206 +((unsigned long)ha
[2]<<8)+((unsigned long)ha
[3]));
207 return ((p
& mask
) == (a
& mask
));
209 /* pattern is a suffix of a FQDN */
213 return (strcasecmp(pat
, hn
+ m
- n
) == 0);
217 static char *wdays
[] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" };
219 /* example timespecs:
223 meaning monday, tuesday or wednesday between 8:00 and 17:59
227 meaning fridays from 4:00 to 5:59 and from 13:00 to 13:59
230 timeok(struct tm
*t
, char *spec
)
239 while ((p
= strsep(&sp
, ":"))) {
240 if (*p
>= '0' && *p
<= '9') {
242 if (h
== t
->tm_hour
) hourok
= 1;
243 if ((q
= strchr(p
, '-')) && (q
[1] >= '0' && q
[1] <= '9')) {
245 if (h
<= t
->tm_hour
&& t
->tm_hour
<= h2
) hourok
= 1;
247 } else if (strcasecmp(wdays
[t
->tm_wday
], p
) == 0) {
252 return (dayok
&& hourok
);
255 /* return true if tty equals class or is in the class defined by class.
256 Also return true if hostname matches the hostname pattern, class
257 or a pattern in the class named by class. */
259 in_class(const char *tty
, char *class)
272 if (class[0] == '[') {
273 if ((p
= strchr(class, ']'))) {
275 strncpy(timespec
, class+1, sizeof(timespec
));
276 timespec
[sizeof(timespec
)-1] = 0;
278 if(!timeok(tm
, timespec
)) return 0;
281 /* really ought to warn about syntax error */
284 if (strcmp(tty
, class) == 0) return 1;
286 if ((class[0] == '@') && isapty(tty
)
287 && hnmatch(hostname
, class+1)) return 1;
289 for (tc
= ttyclasses
; tc
; tc
= tc
->next
) {
290 if (strcmp(tc
->classname
, class) == 0) {
291 for (ge
= tc
->first
; ge
; ge
= ge
->next
) {
295 if ((p
= strchr(n
, ']'))) {
297 strncpy(timespec
, n
+1, sizeof(timespec
));
298 timespec
[sizeof(timespec
)-1] = 0;
300 if(!timeok(tm
, timespec
)) continue;
303 /* really ought to warn about syntax error */
306 if (strcmp(n
, tty
) == 0) return 1;
308 if ((n
[0] == '@') && isapty(tty
)
309 && hnmatch(hostname
, n
+1)) return 1;
317 /* start JDS - SBA */
319 free_group(struct grplist
*ge
)
322 memset(ge
->name
, 0, NAMELEN
);
323 free_group(ge
->next
);
330 free_class(struct ttyclass
*tc
)
333 memset(tc
->classname
, 0, CLASSNAMELEN
);
334 free_group(tc
->first
);
336 free_class(tc
->next
);
345 free_class(ttyclasses
);
351 checktty(const char *user
, const char *tty
, struct passwd
*pwd
)
354 char buf
[256], defaultbuf
[256];
356 enum State state
= StateUsers
;
359 /* no /etc/usertty, default to allow access */
361 if (!(f
= fopen("usertty", "r"))) return;
363 if (!(f
= fopen(_PATH_USERTTY
, "r"))) return;
368 return; /* misspelled username handled elsewhere */
371 find_groups(pwd
->pw_gid
, user
);
374 while(fgets(buf
, 255, f
)) {
377 for(ptr
= buf
; ptr
< buf
+ 256; ptr
++)
378 if(*ptr
== '#') *ptr
= 0;
381 strncpy(defaultbuf
, buf
, 256);
386 if (strncmp("GROUPS", buf
, 6) == 0) {
389 } else if (strncmp("USERS", buf
, 5) == 0) {
392 } else if (strncmp("CLASSES", buf
, 7) == 0) {
393 state
= StateClasses
;
398 if((state
== StateUsers
&& (strncmp(user
, buf
, 8) == 0))
399 || (state
== StateGroups
&& am_in_group(buf
))) {
400 found_match
= 1; /* we found a line matching the user */
401 while((ptr
= strtok(NULL
, "\t\n "))) {
402 if (in_class(tty
, ptr
)) {
404 free_all(); /* JDS */
408 } else if (state
== StateClasses
) {
409 /* define a new tty/host class */
410 struct ttyclass
*tc
= new_class(buf
);
412 while ((ptr
= strtok(NULL
, "\t\n "))) {
413 add_to_class(tc
, ptr
);
419 /* user is not explicitly mentioned in /etc/usertty, if there was
420 a default rule, use that */
422 strtok(defaultbuf
, " \t");
423 while((ptr
= strtok(NULL
, "\t\n "))) {
424 if (in_class(tty
, ptr
)) {
425 free_all(); /* JDS */
430 /* there was a default rule, but user didn't match, reject! */
431 printf(_("Login on %s from %s denied by default.\n"), tty
, hostname
);
437 /* if we get here, /etc/usertty exists, there's a line
438 matching our username, but it doesn't contain the
439 name of the tty where the user is trying to log in.
442 printf(_("Login on %s from %s denied.\n"), tty
, hostname
);
447 /* users not matched in /etc/usertty are by default allowed access
449 free_all(); /* JDS */
453 main(int argc
, char *argv
[])
457 pw
= getpwnam(argv
[1]);
458 checktty(argv
[1], argv
[2], pw
);