aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2014-09-12 10:27:43 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2014-09-12 10:27:43 +0300
commita7927772940897e89f806f8bd4bce7967c03076a (patch)
treec31bd0fc9be1bb0efe3a3d74182175e6316aa26b
parent05bf037ee1bb67dcb2022f4e1938ece5c4e4581e (diff)
downloadpam-modules-a7927772940897e89f806f8bd4bce7967c03076a.tar.gz
pam-modules-a7927772940897e89f806f8bd4bce7967c03076a.tar.bz2
Provide a way to keep user-defined pubkeys in file.
A user can add his public keys to the authorized_keys file without disturbing the key synchronization from the LDAP database. The #:end comment in the file marks the end of area synchronized with LDAP. Everything below this comment is preserved intact. * pam_ldaphome/pam_ldaphome.c (pubkeyfile): New struct. (pubkeyfile_open,pubkeyfile_read,pubkeyfile_init) (pubkeyfile_write,pubkeyfile_remove_lines) (pubkeyfile_alloc_lines,pubkeyfile_insert_lines) (pubkeyfile_close): New functions. (store_pubkeys): Use pubkeyfile functions to operate on the authorized_keys file.
-rw-r--r--pam_ldaphome/pam_ldaphome.c261
1 files changed, 219 insertions, 42 deletions
diff --git a/pam_ldaphome/pam_ldaphome.c b/pam_ldaphome/pam_ldaphome.c
index 6320e87..8429b97 100644
--- a/pam_ldaphome/pam_ldaphome.c
+++ b/pam_ldaphome/pam_ldaphome.c
@@ -1252,17 +1252,195 @@ populate_homedir(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
1252 return rc; 1252 return rc;
1253} 1253}
1254 1254
1255/* Operations on public key files */
1256
1257struct pubkeyfile {
1258 char *file_name; /* Name of the file */
1259 int fd; /* File descriptor */
1260 char *base; /* File contents */
1261 size_t size; /* Size of base */
1262 char **lnv; /* File contents parsed into nul-terminated lines */
1263 size_t lnc; /* Number of lines in lnv */
1264 size_t lnm; /* Max. capacity of lnv */
1265};
1266
1267/* Open public key file NAME. Return 0 on success. On error, issue a
1268 diagnostic message and return -1. */
1269static int
1270pubkeyfile_open(struct pubkeyfile *pkb, char *name)
1271{
1272 memset(pkb, 0, sizeof *pkb);
1273 pkb->fd = open(name, O_CREAT|O_RDWR, 0666);
1274 if (pkb->fd == -1) {
1275 _pam_log(LOG_ERR, "can't open %s: %s",
1276 name, strerror(errno));
1277 return -1;
1278 }
1279 pkb->file_name = gray_strdup(name);
1280 return 0;
1281}
1282
1283/* Read in the contents of the open public key file PKB. */
1284static int
1285pubkeyfile_read(struct pubkeyfile *pkb)
1286{
1287 struct stat st;
1288 char *p;
1289 size_t i;
1290
1291 if (fstat(pkb->fd, &st)) {
1292 _pam_log(LOG_ERR, "fstat %s: %s",
1293 pkb->file_name, strerror(errno));
1294 return -1;
1295 }
1296 pkb->size = st.st_size;
1297 pkb->base = gray_malloc(st.st_size + 1);
1298 if (full_read(pkb->fd, pkb->file_name, pkb->base, pkb->size)) {
1299 _pam_log(LOG_ERR, "fread %s: %s",
1300 pkb->file_name, strerror(errno));
1301 return -1;
1302 }
1303 pkb->base[pkb->size] = 0;
1304 pkb->lnc = 0;
1305 for (p = pkb->base; *p; p++)
1306 if (*p == '\n')
1307 ++pkb->lnc;
1308 pkb->lnm = pkb->lnc + 1;
1309 pkb->lnv = gray_calloc(pkb->lnm, sizeof(pkb->lnv[0]));
1310
1311 i = 0;
1312 for (p = pkb->base; *p; p++) {
1313 if (p == pkb->base || p[-1] == 0)
1314 pkb->lnv[i++] = p;
1315 if (*p == '\n')
1316 *p = 0;
1317 }
1318 pkb->lnv[i] = NULL;
1319 return 0;
1320}
1321
1322/* Open the public key file NAME and read its contents. */
1323static int
1324pubkeyfile_init(struct pubkeyfile *pkb, char *name)
1325{
1326 if (pubkeyfile_open(pkb, name))
1327 return -1;
1328 return pubkeyfile_read(pkb);
1329}
1330
1331/* Write data from lnv into the public key file, overwriting its current
1332 content. */
1333static int
1334pubkeyfile_write(struct pubkeyfile *pkb)
1335{
1336 int i;
1337
1338 if (lseek(pkb->fd, 0, SEEK_SET)) {
1339 _pam_log(LOG_ERR, "lseek %s: %s",
1340 pkb->file_name, strerror(errno));
1341 return -1;
1342 }
1343 if (ftruncate(pkb->fd, 0)) {
1344 _pam_log(LOG_ERR, "ftruncate %s: %s",
1345 pkb->file_name, strerror(errno));
1346 return -1;
1347 }
1348
1349 for (i = 0; i < pkb->lnc; i++) {
1350 if (pkb->lnv[i]) {
1351 static char newline = '\n';
1352 size_t len = strlen(pkb->lnv[i]);
1353 if (write(pkb->fd, pkb->lnv[i], len) != len
1354 || write(pkb->fd, &newline, 1) != 1) {
1355 _pam_log(LOG_ERR, "error writing %s: %s",
1356 pkb->file_name, strerror(errno));
1357 return -1;
1358 }
1359 }
1360 }
1361 return 0;
1362}
1363
1364/* Remove COUNT lines starting from position POS in PKB. */
1365static void
1366pubkeyfile_remove_lines(struct pubkeyfile *pkb, int pos, int count)
1367{
1368 if (count == 0)
1369 return;
1370 if (pos > pkb->lnc) {
1371 _pam_log(LOG_ERR, "%s:%d: INTERNAL ERROR: pos out of range",
1372 __FILE__, __LINE__);
1373 abort();
1374 }
1375 if (pos + count > pkb->lnc) {
1376 _pam_log(LOG_ERR, "%s:%d: INTERNAL ERROR: count out of range",
1377 __FILE__, __LINE__);
1378 abort();
1379 }
1380 memmove(pkb->lnv + pos, pkb->lnv + pos + count,
1381 (pkb->lnc - pos - count + 1) * sizeof(pkb->lnv[0]));
1382 pkb->lnc -= count;
1383}
1384
1385/* Allocate COUNT lines starting from position POS in PKB, preserving
1386 the existing data. */
1387static void
1388pubkeyfile_alloc_lines(struct pubkeyfile *pkb, size_t pos, size_t count)
1389{
1390 if (pos > pkb->lnc) {
1391 _pam_log(LOG_ERR, "%s:%d: INTERNAL ERROR: pos out of range",
1392 __FILE__, __LINE__);
1393 abort();
1394 }
1395 if (pkb->lnc + count + 1 > pkb->lnm) {
1396 pkb->lnm += count;
1397 pkb->lnv = gray_realloc(pkb->lnv,
1398 pkb->lnm * sizeof(pkb->lnv[0]));
1399 }
1400 memmove(pkb->lnv + pos + count, pkb->lnv + pos,
1401 (pkb->lnc - pos + 1) * sizeof(pkb->lnv[0]));
1402 pkb->lnc += count;
1403}
1404
1405/* Insert lines from LV in position POS in the file PKB, shifting down
1406 existing lines as necessary. */
1407void
1408pubkeyfile_insert_lines(struct pubkeyfile *pkb, size_t pos, char **lv)
1409{
1410 size_t i;
1411 size_t lc;
1412
1413 for (lc = 0; lv[lc]; lc++)
1414 ;
1415
1416 pubkeyfile_alloc_lines(pkb, pos, lc);
1417
1418 for (i = 0; i < lc; i++)
1419 pkb->lnv[pos + i] = lv[i];
1420}
1421
1422/* Close the public key file */
1423void
1424pubkeyfile_close(struct pubkeyfile *pkb)
1425{
1426 close(pkb->fd);
1427 free(pkb->file_name);
1428 free(pkb->base);
1429 free(pkb->lnv);
1430}
1431
1432
1255static int 1433static int
1256store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env) 1434store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env)
1257{ 1435{
1258 FILE *fp; 1436 int rc;
1259 int c;
1260 char *file_name; 1437 char *file_name;
1261 size_t homelen, pathlen, len; 1438 size_t homelen, pathlen, len;
1262 int retval, i; 1439 int retval, i, j;
1263 int update = 0; 1440 int update = 0;
1264 int oldmask; 1441 int oldmask;
1265 unsigned long mode; 1442 unsigned long mode;
1443 struct pubkeyfile pkf;
1266 1444
1267 homelen = strlen(pw->pw_dir); 1445 homelen = strlen(pw->pw_dir);
1268 pathlen = strlen(authorized_keys_file); 1446 pathlen = strlen(authorized_keys_file);
@@ -1285,66 +1463,65 @@ store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env)
1285 oldmask = umask(0666 ^ (mode & 0777)); 1463 oldmask = umask(0666 ^ (mode & 0777));
1286 } 1464 }
1287 1465
1288 fp = fopen(file_name, "r+"); 1466 if (access(file_name, R_OK)
1289 if (!fp && create_interdir(file_name, pw) == 0) { 1467 && create_interdir(file_name, pw) == 0) {
1290 fp = fopen(file_name, "w"); 1468 update = 1;
1291 update =