smdb.c revision 64562
1/*
2** Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
3**	All rights reserved.
4**
5** By using this file, you agree to the terms and conditions set
6** forth in the LICENSE file which can be found at the top level of
7** the sendmail distribution.
8*/
9
10#ifndef lint
11static char id[] = "@(#)$Id: smdb.c,v 8.37.4.1 2000/05/25 18:56:09 gshapiro Exp $";
12#endif /* ! lint */
13
14#include <fcntl.h>
15#include <stdlib.h>
16#include <unistd.h>
17
18
19#include <sendmail/sendmail.h>
20#include <libsmdb/smdb.h>
21
22/*
23** SMDB_MALLOC_DATABASE -- Allocates a database structure.
24**
25**	Parameters:
26**		None
27**
28**	Returns:
29**		An pointer to an allocated SMDB_DATABASE structure or
30**		NULL if it couldn't allocate the memory.
31*/
32
33SMDB_DATABASE *
34smdb_malloc_database()
35{
36	SMDB_DATABASE *db;
37
38	db = (SMDB_DATABASE *) malloc(sizeof(SMDB_DATABASE));
39
40	if (db != NULL)
41		memset(db, '\0', sizeof(SMDB_DATABASE));
42
43	return db;
44}
45
46
47/*
48** SMDB_FREE_DATABASE -- Unallocates a database structure.
49**
50**	Parameters:
51**		database -- a SMDB_DATABASE pointer to deallocate.
52**
53**	Returns:
54**		None
55*/
56
57void
58smdb_free_database(database)
59	SMDB_DATABASE *database;
60{
61	if (database != NULL)
62		free(database);
63}
64
65
66/*
67** SMDB_OPEN_DATABASE -- Opens a database.
68**
69**	This opens a database. If type is SMDB_DEFAULT it tries to
70**	use a DB1 or DB2 hash. If that isn't available, it will try
71**	to use NDBM. If a specific type is given it will try to open
72**	a database of that type.
73**
74**	Parameters:
75**		database -- An pointer to a SMDB_DATABASE pointer where the
76**			   opened database will be stored. This should
77**			   be unallocated.
78**		db_name -- The name of the database to open. Do not include
79**			  the file name extension.
80**		mode -- The mode to set on the database file or files.
81**		mode_mask -- Mode bits that must match on an opened database.
82**		sff -- Flags to safefile.
83**		type -- The type of database to open. Supported types
84**		       vary depending on what was compiled in.
85**		user_info -- Information on the user to use for file
86**			    permissions.
87**		params -- Params specific to the database being opened.
88**			 Only supports some DB hash options right now
89**			 (see smdb_db_open() for details).
90**
91**	Returns:
92**		SMDBE_OK -- Success.
93**		Anything else is an error. Look up more info about the
94**		error in the comments for the specific open() used.
95*/
96
97int
98smdb_open_database(database, db_name, mode, mode_mask, sff, type, user_info,
99		   params)
100	SMDB_DATABASE **database;
101	char *db_name;
102	int mode;
103	int mode_mask;
104	long sff;
105	SMDB_DBTYPE type;
106	SMDB_USER_INFO *user_info;
107	SMDB_DBPARAMS *params;
108{
109	int result;
110	bool type_was_default = FALSE;
111
112	if (type == SMDB_TYPE_DEFAULT)
113	{
114		type_was_default = TRUE;
115#ifdef NEWDB
116		type = SMDB_TYPE_HASH;
117#else /* NEWDB */
118# ifdef NDBM
119		type = SMDB_TYPE_NDBM;
120# endif /* NDBM */
121#endif /* NEWDB */
122	}
123
124	if (type == SMDB_TYPE_DEFAULT)
125		return SMDBE_UNKNOWN_DB_TYPE;
126
127	if ((strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0) ||
128	    (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0))
129	{
130#ifdef NEWDB
131		result = smdb_db_open(database, db_name, mode, mode_mask, sff,
132				      type, user_info, params);
133# ifdef NDBM
134		if (result == ENOENT && type_was_default)
135			type = SMDB_TYPE_NDBM;
136		else
137# endif /* NDBM */
138			return result;
139#else /* NEWDB */
140		return SMDBE_UNSUPPORTED_DB_TYPE;
141#endif /* NEWDB */
142	}
143
144	if (strncmp(type, SMDB_TYPE_NDBM, SMDB_TYPE_NDBM_LEN) == 0)
145	{
146#ifdef NDBM
147		result = smdb_ndbm_open(database, db_name, mode, mode_mask,
148					sff, type, user_info, params);
149		return result;
150#else /* NDBM */
151		return SMDBE_UNSUPPORTED_DB_TYPE;
152#endif /* NDBM */
153	}
154
155	return SMDBE_UNKNOWN_DB_TYPE;
156}
157
158/*
159** SMDB_ADD_EXTENSION -- Adds an extension to a file name.
160**
161**	Just adds a . followed by a string to a db_name if there
162**	is room and the db_name does not already have that extension.
163**
164**	Parameters:
165**		full_name -- The final file name.
166**		max_full_name_len -- The max length for full_name.
167**		db_name -- The name of the db.
168**		extension -- The extension to add.
169**
170**	Returns:
171**		SMDBE_OK -- Success.
172**		Anything else is an error. Look up more info about the
173**		error in the comments for the specific open() used.
174*/
175
176int
177smdb_add_extension(full_name, max_full_name_len, db_name, extension)
178	char *full_name;
179	int max_full_name_len;
180	char *db_name;
181	char *extension;
182{
183	int extension_len;
184	int db_name_len;
185
186	if (full_name == NULL || db_name == NULL || extension == NULL)
187		return SMDBE_INVALID_PARAMETER;
188
189	extension_len = strlen(extension);
190	db_name_len = strlen(db_name);
191
192	if (extension_len + db_name_len + 2 > max_full_name_len)
193		return SMDBE_DB_NAME_TOO_LONG;
194
195	if (db_name_len < extension_len + 1 ||
196	    db_name[db_name_len - extension_len - 1] != '.' ||
197	    strcmp(&db_name[db_name_len - extension_len], extension) != 0)
198		snprintf(full_name, max_full_name_len, "%s.%s", db_name,
199			 extension);
200	else
201		(void) strlcpy(full_name, db_name, max_full_name_len);
202
203	return SMDBE_OK;
204}
205
206/*
207**  SMDB_LOCK_FILE -- Locks the database file.
208**
209**	Locks the actual database file.
210**
211**	Parameters:
212**		lock_fd -- The resulting descriptor for the locked file.
213**		db_name -- The name of the database without extension.
214**		mode -- The open mode.
215**		sff -- Flags to safefile.
216**		extension -- The extension for the file.
217**
218**	Returns:
219**		SMDBE_OK -- Success, otherwise errno.
220*/
221
222int
223smdb_lock_file(lock_fd, db_name, mode, sff, extension)
224	int *lock_fd;
225	char *db_name;
226	int mode;
227	long sff;
228	char *extension;
229{
230	int result;
231	char file_name[SMDB_MAX_NAME_LEN];
232
233	result = smdb_add_extension(file_name, SMDB_MAX_NAME_LEN, db_name,
234				    extension);
235	if (result != SMDBE_OK)
236		return result;
237
238	*lock_fd = safeopen(file_name, mode & ~O_TRUNC, 0644, sff);
239	if (*lock_fd < 0)
240		return errno;
241
242	return SMDBE_OK;
243}
244
245/*
246**  SMDB_UNLOCK_FILE -- Unlocks a file
247**
248**	Unlocks a file.
249**
250**	Parameters:
251**		lock_fd -- The descriptor for the locked file.
252**
253**	Returns:
254**		SMDBE_OK -- Success, otherwise errno.
255*/
256
257int
258smdb_unlock_file(lock_fd)
259	int lock_fd;
260{
261	int result;
262
263	result = close(lock_fd);
264	if (result != 0)
265		return errno;
266
267	return SMDBE_OK;
268}
269
270/*
271**  SMDB_SETUP_FILE -- Gets db file ready for use.
272**
273**	Makes sure permissions on file are safe and creates it if it
274**	doesn't exist.
275**
276**	Parameters:
277**		db_name -- The name of the database without extension.
278**		extension -- The extension.
279**		sff -- Flags to safefile.
280**		mode_mask -- Mode bits that must match.
281**		user_info -- Information on the user to use for file
282**			    permissions.
283**		stat_info -- A place to put the stat info for the file.
284**	Returns:
285**		SMDBE_OK -- Success, otherwise errno.
286*/
287
288int
289smdb_setup_file(db_name, extension, mode_mask, sff, user_info, stat_info)
290	char *db_name;
291	char *extension;
292	int mode_mask;
293	long sff;
294	SMDB_USER_INFO *user_info;
295	struct stat *stat_info;
296{
297	int st;
298	int result;
299	char db_file_name[SMDB_MAX_NAME_LEN];
300
301	result = smdb_add_extension(db_file_name, SMDB_MAX_NAME_LEN, db_name,
302				    extension);
303	if (result != SMDBE_OK)
304		return result;
305
306	st = safefile(db_file_name, user_info->smdbu_id,
307		      user_info->smdbu_group_id, user_info->smdbu_name,
308		      sff, mode_mask, stat_info);
309	if (st != 0)
310		return st;
311
312	return SMDBE_OK;
313}
314
315/*
316**  SMDB_FILECHANGED -- Checks to see if a file changed.
317**
318**	Compares the passed in stat_info with a current stat on
319**	the passed in file descriptor. Check filechanged for
320**	return values.
321**
322**	Parameters:
323**		db_name -- The name of the database without extension.
324**		extension -- The extension.
325**		db_fd -- A file descriptor for the database file.
326**		stat_info -- An old stat_info.
327**	Returns:
328**		SMDBE_OK -- Success, otherwise errno.
329*/
330
331int
332smdb_filechanged(db_name, extension, db_fd, stat_info)
333	char *db_name;
334	char *extension;
335	int db_fd;
336	struct stat *stat_info;
337{
338	int result;
339	char db_file_name[SMDB_MAX_NAME_LEN];
340
341	result = smdb_add_extension(db_file_name, SMDB_MAX_NAME_LEN, db_name,
342				    extension);
343	if (result != SMDBE_OK)
344		return result;
345
346	result = filechanged(db_file_name, db_fd, stat_info);
347
348	return result;
349}
350/*
351** SMDB_PRINT_AVAILABLE_TYPES -- Prints the names of the available types.
352**
353**	Parameters:
354**		None
355**
356**	Returns:
357**		None
358*/
359
360void
361smdb_print_available_types()
362{
363#ifdef NDBM
364	printf("dbm\n");
365#endif /* NDBM */
366#ifdef NEWDB
367	printf("hash\n");
368	printf("btree\n");
369#endif /* NEWDB */
370}
371/*
372** SMDB_DB_DEFINITION -- Given a database type, return database definition
373**
374**	Reads though a structure making an association with the database
375**	type and the required cpp define from sendmail/README.
376**	List size is dynamic and must be NULL terminated.
377**
378**	Parameters:
379**		type -- The name of the database type.
380**
381**	Returns:
382**		definition for type, otherwise NULL.
383*/
384
385typedef struct
386{
387	SMDB_DBTYPE type;
388	char *dbdef;
389} dbtype;
390
391static dbtype DatabaseDefs[] =
392{
393	{ SMDB_TYPE_HASH,	"NEWDB" },
394	{ SMDB_TYPE_BTREE,	"NEWDB" },
395	{ SMDB_TYPE_NDBM,	"NDBM"	},
396	{ NULL,			"OOPS"	}
397};
398
399char *
400smdb_db_definition(type)
401	SMDB_DBTYPE type;
402{
403	dbtype *ptr = DatabaseDefs;
404
405	while (ptr != NULL && ptr->type != NULL)
406	{
407		if (strcmp(type, ptr->type) == 0)
408			return ptr->dbdef;
409		ptr++;
410	}
411	return NULL;
412}
413