1 /* Tests for UTMP functions.
2    Copyright (C) 1998-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <errno.h>
20 #include <error.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <time.h>
25 
26 #ifdef UTMPX
27 # include <utmpx.h>
28 # define utmp utmpx
29 # define utmpname utmpxname
30 # define setutent setutxent
31 # define getutent getutxent
32 # define endutent endutxent
33 # define getutline getutxline
34 # define getutid getutxid
35 # define pututline pututxline
36 #else
37 # include <utmp.h>
38 #endif
39 
40 
41 /* Prototype for our test function.  */
42 static int do_test (int argc, char *argv[]);
43 
44 /* We have a preparation function.  */
45 static void do_prepare (int argc, char *argv[]);
46 #define PREPARE do_prepare
47 
48 /* This defines the `main' function and some more.  */
49 #include <test-skeleton.c>
50 
51 
52 /* These are for the temporary file we generate.  */
53 char *name;
54 int fd;
55 
56 static void
do_prepare(int argc,char * argv[])57 do_prepare (int argc, char *argv[])
58 {
59   size_t name_len;
60 
61   name_len = strlen (test_dir);
62   name = xmalloc (name_len + sizeof ("/utmpXXXXXX"));
63   mempcpy (mempcpy (name, test_dir, name_len),
64 	   "/utmpXXXXXX", sizeof ("/utmpXXXXXX"));
65 
66   /* Open our test file.  */
67   fd = mkstemp (name);
68   if (fd == -1)
69     error (EXIT_FAILURE, errno, "cannot open test file `%s'", name);
70   add_temp_file (name);
71 }
72 
73 struct utmp entry[] =
74 {
75 #define UT(a)  .ut_tv = { .tv_sec = (a)}
76 
77   { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
78   { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
79   { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
80   { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
81     .ut_user = "LOGIN", UT(4000) },
82   { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
83     .ut_user = "albert", UT(8000) },
84   { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
85     .ut_user = "niels", UT(10000) },
86   { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
87   { .ut_type = EMPTY },
88   { .ut_type = EMPTY }
89 };
90 int num_entries = sizeof entry / sizeof (struct utmp);
91 
92 time_t entry_time = 20000;
93 pid_t entry_pid = 234;
94 
95 static int
do_init(void)96 do_init (void)
97 {
98   int n;
99 
100   setutent ();
101 
102   for (n = 0; n < num_entries; n++)
103     {
104       if (pututline (&entry[n]) == NULL)
105 	{
106 	  error (0, errno, "cannot write UTMP entry");
107 	  return 1;
108 	}
109     }
110 
111   endutent ();
112 
113   return 0;
114 }
115 
116 
117 static int
do_check(void)118 do_check (void)
119 {
120   struct utmp *ut;
121   int n;
122 
123   setutent ();
124 
125   n = 0;
126   while ((ut = getutent ()))
127     {
128       if (n < num_entries
129 	  && memcmp (ut, &entry[n], sizeof (struct utmp)))
130 	{
131 	  error (0, 0, "UTMP entry does not match");
132 	  return 1;
133 	}
134 
135       n++;
136     }
137 
138   if (n != num_entries)
139     {
140       error (0, 0, "number of UTMP entries is incorrect");
141       return 1;
142     }
143 
144   endutent ();
145 
146   return 0;
147 }
148 
149 static int
simulate_login(const char * line,const char * user)150 simulate_login (const char *line, const char *user)
151 {
152   int n;
153 
154   for (n = 0; n < num_entries; n++)
155     {
156       if (strcmp (line, entry[n].ut_line) == 0
157 	  || entry[n].ut_type == DEAD_PROCESS)
158 	{
159 	  if (entry[n].ut_pid == DEAD_PROCESS)
160 	    entry[n].ut_pid = (entry_pid += 27);
161 	  entry[n].ut_type = USER_PROCESS;
162 	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
163 	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
164 	  setutent ();
165 
166 	  if (pututline (&entry[n]) == NULL)
167 	    {
168 	      error (0, errno, "cannot write UTMP entry");
169 	      return 1;
170 	    }
171 
172 	  endutent ();
173 
174 	  return 0;
175 	}
176     }
177 
178   error (0, 0, "no entries available");
179   return 1;
180 }
181 
182 static int
simulate_logout(const char * line)183 simulate_logout (const char *line)
184 {
185   int n;
186 
187   for (n = 0; n < num_entries; n++)
188     {
189       if (strcmp (line, entry[n].ut_line) == 0)
190 	{
191 	  entry[n].ut_type = DEAD_PROCESS;
192 	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
193           entry[n].ut_tv.tv_sec = (entry_time += 1000);
194 	  setutent ();
195 
196 	  if (pututline (&entry[n]) == NULL)
197 	    {
198 	      error (0, errno, "cannot write UTMP entry");
199 	      return 1;
200 	    }
201 
202 	  endutent ();
203 
204 	  return 0;
205 	}
206     }
207 
208   error (0, 0, "no entry found for `%s'", line);
209   return 1;
210 }
211 
212 static int
check_login(const char * line)213 check_login (const char *line)
214 {
215   struct utmp *up;
216   struct utmp ut;
217   int n;
218 
219   setutent ();
220 
221   strcpy (ut.ut_line, line);
222   up = getutline (&ut);
223   if (up == NULL)
224     {
225       error (0, errno, "cannot get entry for line `%s'", line);
226       return 1;
227     }
228 
229   endutent ();
230 
231   for (n = 0; n < num_entries; n++)
232     {
233       if (strcmp (line, entry[n].ut_line) == 0)
234 	{
235 	  if (memcmp (up, &entry[n], sizeof (struct utmp)))
236 	    {
237 	      error (0, 0, "UTMP entry does not match");
238 	      return 1;
239 	    }
240 
241 	  return 0;
242 	}
243     }
244 
245   error (0, 0, "bogus entry for line `%s'", line);
246   return 1;
247 }
248 
249 static int
check_logout(const char * line)250 check_logout (const char *line)
251 {
252   struct utmp ut;
253 
254   setutent ();
255 
256   strcpy (ut.ut_line, line);
257   if (getutline (&ut) != NULL)
258     {
259       error (0, 0, "bogus login entry for `%s'", line);
260       return 1;
261     }
262 
263   endutent ();
264 
265   return 0;
266 }
267 
268 static int
check_id(const char * id)269 check_id (const char *id)
270 {
271   struct utmp *up;
272   struct utmp ut;
273   int n;
274 
275   setutent ();
276 
277   ut.ut_type = USER_PROCESS;
278   strcpy (ut.ut_id, id);
279   up = getutid (&ut);
280   if (up == NULL)
281     {
282       error (0, errno, "cannot get entry for ID `%s'", id);
283       return 1;
284     }
285 
286   endutent ();
287 
288   for (n = 0; n < num_entries; n++)
289     {
290       if (strcmp (id, entry[n].ut_id) == 0)
291 	{
292 	  if (memcmp (up, &entry[n], sizeof (struct utmp)))
293 	    {
294 	      error (0, 0, "UTMP entry does not match");
295 	      return 1;
296 	    }
297 
298 	  return 0;
299 	}
300     }
301 
302   error (0, 0, "bogus entry for ID `%s'", id);
303   return 1;
304 }
305 
306 static int
check_type(int type)307 check_type (int type)
308 {
309   struct utmp *up;
310   struct utmp ut;
311   int n;
312 
313   setutent ();
314 
315   ut.ut_type = type;
316   up = getutid (&ut);
317   if (up == NULL)
318     {
319       error (0, errno, "cannot get entry for type `%d'", type);
320       return 1;
321     }
322 
323   endutent ();
324 
325   for (n = 0; n < num_entries; n++)
326     {
327       if (type == entry[n].ut_type)
328 	{
329 	  if (memcmp (up, &entry[n], sizeof (struct utmp)))
330 	    {
331 	      error (0, 0, "UTMP entry does not match");
332 	      return 1;
333 	    }
334 
335 	  return 0;
336 	}
337     }
338 
339   error (0, 0, "bogus entry for type `%d'", type);
340   return 1;
341 }
342 
343 static int
do_test(int argc,char * argv[])344 do_test (int argc, char *argv[])
345 {
346   int result = 0;
347 
348   utmpname (name);
349 
350   result |= do_init ();
351   result |= do_check ();
352 
353   result |= simulate_login ("tty1", "erwin");
354   result |= do_check ();
355 
356   result |= simulate_login ("ttyp1", "paul");
357   result |= do_check ();
358 
359   result |= simulate_logout ("tty2");
360   result |= do_check ();
361 
362   result |= simulate_logout ("ttyp0");
363   result |= do_check ();
364 
365   result |= simulate_login ("ttyp2", "richard");
366   result |= do_check ();
367 
368   result |= check_login ("tty1");
369   result |= check_logout ("ttyp0");
370   result |= check_id ("p1");
371   result |= check_id ("2");
372   result |= check_id ("si");
373   result |= check_type (BOOT_TIME);
374   result |= check_type (RUN_LVL);
375 
376   return result;
377 }
378