]> git.ozlabs.org Git - petitboot/blob - lib/crypt/crypt.c
discover: Recognise and open LUKS encrypted partitions
[petitboot] / lib / crypt / crypt.c
1 /*
2  *  Copyright (C) 2018 IBM Corporation
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; version 2 of the License.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  */
14 #include <string.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <shadow.h>
18 #include <crypt.h>
19 #include <errno.h>
20
21 #include <talloc/talloc.h>
22 #include <log/log.h>
23
24 #include "crypt.h"
25
26 int crypt_set_password_hash(void *ctx, const char *hash)
27 {
28         struct spwd **shadow, *entry;
29         bool found_root;
30         int rc, i, n;
31         FILE *fp;
32
33         if (lckpwdf()) {
34                 pb_log("Could not obtain access to shadow file\n");
35                 return -1;
36         }
37         setspent();
38
39         found_root = false;
40         shadow = NULL;
41         n = 0;
42
43         /* Read all entries and modify the root entry */
44         errno = 0;
45         fp = fopen("/etc/shadow", "r");
46         if (!fp) {
47                 pb_log("Could not open shadow file, %m\n");
48                 rc = -1;
49                 goto out;
50         }
51
52         entry = fgetspent(fp);
53         while (entry) {
54                 shadow = talloc_realloc(ctx, shadow, struct spwd *, n + 1);
55                 if (!shadow) {
56                         pb_log("Failed to allocate shadow struct\n");
57                         rc = -1;
58                         goto out;
59                 }
60
61                 shadow[n] = talloc_memdup(shadow, entry, sizeof(struct spwd));
62                 if (!shadow[n]) {
63                         pb_log("Could not duplicate entry for %s\n",
64                                         entry->sp_namp);
65                         rc = -1;
66                         goto out;
67                 }
68
69                 shadow[n]->sp_namp = talloc_strdup(shadow, entry->sp_namp);
70                 if (strncmp(shadow[n]->sp_namp, "root", strlen("root")) == 0) {
71                         shadow[n]->sp_pwdp = talloc_strdup(shadow, hash);
72                         found_root = true;
73                 } else {
74                         shadow[n]->sp_pwdp = talloc_strdup(shadow,
75                                         entry->sp_pwdp);
76                 }
77
78                 if (!shadow[n]->sp_namp || !shadow[n]->sp_pwdp) {
79                         pb_log("Failed to allocate new fields for %s\n",
80                                         entry->sp_namp);
81                         rc = -1;
82                         goto out;
83                 }
84
85                 n++;
86                 entry = fgetspent(fp);
87         }
88
89         if (n == 0)
90                 pb_debug_fn("No entries found\n");
91
92         fclose(fp);
93
94         if (!found_root) {
95                 /* Make our own */
96                 pb_debug_fn("No root user found, creating entry\n");
97                 shadow = talloc_realloc(ctx, shadow, struct spwd *, n + 1);
98                 if (!shadow) {
99                         pb_log("Failed to allocate shadow struct\n");
100                         rc = -1;
101                         goto out;
102                 }
103
104                 shadow[n] = talloc_zero(shadow, struct spwd);
105                 shadow[n]->sp_namp = talloc_asprintf(shadow, "root");
106                 shadow[n]->sp_pwdp = talloc_strdup(shadow, hash);
107                 if (!shadow[n]->sp_namp || !shadow[n]->sp_pwdp) {
108                         pb_log("Failed to allocate new fields for root entry\n");
109                         rc = -1;
110                         goto out;
111                 }
112                 n++;
113         }
114
115         errno = 0;
116         fp = fopen("/etc/shadow", "w");
117         if (!fp) {
118                 pb_log("Could not open shadow file, %m\n");
119                 rc = -1;
120                 goto out;
121         }
122
123         /* Write each entry back to keep the same format in /etc/shadow */
124         for (i = 0; i < n; i++) {
125                 rc = putspent(shadow[i], fp);
126                 if (rc)
127                         pb_log("Failed to write back shadow entry for %s!\n",
128                                         shadow[i]->sp_namp);
129         }
130
131         rc = 0;
132 out:
133         if (fp)
134                 fclose(fp);
135         talloc_free(shadow);
136         endspent();
137         ulckpwdf();
138         return rc;
139 }
140
141 static const char *crypt_hash_password(const char *password)
142 {
143         struct spwd *shadow;
144         char *hash, *salt;
145         char new_salt[17];
146         int i;
147
148         shadow = getspnam("root");
149         if (!shadow) {
150                 pb_log("Could not find root shadow\n");
151                 return NULL;
152         }
153
154         if (shadow->sp_pwdp && strlen(shadow->sp_pwdp)) {
155                 salt = shadow->sp_pwdp;
156         } else {
157                 for (i = 0; i < 16; i++)
158                         new_salt[i] = random() % 94 + 32;
159                 new_salt[i] = '\0';
160                 salt = talloc_asprintf(password, "$6$%s", new_salt);
161         }
162
163         hash = crypt(password ?: "", salt);
164         if (!hash)
165                 pb_log("Could not create hash, %m\n");
166
167
168         return hash;
169 }
170
171
172 int crypt_set_password(void *ctx, const char *password)
173 {
174         const char *hash;
175
176         if (!password || !strlen(password))
177                 return crypt_set_password_hash(ctx, "");
178
179         hash = crypt_hash_password(password);
180         if (!hash)
181                 return -1;
182
183         return crypt_set_password_hash(ctx, hash);
184 }
185
186 char *crypt_get_hash(void *ctx)
187 {
188         struct spwd *shadow;
189
190         shadow = getspnam("root");
191         if (!shadow) {
192                 pb_log("Could not find root shadow\n");
193                 return false;
194         }
195
196         return talloc_strdup(ctx, shadow->sp_pwdp);
197 }
198
199 bool crypt_check_password(const char *password)
200 {
201         struct spwd *shadow;
202         char *hash;
203
204         shadow = getspnam("root");
205         if (!shadow) {
206                 pb_log("Could not find root shadow\n");
207                 return false;
208         }
209
210         hash = crypt(password ? : "", shadow->sp_pwdp);
211         if (!hash) {
212                 pb_log("Could not create hash, %m\n");
213                 return false;
214         }
215
216         return strncmp(shadow->sp_pwdp, hash, strlen(shadow->sp_pwdp)) == 0;
217 }