diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-09-12 10:27:43 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-09-12 10:27:43 +0300 |
commit | a7927772940897e89f806f8bd4bce7967c03076a (patch) | |
tree | c31bd0fc9be1bb0efe3a3d74182175e6316aa26b | |
parent | 05bf037ee1bb67dcb2022f4e1938ece5c4e4581e (diff) | |
download | pam-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.c | 261 |
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 | |||
1257 | struct 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. */ | ||
1269 | static int | ||
1270 | pubkeyfile_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. */ | ||
1284 | static int | ||
1285 | pubkeyfile_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. */ | ||
1323 | static int | ||
1324 | pubkeyfile_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. */ | ||
1333 | static int | ||
1334 | pubkeyfile_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. */ | ||
1365 | static void | ||
1366 | pubkeyfile_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. */ | ||
1387 | static void | ||
1388 | pubkeyfile_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. */ | ||
1407 | void | ||
1408 | pubkeyfile_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 */ | ||
1423 | void | ||
1424 | pubkeyfile_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 | |||
1255 | static int | 1433 | static int |
1256 | store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env) | 1434 | store_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 = |