source: trunk/athena/lib/al/util.c @ 11480

Revision 11480, 8.6 KB checked in by ghudson, 26 years ago (diff)
Insert error string for new error code AL_ENOENT.
Line 
1/* Copyright 1997 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 */
15
16/* This file is part of the Athena login library.  It implements
17 * miscellaneous functions.
18 */
19
20static const char rcsid[] = "$Id: util.c,v 1.7 1998-05-07 17:08:13 ghudson Exp $";
21
22#include <sys/param.h>
23#include <assert.h>
24#include <string.h>
25#include <ctype.h>
26#include <stdlib.h>
27#include <pwd.h>
28#include "al.h"
29#include "al_private.h"
30
31#ifdef HAVE_MASTER_PASSWD
32#include <db.h>
33#include <utmp.h>
34#include <unistd.h>
35#include <fcntl.h>
36#include <sys/stat.h>
37#endif
38
39const char *al_strerror(int code, char **mem)
40{
41  /* A future implementation may want to handle internationalization.
42   * For now, just return a string literal from a table. */
43  const char *errtext[] = {
44    "Successful completion",
45    "Successful completion with some warnings",
46    "Bad Hesiod entry for user",
47    "Unknown username",
48    "You are not allowed to log into this machine",
49    "Logins currently disabled",
50    "You are not allowed to log into this machine remotely",
51    "Could not add user to passwd file",
52    "Could not modify user's session record",
53    "Permission denied while modifying system files",
54    "No such file or directory",
55    "Out of memory",
56    "Bad session record overwritten",
57    "Could not add you to group file",
58    "Using a temporary home directory created by a previous login",
59    "Attach failed; you have a temporary home directory",
60    "Attach failed; you have no home directory",
61    "Home directory attach is disabled on this machine"
62  };
63
64  assert(code >= 0 && code < (sizeof(errtext) / sizeof(*errtext)));
65  return errtext[code];
66}
67
68void al_free_errmem(char *mem)
69{
70  /* Do nothing for now. */
71}
72
73/* The next couple of functions (al__getpwnam() and al__getpwuid())
74 * are here because libal, being a library, shouldn't be stomping on
75 * the static memory returned by the native operating system's
76 * getpwnam() and getpwuid() calls.  Unfortunately, we have to write a
77 * lot of code which does the same thing as libc does.  Some day we
78 * may be able to assume that all modern platforms have getpwnam_r()
79 * and getpwuid_r() and have a single, simple version of these
80 * functions.
81 */
82
83#ifdef HAVE_MASTER_PASSWD
84static struct passwd *lookup(const DBT *key);
85
86struct passwd *al__getpwnam(const char *username)
87{
88  DBT key;
89  char buf[UT_NAMESIZE + 1];
90  int len;
91
92  /* Paranoia: don't find an empty username. */
93  if (!*username)
94    return NULL;
95  len = strlen(username);
96  if (len > UT_NAMESIZE)
97    len = UT_NAMESIZE;
98  buf[0] = _PW_KEYBYNAME;
99  memcpy(buf + 1, username, len);
100  key.data = buf;
101  key.size = len + 1;
102  return lookup(&key);
103}
104
105struct passwd *al__getpwuid(uid_t uid)
106{
107  DBT key;
108  char buf[128];
109
110  sprintf(buf, "%c%d", _PW_KEYBYUID, (int) uid);
111  key.data = buf;
112  key.size = strlen(buf);
113  return lookup(&key);
114}
115
116static struct passwd *lookup(const DBT *key)
117{
118  DB *db;
119  DBT value;
120  unsigned char buf[UT_NAMESIZE + 1];
121  int len, success = 0;
122  char *p, *buffer;
123  struct passwd *pwd;
124
125  /* Open the insecure or secure database depending on whether we're root. */
126  db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL);
127  if (!db)
128    db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
129  if (!db)
130    return NULL;
131
132  /* Look up the username. */
133  if (db->get(db, key, &value, 0) != 0)
134    {
135      db->close(db);
136      return NULL;
137    }
138  buffer = malloc(sizeof(struct passwd) + value.size);
139  if (!buffer)
140    {
141      db->close(db);
142      return NULL;
143    }
144  pwd = (struct passwd *) buffer;
145  buffer += sizeof(struct passwd);
146  memcpy(buffer, value.data, value.size);
147#define FIELD(v) v = buffer; buffer += strlen(buffer) + 1
148  FIELD(pwd->pw_name);
149  FIELD(pwd->pw_passwd);
150  memcpy(&pwd->pw_uid, buffer, sizeof(int));
151  memcpy(&pwd->pw_gid, buffer + sizeof(int), sizeof(int));
152  memcpy(&pwd->pw_change, buffer + 2 * sizeof(int), sizeof(time_t));
153  buffer += 2 * sizeof(int) + sizeof(time_t);
154  FIELD(pwd->pw_class);
155  FIELD(pwd->pw_gecos);
156  FIELD(pwd->pw_dir);
157  FIELD(pwd->pw_shell);
158  memcpy(&pwd->pw_expire, buffer, sizeof(time_t));
159  db->close(db);
160  return pwd;
161}
162
163#else /* HAVE_MASTER_PASSWD */
164
165static struct passwd *lookup(const char *username, uid_t uid);
166
167struct passwd *al__getpwnam(const char *username)
168{
169  /* Paranoia: don't find an empty username. */
170  if (!*username)
171    return NULL;
172  return lookup(username, 0);
173}
174
175struct passwd *al__getpwuid(uid_t uid)
176{
177  return lookup(NULL, uid);
178}
179
180/* If username is NULL, it's a lookup by uid; otherwise it's by name. */
181static struct passwd *lookup(const char *username, uid_t uid)
182{
183  /* BSD 4.3 has /etc/passwd and /etc/passwd.{dir,pag}.  Only implement
184   * reading /etc/passwd, since the DBM routines aren't reentrant and
185   * we don't really need that level of performance in the login system
186   * anyway. */
187  FILE *fp;
188  int linesize, len = (username) ? strlen(username) : 0;
189  struct passwd *pwd;
190  char *line = NULL, *buffer;
191  const char *p;
192
193  fp = fopen(PATH_PASSWD, "r");
194  if (!fp)
195    return NULL;
196
197  while (al__read_line(fp, &line, &linesize) == 0)
198    {
199      /* See if we got the right entry. */
200      if (username && (strncmp(line, username, len) != 0 || line[len] != ':'))
201        continue;
202      if (!username)
203        {
204          p = strchr(line, ':');
205          if (p)
206            p = strchr(p + 1, ':');
207          if (!p || atoi(p + 1) != uid)
208            continue;
209        }
210
211      /* Allocate space for the return value. */
212      buffer = malloc(sizeof(struct passwd) + strlen(line) + 1);
213      if (!buffer)
214        {
215          free(line);
216          fclose(fp);
217          return NULL;
218        }
219      pwd = (struct passwd *) buffer;
220      buffer += sizeof(struct passwd);
221      strcpy(buffer, line);
222
223#if defined(BSD) || defined(ultrix)
224      pwd->pw_quota = 0;
225      pwd->pw_comment = "";
226#endif
227
228      /* Set the fields of the returned structure. */
229#define BAD_LINE        { free(pwd); break; }
230#define NEXT_FIELD      { buffer = strchr(buffer, ':'); \
231        if (!buffer) BAD_LINE; *buffer++ = 0; }
232#define FIELD(v)        { v = buffer; NEXT_FIELD; }
233      FIELD(pwd->pw_name);
234      FIELD(pwd->pw_passwd);
235      if (!isdigit(*buffer))
236        BAD_LINE;
237      pwd->pw_uid = atoi(buffer);
238      NEXT_FIELD;
239      if (!isdigit(*buffer))
240        BAD_LINE;
241      pwd->pw_gid = atoi(buffer);
242      NEXT_FIELD;
243      FIELD(pwd->pw_gecos);
244      FIELD(pwd->pw_dir);
245      pwd->pw_shell = buffer;
246      buffer[strlen(buffer) - 1] = 0;
247      fclose(fp);
248      free(line);
249      return pwd;
250    }
251
252  /* We lost. */
253  free(line);
254  fclose(fp);
255  return NULL;
256}
257#endif /* HAVE_MASTER_PASSWD */
258
259void al__free_passwd(struct passwd *pwd)
260{
261  free(pwd);
262}
263
264/* This is an internal function.  Its contract is to read a line from a
265 * file into a dynamically allocated buffer, zeroing the trailing newline
266 * if there is one.  The calling routine may call al__read_line multiple
267 * times with the same buf and bufsize pointers; *buf will be reallocated
268 * and *bufsize adjusted as appropriate.  The initial value of *buf
269 * should be NULL.  After the calling routine is done reading lines, it
270 * should free *buf.  This function returns 0 if a line was successfully
271 * read, 1 if the file ended, and -1 if there was an I/O error or if it
272 * ran out of memory.
273 */
274
275int al__read_line(FILE *fp, char **buf, int *bufsize)
276{
277  char *newbuf;
278  int offset = 0, len;
279
280  if (*buf == NULL)
281    {
282      *buf = malloc(128);
283      if (!*buf)
284        return -1;
285      *bufsize = 128;
286    }
287
288  while (1)
289    {
290      if (!fgets(*buf + offset, *bufsize - offset, fp))
291        return (offset != 0) ? 0 : (ferror(fp)) ? -1 : 1;
292      len = offset + strlen(*buf + offset);
293      if ((*buf)[len - 1] == '\n')
294        {
295          (*buf)[len - 1] = 0;
296          return 0;
297        }
298      offset = len;
299
300      /* Allocate more space. */
301      newbuf = realloc(*buf, *bufsize * 2);
302      if (!newbuf)
303        return -1;
304      *buf = newbuf;
305      *bufsize *= 2;
306    }
307}
308
309/* Disallow usernames which might walk the filesystem, usernames which
310 * contain nonprintables, or usernames which might not play nice with the
311 * passwd file. */
312int al__username_valid(const char *username)
313{
314  if (!*username || *username == '.')
315    return 0;
316  for (; *username; username++)
317    {
318      if (!isprint(*username) || *username == '/' || *username == ':')
319        return 0;
320    }
321  return 1;
322}
Note: See TracBrowser for help on using the repository browser.