/src/samba/source3/libads/net_ads_setspn.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | net ads setspn routines |
4 | | Copyright (C) Noel Power 2018 |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include "includes.h" |
21 | | #include "ads.h" |
22 | | |
23 | | #ifdef HAVE_ADS |
24 | | bool ads_setspn_list(ADS_STRUCT *ads, const char *machine_name) |
25 | 0 | { |
26 | 0 | size_t i = 0; |
27 | 0 | TALLOC_CTX *frame = NULL; |
28 | 0 | char **spn_array = NULL; |
29 | 0 | size_t num_spns = 0; |
30 | 0 | bool ok = false; |
31 | 0 | ADS_STATUS status; |
32 | |
|
33 | 0 | frame = talloc_stackframe(); |
34 | 0 | status = ads_get_service_principal_names(frame, |
35 | 0 | ads, |
36 | 0 | machine_name, |
37 | 0 | &spn_array, |
38 | 0 | &num_spns); |
39 | 0 | if (!ADS_ERR_OK(status)) { |
40 | 0 | goto done; |
41 | 0 | } |
42 | | |
43 | 0 | d_printf("Registered SPNs for %s\n", machine_name); |
44 | 0 | for (i = 0; i < num_spns; i++) { |
45 | 0 | d_printf("\t%s\n", spn_array[i]); |
46 | 0 | } |
47 | |
|
48 | 0 | ok = true; |
49 | 0 | done: |
50 | 0 | TALLOC_FREE(frame); |
51 | 0 | return ok; |
52 | 0 | } |
53 | | |
54 | | /* returns true if spn exists in spn_array (match is NOT case-sensitive) */ |
55 | | static bool find_spn_in_spnlist(TALLOC_CTX *ctx, |
56 | | const char *spn, |
57 | | char **spn_array, |
58 | | size_t num_spns) |
59 | 0 | { |
60 | 0 | char *lc_spn = NULL; |
61 | 0 | size_t i = 0; |
62 | |
|
63 | 0 | lc_spn = strlower_talloc(ctx, spn); |
64 | 0 | if (lc_spn == NULL) { |
65 | 0 | DBG_ERR("Out of memory, lowercasing %s.\n", |
66 | 0 | spn); |
67 | 0 | return false; |
68 | 0 | } |
69 | | |
70 | 0 | for (i = 0; i < num_spns; i++) { |
71 | 0 | char *lc_spn_attr = strlower_talloc(ctx, spn_array[i]); |
72 | 0 | if (lc_spn_attr == NULL) { |
73 | 0 | DBG_ERR("Out of memory, lowercasing %s.\n", |
74 | 0 | spn_array[i]); |
75 | 0 | return false; |
76 | 0 | } |
77 | | |
78 | 0 | if (strequal(lc_spn, lc_spn_attr)) { |
79 | 0 | return true; |
80 | 0 | } |
81 | 0 | } |
82 | | |
83 | 0 | return false; |
84 | 0 | } |
85 | | |
86 | | bool ads_setspn_add(ADS_STRUCT *ads, const char *machine_name, const char * spn) |
87 | 0 | { |
88 | 0 | bool ret = false; |
89 | 0 | TALLOC_CTX *frame = NULL; |
90 | 0 | ADS_STATUS status; |
91 | 0 | struct spn_struct *spn_struct = NULL; |
92 | 0 | const char *spns[2] = {NULL, NULL}; |
93 | 0 | char **existing_spns = NULL; |
94 | 0 | size_t num_spns = 0; |
95 | 0 | bool found = false; |
96 | |
|
97 | 0 | frame = talloc_stackframe(); |
98 | 0 | spns[0] = spn; |
99 | 0 | spn_struct = parse_spn(frame, spn); |
100 | 0 | if (spn_struct == NULL) { |
101 | 0 | goto done; |
102 | 0 | } |
103 | | |
104 | 0 | status = ads_get_service_principal_names(frame, |
105 | 0 | ads, |
106 | 0 | machine_name, |
107 | 0 | &existing_spns, |
108 | 0 | &num_spns); |
109 | |
|
110 | 0 | if (!ADS_ERR_OK(status)) { |
111 | 0 | goto done; |
112 | 0 | } |
113 | | |
114 | 0 | found = find_spn_in_spnlist(frame, spn, existing_spns, num_spns); |
115 | 0 | if (found) { |
116 | 0 | d_printf("Duplicate SPN found, aborting operation.\n"); |
117 | 0 | goto done; |
118 | 0 | } |
119 | | |
120 | 0 | d_printf("Registering SPN %s for object %s\n", spn, machine_name); |
121 | 0 | status = ads_add_service_principal_names(ads, machine_name, spns); |
122 | 0 | if (!ADS_ERR_OK(status)) { |
123 | 0 | goto done; |
124 | 0 | } |
125 | 0 | ret = true; |
126 | 0 | d_printf("Updated object\n"); |
127 | 0 | done: |
128 | 0 | TALLOC_FREE(frame); |
129 | 0 | return ret; |
130 | 0 | } |
131 | | |
132 | | bool ads_setspn_delete(ADS_STRUCT *ads, |
133 | | const char *machine_name, |
134 | | const char * spn) |
135 | 0 | { |
136 | 0 | size_t i = 0, j = 0; |
137 | 0 | TALLOC_CTX *frame = NULL; |
138 | 0 | char **spn_array = NULL; |
139 | 0 | const char **new_spn_array = NULL; |
140 | 0 | char *lc_spn = NULL; |
141 | 0 | size_t num_spns = 0; |
142 | 0 | ADS_STATUS status; |
143 | 0 | ADS_MODLIST mods; |
144 | 0 | bool ok = false; |
145 | 0 | LDAPMessage *res = NULL; |
146 | |
|
147 | 0 | frame = talloc_stackframe(); |
148 | |
|
149 | 0 | lc_spn = strlower_talloc(frame, spn); |
150 | 0 | if (lc_spn == NULL) { |
151 | 0 | DBG_ERR("Out of memory, lowercasing %s.\n", spn); |
152 | 0 | goto done; |
153 | 0 | } |
154 | | |
155 | 0 | status = ads_find_machine_acct(ads, |
156 | 0 | &res, |
157 | 0 | machine_name); |
158 | 0 | if (!ADS_ERR_OK(status)) { |
159 | 0 | goto done; |
160 | 0 | } |
161 | | |
162 | 0 | status = ads_get_service_principal_names(frame, |
163 | 0 | ads, |
164 | 0 | machine_name, |
165 | 0 | &spn_array, |
166 | 0 | &num_spns); |
167 | 0 | if (!ADS_ERR_OK(status)) { |
168 | 0 | goto done; |
169 | 0 | } |
170 | | |
171 | 0 | new_spn_array = talloc_zero_array(frame, const char*, num_spns + 1); |
172 | 0 | if (!new_spn_array) { |
173 | 0 | DBG_ERR("Out of memory, failed to allocate array.\n"); |
174 | 0 | goto done; |
175 | 0 | } |
176 | | |
177 | | /* |
178 | | * create new spn list to write to object (excluding the spn to |
179 | | * be deleted). |
180 | | */ |
181 | 0 | for (i = 0, j = 0; i < num_spns; i++) { |
182 | | /* |
183 | | * windows setspn.exe deletes matching spn in a case |
184 | | * insensitive way. |
185 | | */ |
186 | 0 | char *lc_spn_attr = strlower_talloc(frame, spn_array[i]); |
187 | 0 | if (lc_spn_attr == NULL) { |
188 | 0 | DBG_ERR("Out of memory, lowercasing %s.\n", |
189 | 0 | spn_array[i]); |
190 | 0 | goto done; |
191 | 0 | } |
192 | | |
193 | 0 | if (!strequal(lc_spn, lc_spn_attr)) { |
194 | 0 | new_spn_array[j++] = spn_array[i]; |
195 | 0 | } |
196 | 0 | } |
197 | | |
198 | | /* found and removed spn */ |
199 | 0 | if (j < num_spns) { |
200 | 0 | char *dn = NULL; |
201 | 0 | mods = ads_init_mods(frame); |
202 | 0 | if (mods == NULL) { |
203 | 0 | goto done; |
204 | 0 | } |
205 | 0 | d_printf("Unregistering SPN %s for %s\n", spn, machine_name); |
206 | 0 | status = ads_mod_strlist(frame, &mods, "servicePrincipalName", new_spn_array); |
207 | 0 | if (!ADS_ERR_OK(status)) { |
208 | 0 | goto done; |
209 | 0 | } |
210 | | |
211 | 0 | dn = ads_get_dn(ads, frame, res); |
212 | 0 | if (dn == NULL ) { |
213 | 0 | goto done; |
214 | 0 | } |
215 | | |
216 | 0 | status = ads_gen_mod(ads, dn, mods); |
217 | 0 | if (!ADS_ERR_OK(status)) { |
218 | 0 | goto done; |
219 | 0 | } |
220 | 0 | } |
221 | 0 | d_printf("Updated object\n"); |
222 | |
|
223 | 0 | ok = true; |
224 | 0 | done: |
225 | | TALLOC_FREE(frame); |
226 | 0 | return ok; |
227 | 0 | } |
228 | | |
229 | | #endif /* HAVE_ADS */ |