author | Jon Tibble <meths@btinternet.com> |
Thu, 09 Dec 2010 22:32:39 +0100 | |
changeset 13255 | 4afa820d78b9 |
parent 7767 | 905db6a104b6 |
permissions | -rw-r--r-- |
0 | 1 |
/* |
2 |
* CDDL HEADER START |
|
3 |
* |
|
4 |
* The contents of this file are subject to the terms of the |
|
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
5 |
* Common Development and Distribution License (the "License"). |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
6 |
* You may not use this file except in compliance with the License. |
0 | 7 |
* |
8 |
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 |
* or http://www.opensolaris.org/os/licensing. |
|
10 |
* See the License for the specific language governing permissions |
|
11 |
* and limitations under the License. |
|
12 |
* |
|
13 |
* When distributing Covered Code, include this CDDL HEADER in each |
|
14 |
* file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 |
* If applicable, add the following below this CDDL HEADER, with the |
|
16 |
* fields enclosed by brackets "[]" replaced with your own identifying |
|
17 |
* information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 |
* |
|
19 |
* CDDL HEADER END |
|
20 |
*/ |
|
6812 | 21 |
|
0 | 22 |
/* |
6812 | 23 |
* Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
0 | 24 |
* Use is subject to license terms. |
25 |
*/ |
|
26 |
||
27 |
/* Copyright (c) 1988 AT&T */ |
|
28 |
/* All Rights Reserved */ |
|
29 |
||
30 |
/* |
|
31 |
* Compatibility routines to read and write alternate |
|
32 |
* utmp-like files. These routines are only used in |
|
33 |
* the case where utmpname() is used to change to a file |
|
34 |
* other than /var/adm/utmp or /var/adm/wtmp. In this case, |
|
35 |
* we assume that someone really wants to read old utmp-format |
|
36 |
* files. Otherwise, the getutent, setutent, getutid, setutline, |
|
37 |
* and pututline functions are actually wrappers around the |
|
38 |
* equivalent function operating on utmpx-like files. |
|
39 |
*/ |
|
40 |
||
6812 | 41 |
#include "lint.h" |
0 | 42 |
#include <stdio.h> |
43 |
#include <sys/param.h> |
|
44 |
#include <sys/types.h> |
|
45 |
#include <sys/stat.h> |
|
46 |
#include <utmpx.h> |
|
47 |
#include <errno.h> |
|
48 |
#include <fcntl.h> |
|
49 |
#include <string.h> |
|
50 |
#include <strings.h> |
|
51 |
#include <stdlib.h> |
|
52 |
#include <unistd.h> |
|
53 |
#include <ctype.h> |
|
54 |
#include <utime.h> |
|
55 |
#include <sys/wait.h> |
|
56 |
||
57 |
#define IDLEN 4 /* length of id field in utmp */ |
|
58 |
#define SC_WILDC 0xff /* wild char for utmp ids */ |
|
59 |
#define MAXVAL 255 /* max value for an id 'character' */ |
|
60 |
||
61 |
#ifdef ut_time |
|
62 |
#undef ut_time |
|
63 |
#endif |
|
64 |
||
65 |
static void utmp_frec2api(const struct futmp *, struct utmp *); |
|
66 |
static void utmp_api2frec(const struct utmp *, struct futmp *); |
|
67 |
struct utmp *_compat_getutent(void); |
|
68 |
struct utmp *_compat_getutid(const struct utmp *); |
|
69 |
struct utmp *_compat_getutline(const struct utmp *); |
|
70 |
struct utmp *_compat_pututline(const struct utmp *); |
|
71 |
void _compat_setutent(void); |
|
72 |
void _compat_endutent(void); |
|
73 |
void _compat_updwtmp(const char *, struct utmp *); |
|
74 |
struct utmp *_compat_makeut(struct utmp *); |
|
75 |
struct utmp *_compat_modut(struct utmp *); |
|
76 |
||
77 |
static void unlockut(void); |
|
78 |
static int idcmp(const char *, const char *); |
|
79 |
static int allocid(char *, unsigned char *); |
|
80 |
static int lockut(void); |
|
81 |
||
82 |
||
83 |
static int fd = -1; /* File descriptor for the utmp file. */ |
|
84 |
/* |
|
85 |
* name of the current utmp-like file - set by utmpname (getutx.c) |
|
86 |
* only if running in backward compatibility mode |
|
7767
905db6a104b6
6755382 new "more linker like" version of lint2 exposes new lint warnings in ON
John Beck <John.Beck@Sun.COM>
parents:
6812
diff
changeset
|
87 |
* We don't modify this, but we can't declare it const or lint will freak. |
0 | 88 |
*/ |
7767
905db6a104b6
6755382 new "more linker like" version of lint2 exposes new lint warnings in ON
John Beck <John.Beck@Sun.COM>
parents:
6812
diff
changeset
|
89 |
extern char _compat_utmpfile[]; |
0 | 90 |
|
91 |
#ifdef ERRDEBUG |
|
92 |
static long loc_utmp; /* Where in "utmp" the current "ubuf" was found. */ |
|
93 |
#endif |
|
94 |
||
95 |
static struct futmp fubuf; /* Copy of last entry read in. */ |
|
96 |
static struct utmp ubuf; /* Last entry returned to client */ |
|
97 |
||
98 |
/* |
|
99 |
* In the 64-bit world, the utmp data structure grows because of |
|
100 |
* the ut_time field (a time_t) at the end of it. |
|
101 |
*/ |
|
102 |
static void |
|
103 |
utmp_frec2api(const struct futmp *src, struct utmp *dst) |
|
104 |
{ |
|
105 |
if (src == NULL) |
|
106 |
return; |
|
107 |
||
108 |
(void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user)); |
|
109 |
(void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line)); |
|
110 |
(void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id)); |
|
111 |
dst->ut_pid = src->ut_pid; |
|
112 |
dst->ut_type = src->ut_type; |
|
113 |
dst->ut_exit.e_termination = src->ut_exit.e_termination; |
|
114 |
dst->ut_exit.e_exit = src->ut_exit.e_exit; |
|
115 |
dst->ut_time = (time_t)src->ut_time; |
|
116 |
} |
|
117 |
||
118 |
static void |
|
119 |
utmp_api2frec(const struct utmp *src, struct futmp *dst) |
|
120 |
{ |
|
121 |
if (src == NULL) |
|
122 |
return; |
|
123 |
||
124 |
(void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user)); |
|
125 |
(void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line)); |
|
126 |
(void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id)); |
|
127 |
dst->ut_pid = src->ut_pid; |
|
128 |
dst->ut_type = src->ut_type; |
|
129 |
dst->ut_exit.e_termination = src->ut_exit.e_termination; |
|
130 |
dst->ut_exit.e_exit = src->ut_exit.e_exit; |
|
131 |
dst->ut_time = (time32_t)src->ut_time; |
|
132 |
} |
|
133 |
||
134 |
/* |
|
135 |
* "getutent_frec" gets the raw version of the next entry in the utmp file. |
|
136 |
*/ |
|
137 |
static struct futmp * |
|
138 |
getutent_frec(void) |
|
139 |
{ |
|
140 |
/* |
|
141 |
* If the "utmp" file is not open, attempt to open it for |
|
142 |
* reading. If there is no file, attempt to create one. If |
|
143 |
* both attempts fail, return NULL. If the file exists, but |
|
144 |
* isn't readable and writeable, do not attempt to create. |
|
145 |
*/ |
|
146 |
if (fd < 0) { |
|
147 |
if ((fd = open(_compat_utmpfile, O_RDWR|O_CREAT, 0644)) < 0) { |
|
148 |
||
149 |
/* |
|
150 |
* If the open failed for permissions, try opening |
|
151 |
* it only for reading. All "pututline()" later |
|
152 |
* will fail the writes. |
|
153 |
*/ |
|
154 |
if ((fd = open(_compat_utmpfile, O_RDONLY)) < 0) |
|
155 |
return (NULL); |
|
156 |
} |
|
157 |
} |
|
158 |
||
159 |
/* Try to read in the next entry from the utmp file. */ |
|
160 |
||
161 |
if (read(fd, &fubuf, sizeof (fubuf)) != sizeof (fubuf)) { |
|
162 |
bzero(&fubuf, sizeof (fubuf)); |
|
163 |
return (NULL); |
|
164 |
} |
|
165 |
||
166 |
/* Save the location in the file where this entry was found. */ |
|
167 |
||
168 |
(void) lseek(fd, 0L, 1); |
|
169 |
return (&fubuf); |
|
170 |
} |
|
171 |
||
172 |
/* |
|
173 |
* "_compat_getutent" gets the next entry in the utmp file. |
|
174 |
*/ |
|
175 |
struct utmp * |
|
176 |
_compat_getutent(void) |
|
177 |
{ |
|
178 |
struct futmp *futp; |
|
179 |
||
180 |
futp = getutent_frec(); |
|
181 |
utmp_frec2api(&fubuf, &ubuf); |
|
182 |
if (futp == NULL) |
|
183 |
return (NULL); |
|
184 |
return (&ubuf); |
|
185 |
} |
|
186 |
||
187 |
/* |
|
188 |
* "_compat_getutid" finds the specified entry in the utmp file. If |
|
189 |
* it can't find it, it returns NULL. |
|
190 |
*/ |
|
191 |
struct utmp * |
|
192 |
_compat_getutid(const struct utmp *entry) |
|
193 |
{ |
|
194 |
short type; |
|
195 |
||
196 |
utmp_api2frec(&ubuf, &fubuf); |
|
197 |
||
198 |
/* |
|
199 |
* Start looking for entry. Look in our current buffer before |
|
200 |
* reading in new entries. |
|
201 |
*/ |
|
202 |
do { |
|
203 |
/* |
|
204 |
* If there is no entry in "ubuf", skip to the read. |
|
205 |
*/ |
|
206 |
if (fubuf.ut_type != EMPTY) { |
|
207 |
switch (entry->ut_type) { |
|
208 |
||
209 |
/* |
|
210 |
* Do not look for an entry if the user sent |
|
211 |
* us an EMPTY entry. |
|
212 |
*/ |
|
213 |
case EMPTY: |
|
214 |
return (NULL); |
|
215 |
||
216 |
/* |
|
217 |
* For RUN_LVL, BOOT_TIME, DOWN_TIME, |
|
218 |
* OLD_TIME, and NEW_TIME entries, only the |
|
219 |
* types have to match. If they do, return |
|
220 |
* the address of internal buffer. |
|
221 |
*/ |
|
222 |
case RUN_LVL: |
|
223 |
case BOOT_TIME: |
|
224 |
case DOWN_TIME: |
|
225 |
case OLD_TIME: |
|
226 |
case NEW_TIME: |
|
227 |
if (entry->ut_type == fubuf.ut_type) { |
|
228 |
utmp_frec2api(&fubuf, &ubuf); |
|
229 |
return (&ubuf); |
|
230 |
} |
|
231 |
break; |
|
232 |
||
233 |
/* |
|
234 |
* For INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, |
|
235 |
* and DEAD_PROCESS the type of the entry in "fubuf", |
|
236 |
* must be one of the above and id's must match. |
|
237 |
*/ |
|
238 |
case INIT_PROCESS: |
|
239 |
case LOGIN_PROCESS: |
|
240 |
case USER_PROCESS: |
|
241 |
case DEAD_PROCESS: |
|
242 |
if (((type = fubuf.ut_type) == INIT_PROCESS || |
|
243 |
type == LOGIN_PROCESS || |
|
244 |
type == USER_PROCESS || |
|
245 |
type == DEAD_PROCESS) && |
|
246 |
fubuf.ut_id[0] == entry->ut_id[0] && |
|
247 |
fubuf.ut_id[1] == entry->ut_id[1] && |
|
248 |
fubuf.ut_id[2] == entry->ut_id[2] && |
|
249 |
fubuf.ut_id[3] == entry->ut_id[3]) { |
|
250 |
utmp_frec2api(&fubuf, &ubuf); |
|
251 |
return (&ubuf); |
|
252 |
} |
|
253 |
break; |
|
254 |
||
255 |
/* Do not search for illegal types of entry. */ |
|
256 |
default: |
|
257 |
return (NULL); |
|
258 |
} |
|
259 |
} |
|
260 |
} while (getutent_frec() != NULL); |
|
261 |
||
262 |
/* the proper entry wasn't found. */ |
|
263 |
||
264 |
utmp_frec2api(&fubuf, &ubuf); |
|
265 |
return (NULL); |
|
266 |
} |
|
267 |
||
268 |
/* |
|
269 |
* "_compat_getutline" searches the "utmp" file for a LOGIN_PROCESS or |
|
270 |
* USER_PROCESS with the same "line" as the specified "entry". |
|
271 |
*/ |
|
272 |
struct utmp * |
|
273 |
_compat_getutline(const struct utmp *entry) |
|
274 |
{ |
|
275 |
utmp_api2frec(&ubuf, &fubuf); |
|
276 |
||
277 |
do { |
|
278 |
/* |
|
279 |
* If the current entry is the one we are interested in, |
|
280 |
* return a pointer to it. |
|
281 |
*/ |
|
282 |
if (fubuf.ut_type != EMPTY && |
|
283 |
(fubuf.ut_type == LOGIN_PROCESS || |
|
284 |
fubuf.ut_type == USER_PROCESS) && |
|
285 |
strncmp(&entry->ut_line[0], &fubuf.ut_line[0], |
|
286 |
sizeof (fubuf.ut_line)) == 0) { |
|
287 |
utmp_frec2api(&fubuf, &ubuf); |
|
288 |
return (&ubuf); |
|
289 |
} |
|
290 |
} while (getutent_frec() != NULL); |
|
291 |
||
292 |
utmp_frec2api(&fubuf, &ubuf); |
|
293 |
return (NULL); |
|
294 |
} |
|
295 |
||
296 |
/* |
|
297 |
* "_compat_pututline" writes the structure sent into the utmp file |
|
298 |
* If there is already an entry with the same id, then it is |
|
299 |
* overwritten, otherwise a new entry is made at the end of the |
|
300 |
* utmp file. |
|
301 |
*/ |
|
302 |
struct utmp * |
|
303 |
_compat_pututline(const struct utmp *entry) |
|
304 |
{ |
|
305 |
int fc; |
|
306 |
struct utmp *answer; |
|
307 |
struct utmp tmpbuf; |
|
308 |
struct futmp ftmpbuf; |
|
309 |
||
310 |
/* |
|
311 |
* Copy the user supplied entry into our temporary buffer to |
|
312 |
* avoid the possibility that the user is actually passing us |
|
313 |
* the address of "ubuf". |
|
314 |
*/ |
|
315 |
tmpbuf = *entry; |
|
316 |
utmp_api2frec(entry, &ftmpbuf); |
|
317 |
||
318 |
(void) getutent_frec(); |
|
319 |
if (fd < 0) { |
|
320 |
#ifdef ERRDEBUG |
|
321 |
gdebug("pututline: Unable to create utmp file.\n"); |
|
322 |
#endif |
|
323 |
return (NULL); |
|
324 |
} |
|
325 |
||
326 |
/* Make sure file is writable */ |
|
327 |
||
328 |
if ((fc = fcntl(fd, F_GETFL, NULL)) == -1 || (fc & O_RDWR) != O_RDWR) |
|
329 |
return (NULL); |
|
330 |
||
331 |
/* |
|
332 |
* Find the proper entry in the utmp file. Start at the current |
|
333 |
* location. If it isn't found from here to the end of the |
|
334 |
* file, then reset to the beginning of the file and try again. |
|
335 |
* If it still isn't found, then write a new entry at the end of |
|
336 |
* the file. (Making sure the location is an integral number of |
|
337 |
* utmp structures into the file incase the file is scribbled.) |
|
338 |
*/ |
|
339 |
||
340 |
if (_compat_getutid(&tmpbuf) == NULL) { |
|
341 |
#ifdef ERRDEBUG |
|
342 |
gdebug("1st getutid() failed. fd: %d", fd); |
|
343 |
#endif |
|
344 |
_compat_setutent(); |
|
345 |
if (_compat_getutid(&tmpbuf) == NULL) { |
|
346 |
#ifdef ERRDEBUG |
|
347 |
loc_utmp = lseek(fd, 0L, 1); |
|
348 |
gdebug("2nd getutid() failed. fd: %d loc_utmp: %ld\n", |
|
349 |
fd, loc_utmp); |
|
350 |
#endif |
|
351 |
(void) fcntl(fd, F_SETFL, fc | O_APPEND); |
|
352 |
} else |
|
353 |
(void) lseek(fd, -(long)sizeof (struct futmp), 1); |
|
354 |
} else |
|
355 |
(void) lseek(fd, -(long)sizeof (struct futmp), 1); |
|
356 |
||
357 |
/* |
|
358 |
* Write out the user supplied structure. If the write fails, |
|
359 |
* then the user probably doesn't have permission to write the |
|
360 |
* utmp file. |
|
361 |
*/ |
|
362 |
if (write(fd, &ftmpbuf, sizeof (ftmpbuf)) != sizeof (ftmpbuf)) { |
|
363 |
#ifdef ERRDEBUG |
|
364 |
gdebug("pututline failed: write-%d\n", errno); |
|
365 |
#endif |
|
366 |
answer = NULL; |
|
367 |
} else { |
|
368 |
/* |
|
369 |
* Copy the new user structure into ubuf so that it will |
|
370 |
* be up to date in the future. |
|
371 |
*/ |
|
372 |
fubuf = ftmpbuf; |
|
373 |
utmp_frec2api(&fubuf, &ubuf); |
|
374 |
answer = &ubuf; |
|
375 |
||
376 |
#ifdef ERRDEBUG |
|
377 |
gdebug("id: %c%c loc: %ld\n", fubuf.ut_id[0], |
|
378 |
fubuf.ut_id[1], fubuf.ut_id[2], fubuf.ut_id[3], |
|
379 |
loc_utmp); |
|
380 |
#endif |
|
381 |
} |
|
382 |
||
383 |
(void) fcntl(fd, F_SETFL, fc); |
|
384 |
||
385 |
return (answer); |
|
386 |
} |
|
387 |
||
388 |
/* |
|
389 |
* "_compat_setutent" just resets the utmp file back to the beginning. |
|
390 |
*/ |
|
391 |
void |
|
392 |
_compat_setutent(void) |
|
393 |
{ |
|
394 |
if (fd != -1) |
|
395 |
(void) lseek(fd, 0L, 0); |
|
396 |
||
397 |
/* |
|
398 |
* Zero the stored copy of the last entry read, since we are |
|
399 |
* resetting to the beginning of the file. |
|
400 |
*/ |
|
401 |
bzero(&ubuf, sizeof (ubuf)); |
|
402 |
bzero(&fubuf, sizeof (fubuf)); |
|
403 |
} |
|
404 |
||
405 |
/* |
|
406 |
* "_compat_endutent" closes the utmp file. |
|
407 |
*/ |
|
408 |
void |
|
409 |
_compat_endutent(void) |
|
410 |
{ |
|
411 |
if (fd != -1) |
|
412 |
(void) close(fd); |
|
413 |
fd = -1; |
|
414 |
bzero(&ubuf, sizeof (ubuf)); |
|
415 |
bzero(&fubuf, sizeof (fubuf)); |
|
416 |
} |
|
417 |
||
418 |
||
419 |
/* |
|
420 |
* If one of wtmp and wtmpx files exist, create the other, and the record. |
|
421 |
* If they both exist add the record. |
|
422 |
*/ |
|
423 |
void |
|
424 |
_compat_updwtmp(const char *file, struct utmp *ut) |
|
425 |
{ |
|
426 |
struct futmp fut; |
|
427 |
int fd; |
|
428 |
||
429 |
||
430 |
fd = open(file, O_WRONLY | O_APPEND); |
|
431 |
||
432 |
if (fd < 0) { |
|
433 |
if ((fd = open(file, O_WRONLY|O_CREAT, 0644)) < 0) |
|
434 |
return; |
|
435 |
} |
|
436 |
||
437 |
(void) lseek(fd, 0, 2); |
|
438 |
||
439 |
utmp_api2frec(ut, &fut); |
|
440 |
(void) write(fd, &fut, sizeof (fut)); |
|
441 |
||
442 |
(void) close(fd); |
|
443 |
} |
|
444 |
||
445 |
||
446 |
||
447 |
/* |
|
448 |
* makeut - create a utmp entry, recycling an id if a wild card is |
|
449 |
* specified. |
|
450 |
* |
|
451 |
* args: utmp - point to utmp structure to be created |
|
452 |
*/ |
|
453 |
struct utmp * |
|
454 |
_compat_makeut(struct utmp *utmp) |
|
455 |
{ |
|
456 |
int i; |
|
457 |
struct utmp *utp; /* "current" utmp entry being examined */ |
|
458 |
int wild; /* flag, true iff wild card char seen */ |
|
459 |
||
460 |
/* the last id we matched that was NOT a dead proc */ |
|
461 |
unsigned char saveid[IDLEN]; |
|
462 |
||
463 |
wild = 0; |
|
464 |
for (i = 0; i < IDLEN; i++) |
|
465 |
if ((unsigned char)utmp->ut_id[i] == SC_WILDC) { |
|
466 |
wild = 1; |
|
467 |
break; |
|
468 |
} |
|
469 |
||
470 |
if (wild) { |
|
471 |
||
472 |
/* |
|
473 |
* try to lock the utmp file, only needed if we're |
|
474 |
* doing wildcard matching |
|
475 |
*/ |
|
476 |
||
477 |
if (lockut()) |
|
478 |
return (0); |
|
479 |
_compat_setutent(); |
|
480 |
||
481 |
/* find the first alphanumeric character */ |
|
482 |
for (i = 0; i < MAXVAL; ++i) |
|
483 |
if (isalnum(i)) |
|
484 |
break; |
|
485 |
||
486 |
(void) memset(saveid, i, IDLEN); |
|
487 |
||
488 |
while ((utp = _compat_getutent()) != 0) { |
|
489 |
if (idcmp(utmp->ut_id, utp->ut_id)) |
|
490 |
continue; |
|
491 |
if (utp->ut_type == DEAD_PROCESS) |
|
492 |
break; |
|
493 |
(void) memcpy(saveid, utp->ut_id, IDLEN); |
|
494 |
} |
|
495 |
||
496 |
if (utp) { |
|
497 |
/* |
|
498 |
* found an unused entry, reuse it |
|
499 |
*/ |
|
500 |
(void) memcpy(utmp->ut_id, utp->ut_id, IDLEN); |
|
501 |
utp = _compat_pututline(utmp); |
|
502 |
if (utp) |
|
503 |
_compat_updwtmp(WTMP_FILE, utp); |
|
504 |
_compat_endutent(); |
|
505 |
unlockut(); |
|
506 |
return (utp); |
|
507 |
||
508 |
} else { |
|
509 |
/* |
|
510 |
* nothing available, try to allocate an id |
|
511 |
*/ |
|
512 |
if (allocid(utmp->ut_id, saveid)) { |
|
513 |
_compat_endutent(); |
|
514 |
unlockut(); |
|
515 |
return (NULL); |
|
516 |
} else { |
|
517 |
utp = _compat_pututline(utmp); |
|
518 |
if (utp) |
|
519 |
_compat_updwtmp(WTMP_FILE, utp); |
|
520 |
_compat_endutent(); |
|
521 |
unlockut(); |
|
522 |
return (utp); |
|
523 |
} |
|
524 |
} |
|
525 |
} else { |
|
526 |
utp = _compat_pututline(utmp); |
|
527 |
if (utp) |
|
528 |
_compat_updwtmp(WTMP_FILE, utp); |
|
529 |
_compat_endutent(); |
|
530 |
return (utp); |
|
531 |
} |
|
532 |
} |
|
533 |
||
534 |
||
535 |
/* |
|
536 |
* _compat_modut - modify a utmp entry. |
|
537 |
* |
|
538 |
* args: utmp - point to utmp structure to be created |
|
539 |
*/ |
|
540 |
struct utmp * |
|
541 |
_compat_modut(struct utmp *utp) |
|
542 |
{ |
|
543 |
int i; /* scratch variable */ |
|
544 |
struct utmp utmp; /* holding area */ |
|
545 |
struct utmp *ucp = &utmp; /* and a pointer to it */ |
|
546 |
struct utmp *up; /* "current" utmp entry being examined */ |
|
547 |
struct futmp *fup; |
|
548 |
||
549 |
for (i = 0; i < IDLEN; ++i) |
|
550 |
if ((unsigned char)utp->ut_id[i] == SC_WILDC) |
|
551 |
return (0); |
|
552 |
||
553 |
/* copy the supplied utmp structure someplace safe */ |
|
554 |
utmp = *utp; |
|
555 |
_compat_setutent(); |
|
556 |
while (fup = getutent_frec()) { |
|
557 |
if (idcmp(ucp->ut_id, fup->ut_id)) |
|
558 |
continue; |
|
559 |
break; |
|
560 |
} |
|
561 |
up = _compat_pututline(ucp); |
|
562 |
if (up) |
|
563 |
_compat_updwtmp(WTMP_FILE, up); |
|
564 |
_compat_endutent(); |
|
565 |
return (up); |
|
566 |
} |
|
567 |
||
568 |
||
569 |
||
570 |
/* |
|
571 |
* idcmp - compare two id strings, return 0 if same, non-zero if not * |
|
572 |
* args: s1 - first id string |
|
573 |
* s2 - second id string |
|
574 |
*/ |
|
575 |
static int |
|
576 |
idcmp(const char *s1, const char *s2) |
|
577 |
{ |
|
578 |
int i; |
|
579 |
||
580 |
for (i = 0; i < IDLEN; ++i) |
|
581 |
if ((unsigned char)*s1 != SC_WILDC && (*s1++ != *s2++)) |
|
582 |
return (-1); |
|
583 |
return (0); |
|
584 |
} |
|
585 |
||
586 |
||
587 |
/* |
|
588 |
* allocid - allocate an unused id for utmp, either by recycling a |
|
589 |
* DEAD_PROCESS entry or creating a new one. This routine only |
|
590 |
* gets called if a wild card character was specified. |
|
591 |
* |
|
592 |
* args: srcid - pattern for new id |
|
593 |
* saveid - last id matching pattern for a non-dead process |
|
594 |
*/ |
|
595 |
static int |
|
596 |
allocid(char *srcid, unsigned char *saveid) |
|
597 |
{ |
|
598 |
int i; /* scratch variable */ |
|
599 |
int changed; /* flag to indicate that a new id has been generated */ |
|
600 |
char copyid[IDLEN]; /* work area */ |
|
601 |
||
602 |
(void) memcpy(copyid, srcid, IDLEN); |
|
603 |
changed = 0; |
|
604 |
for (i = 0; i < IDLEN; ++i) { |
|
605 |
/* |
|
606 |
* if this character isn't wild, it'll |
|
607 |
* be part of the generated id |
|
608 |
*/ |
|
609 |
if ((unsigned char) copyid[i] != SC_WILDC) |
|
610 |
continue; |
|
611 |
/* |
|
612 |
* it's a wild character, retrieve the |
|
613 |
* character from the saved id |
|
614 |
*/ |
|
615 |
copyid[i] = saveid[i]; |
|
616 |
/* |
|
617 |
* if we haven't changed anything yet, |
|
618 |
* try to find a new char to use |
|
619 |
*/ |
|
620 |
if (!changed && (saveid[i] < MAXVAL)) { |
|
621 |
||
622 |
/* |
|
623 |
* Note: this algorithm is taking the "last matched" id and trying to make |
|
624 |
* a 1 character change to it to create a new one. Rather than special-case |
|
625 |
* the first time (when no perturbation is really necessary), just don't |
|
626 |
* allocate the first valid id. |
|
627 |
*/ |
|
628 |
||
629 |
while (++saveid[i] < MAXVAL) { |
|
630 |
/* make sure new char is alphanumeric */ |
|
631 |
if (isalnum(saveid[i])) { |
|
632 |
copyid[i] = saveid[i]; |
|
633 |
changed = 1; |
|
634 |
break; |
|
635 |
} |
|
636 |
} |
|
637 |
||
638 |
if (!changed) { |
|
639 |
/* |
|
640 |
* Then 'reset' the current count at |
|
641 |
* this position to it's lowest valid |
|
642 |
* value, and propagate the carry to |
|
643 |
* the next wild-card slot |
|
644 |
* |
|
645 |
* See 1113208. |
|
646 |
*/ |
|
647 |
saveid[i] = 0; |
|
648 |
while (!isalnum(saveid[i])) |
|
649 |
saveid[i]++; |
|
650 |
copyid[i] = ++saveid[i]; |
|
651 |
} |
|
652 |
} |
|
653 |
} |
|
654 |
/* changed is true if we were successful in allocating an id */ |
|
655 |
if (changed) { |
|
656 |
(void) memcpy(srcid, copyid, IDLEN); |
|
657 |
return (0); |
|
658 |
} else |
|
659 |
return (-1); |
|
660 |
} |
|
661 |
||
662 |
||
663 |
/* |
|
664 |
* lockut - lock utmp file |
|
665 |
*/ |
|
666 |
static int |
|
667 |
lockut(void) |
|
668 |
{ |
|
669 |
if ((fd = open(_compat_utmpfile, O_RDWR|O_CREAT, 0644)) < 0) |
|
670 |
return (-1); |
|
671 |
||
672 |
if (lockf(fd, F_LOCK, 0) < 0) { |
|
673 |
(void) close(fd); |
|
674 |
fd = -1; |
|
675 |
return (-1); |
|
676 |
} |
|
677 |
return (0); |
|
678 |
} |
|
679 |
||
680 |
||
681 |
/* |
|
682 |
* unlockut - unlock utmp file |
|
683 |
*/ |
|
684 |
static void |
|
685 |
unlockut(void) |
|
686 |
{ |
|
687 |
(void) lockf(fd, F_ULOCK, 0); |
|
688 |
(void) close(fd); |
|
689 |
fd = -1; |
|
690 |
} |
|
691 |
||
692 |
||
693 |
||
694 |
#ifdef ERRDEBUG |
|
695 |
||
696 |
#include <stdarg.h> |
|
697 |
#include <stdio.h> |
|
698 |
||
699 |
static void |
|
700 |
gdebug(const char *fmt, ...) |
|
701 |
{ |
|
702 |
FILE *fp; |
|
703 |
int errnum; |
|
704 |
va_list ap; |
|
705 |
||
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
0
diff
changeset
|
706 |
if ((fp = fopen("/etc/dbg.getut", "a+F")) == NULL) |
0 | 707 |
return; |
708 |
va_start(ap, fmt); |
|
709 |
(void) vfprintf(fp, fmt, ap); |
|
710 |
va_end(ap); |
|
711 |
(void) fclose(fp); |
|
712 |
} |
|
713 |
#endif |