ypdb.c revision 1.13
1/* $NetBSD: ypdb.c,v 1.13 2023/08/01 08:47:25 mrg Exp $ */ 2 3/* 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Margo Seltzer. 10 * 11 * This code is derived from ndbm module of BSD4.4 db (hash) by 12 * Mats O Jansson 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 27 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 30 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39#include <sys/cdefs.h> 40#ifndef lint 41__RCSID("$NetBSD: ypdb.c,v 1.13 2023/08/01 08:47:25 mrg Exp $"); 42#endif 43 44#include <sys/param.h> 45#include <sys/types.h> 46#include <sys/stat.h> 47 48#include <db.h> 49#include <err.h> 50#include <errno.h> 51#include <fcntl.h> 52#include <stdio.h> 53#include <stdlib.h> 54#include <string.h> 55#include <unistd.h> 56 57#include <rpcsvc/yp.h> 58 59#include "ypdb.h" 60 61static DBM *_ypdb_dbopen(const char *, int, mode_t); 62 63/* 64 * ypdb_open -- 65 * dbopen(3) file, read-only. 66 * First ensure that file has a suffix of YPDB_SUFFIX. 67 * Try opening as a DB_BTREE first, then DB_HASH. 68 * 69 * Returns: 70 * *DBM on success 71 * NULL on failure 72 */ 73 74DBM * 75ypdb_open(const char *file) 76{ 77 char path[MAXPATHLEN]; 78 const char *cp, *suffix; 79 80 cp = strrchr(file, '.'); 81 if (cp != NULL && strcmp(cp, YPDB_SUFFIX) == 0) 82 suffix = ""; 83 else 84 suffix = YPDB_SUFFIX; 85 if ((size_t)snprintf(path, sizeof(path), "%s%s", file, suffix) > 86 sizeof(path)) { 87 warnx("File name `%s' is too long", file); 88 return NULL; 89 } 90 return _ypdb_dbopen(path, O_RDONLY, 0444); 91} 92 93/* 94 * ypdb_mktemp -- 95 * Create a temporary file using mkstemp(3) based on the 96 * template provided in file. 97 * dbopen(3) file, read-write, 0644 (modified by umask(2)). 98 * Try opening as a DB_BTREE first, then DB_HASH. 99 * file won't have YPDB_SUFFIX. 100 * 101 * Returns: 102 * *DBM on success; file now exists. 103 * NULL on failure 104 */ 105 106DBM * 107ypdb_mktemp(char *file) 108{ 109 int fd = -1; 110 DBM *db = NULL; 111 mode_t myumask; 112 int save_errno; 113 114 if ((fd = mkstemp(file)) == -1) 115 return NULL; 116 117 myumask = umask(0); 118 (void)umask(myumask); 119 if (fchmod(fd, 0644 & ~myumask) == -1) 120 goto bad; 121 122 (void) close(fd); 123 fd = -1; 124 125 if ((db = _ypdb_dbopen(file, O_RDWR, 0644)) == NULL) 126 goto bad; 127 128 return db; 129 130 bad: 131 save_errno = errno; 132 if (fd != 1) 133 (void) close(fd); 134 (void) unlink(file); 135 errno = save_errno; 136 return NULL; 137} 138 139/* 140 * _ypdb_dbopen -- 141 * dbopen(3) path with the flags & mode. 142 * Try opening as a DB_BTREE first, then DB_HASH. 143 */ 144 145static DBM * 146_ypdb_dbopen(const char *path, int flags, mode_t mode) 147{ 148 DBM *db; 149 BTREEINFO info; 150 151 /* try our btree format first */ 152 info.flags = 0; 153 info.cachesize = 0; 154 info.maxkeypage = 0; 155 info.minkeypage = 0; 156 info.psize = 0; 157 info.compare = NULL; 158 info.prefix = NULL; 159 info.lorder = 0; 160 db = (DBM *)dbopen(path, flags, mode, DB_BTREE, (void *)&info); 161 if (db != NULL || errno != EFTYPE) 162 return (db); 163 164 /* fallback to standard hash (for sendmail's aliases.db) */ 165 db = (DBM *)dbopen(path, flags, mode, DB_HASH, NULL); 166 return (db); 167} 168 169/* 170 * ypdb_close -- 171 * Close the db 172 */ 173 174void 175ypdb_close(DBM *db) 176{ 177 (void)(db->close)(db); 178} 179 180/* 181 * Returns: 182 * DATUM on success 183 * NULL on failure 184 */ 185 186datum 187ypdb_fetch(DBM *db, datum key) 188{ 189 datum retkey; 190 DBT nk, nd; 191 int status; 192 193 nk.data = key.dptr; 194 nk.size = key.dsize; 195 status = (db->get)(db, &nk, &nd, 0); 196 if (status) { 197 retkey.dptr = NULL; 198 retkey.dsize = 0; 199 } else { 200 retkey.dptr = nd.data; 201 retkey.dsize = nd.size; 202 } 203 return (retkey); 204} 205 206/* 207 * Returns: 208 * DATUM on success 209 * NULL on failure 210 */ 211 212datum 213ypdb_firstkey(DBM *db) 214{ 215 int status; 216 datum retkey; 217 DBT nk, nd; 218 219 status = (db->seq)(db, &nk, &nd, R_FIRST); 220 if (status) { 221 retkey.dptr = NULL; 222 retkey.dsize = 0; 223 } else { 224 retkey.dptr = nk.data; 225 retkey.dsize = nk.size; 226 } 227 return (retkey); 228} 229 230/* 231 * Returns: 232 * DATUM on success 233 * NULL on failure 234 */ 235 236datum 237ypdb_nextkey(DBM *db) 238{ 239 int status; 240 datum retkey; 241 DBT nk, nd; 242 243 status = (db->seq)(db, &nk, &nd, R_NEXT); 244 if (status) { 245 retkey.dptr = NULL; 246 retkey.dsize = 0; 247 } else { 248 retkey.dptr = nk.data; 249 retkey.dsize = nk.size; 250 } 251 return (retkey); 252} 253 254/* 255 * Returns: 256 * DATUM on success 257 * NULL on failure 258 */ 259 260datum 261ypdb_setkey(DBM *db, datum key) 262{ 263 int status; 264 DBT nk, nd; 265 266 nk.data = key.dptr; 267 nk.size = key.dsize; 268 status = (db->seq)(db, &nk, &nd, R_CURSOR); 269 if (status) { 270 key.dptr = NULL; 271 key.dsize = 0; 272 } 273 return (key); 274} 275 276/* 277 * Returns: 278 * 0 on success 279 * <0 failure 280 */ 281 282int 283ypdb_delete(DBM *db, datum key) 284{ 285 int status; 286 DBT nk; 287 288 nk.data = key.dptr; 289 nk.size = key.dsize; 290 status = (db->del)(db, &nk, 0); 291 if (status) 292 return (-1); 293 else 294 return (0); 295} 296 297/* 298 * Returns: 299 * 0 on success 300 * <0 failure 301 * 1 if YPDB_INSERT and entry exists 302 */ 303 304int 305ypdb_store(DBM *db, datum key, datum content, int flags) 306{ 307 DBT nk, nd; 308 309 if (key.dsize > YPMAXRECORD || content.dsize > YPMAXRECORD) 310 return -1; 311 nk.data = key.dptr; 312 nk.size = key.dsize; 313 nd.data = content.dptr; 314 nd.size = content.dsize; 315 return ((db->put)(db, &nk, &nd, 316 (flags == YPDB_INSERT) ? R_NOOVERWRITE : 0)); 317} 318