s3:modules: Update getdate.y to work with newer bison versions
[samba.git] / source3 / libads / net_ads_setspn.c
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 {
26         size_t i = 0;
27         TALLOC_CTX *frame = NULL;
28         char **spn_array = NULL;
29         size_t num_spns = 0;
30         bool ok = false;
31         ADS_STATUS status;
32
33         frame = talloc_stackframe();
34         status = ads_get_service_principal_names(frame,
35                                                  ads,
36                                                  machine_name,
37                                                  &spn_array,
38                                                  &num_spns);
39         if (!ADS_ERR_OK(status)) {
40                 goto done;
41         }
42
43         d_printf("Registered SPNs for %s\n", machine_name);
44         for (i = 0; i < num_spns; i++) {
45                 d_printf("\t%s\n", spn_array[i]);
46         }
47
48         ok = true;
49 done:
50         TALLOC_FREE(frame);
51         return ok;
52 }
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 {
60         char *lc_spn = NULL;
61         size_t i = 0;
62
63         lc_spn = strlower_talloc(ctx, spn);
64         if (lc_spn == NULL) {
65                 DBG_ERR("Out of memory, lowercasing %s.\n",
66                         spn);
67                 return false;
68         }
69
70         for (i = 0; i < num_spns; i++) {
71                 char *lc_spn_attr = strlower_talloc(ctx, spn_array[i]);
72                 if (lc_spn_attr == NULL) {
73                         DBG_ERR("Out of memory, lowercasing %s.\n",
74                                 spn_array[i]);
75                         return false;
76                 }
77
78                 if (strequal(lc_spn, lc_spn_attr)) {
79                         return true;
80                 }
81         }
82
83         return false;
84 }
85
86 bool ads_setspn_add(ADS_STRUCT *ads, const char *machine_name, const char * spn)
87 {
88         bool ret = false;
89         TALLOC_CTX *frame = NULL;
90         ADS_STATUS status;
91         struct spn_struct *spn_struct = NULL;
92         const char *spns[2] = {NULL, NULL};
93         char **existing_spns = NULL;
94         size_t num_spns = 0;
95         bool found = false;
96
97         frame = talloc_stackframe();
98         spns[0] = spn;
99         spn_struct = parse_spn(frame, spn);
100         if (spn_struct == NULL) {
101                 goto done;
102         }
103
104         status = ads_get_service_principal_names(frame,
105                                                  ads,
106                                                  machine_name,
107                                                  &existing_spns,
108                                                  &num_spns);
109
110         if (!ADS_ERR_OK(status)) {
111                 goto done;
112         }
113
114         found = find_spn_in_spnlist(frame, spn, existing_spns, num_spns);
115         if (found) {
116                 d_printf("Duplicate SPN found, aborting operation.\n");
117                 goto done;
118         }
119
120         d_printf("Registering SPN %s for object %s\n", spn, machine_name);
121         status = ads_add_service_principal_names(ads, machine_name, spns);
122         if (!ADS_ERR_OK(status)) {
123                 goto done;
124         }
125         ret = true;
126         d_printf("Updated object\n");
127 done:
128         TALLOC_FREE(frame);
129         return ret;
130 }
131
132 bool ads_setspn_delete(ADS_STRUCT *ads,
133                        const char *machine_name,
134                        const char * spn)
135 {
136         size_t i = 0, j = 0;
137         TALLOC_CTX *frame = NULL;
138         char **spn_array = NULL;
139         const char **new_spn_array = NULL;
140         char *lc_spn = NULL;
141         size_t num_spns = 0;
142         ADS_STATUS status;
143         ADS_MODLIST mods;
144         bool ok = false;
145         LDAPMessage *res = NULL;
146
147         frame = talloc_stackframe();
148
149         lc_spn = strlower_talloc(frame, spn);
150         if (lc_spn == NULL) {
151                 DBG_ERR("Out of memory, lowercasing %s.\n", spn);
152                 goto done;
153         }
154
155         status = ads_find_machine_acct(ads,
156                                        &res,
157                                        machine_name);
158         if (!ADS_ERR_OK(status)) {
159                 goto done;
160         }
161
162         status = ads_get_service_principal_names(frame,
163                                                  ads,
164                                                  machine_name,
165                                                  &spn_array,
166                                                  &num_spns);
167         if (!ADS_ERR_OK(status)) {
168                 goto done;
169         }
170
171         new_spn_array = talloc_zero_array(frame, const char*, num_spns + 1);
172         if (!new_spn_array) {
173                 DBG_ERR("Out of memory, failed to allocate array.\n");
174                 goto done;
175         }
176
177         /*
178          * create new spn list to write to object (excluding the spn to
179          * be deleted).
180          */
181         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                 char *lc_spn_attr = strlower_talloc(frame, spn_array[i]);
187                 if (lc_spn_attr == NULL) {
188                         DBG_ERR("Out of memory, lowercasing %s.\n",
189                                 spn_array[i]);
190                         goto done;
191                 }
192
193                 if (!strequal(lc_spn, lc_spn_attr)) {
194                         new_spn_array[j++] = spn_array[i];
195                 }
196         }
197
198         /* found and removed spn */
199         if (j < num_spns) {
200                 char *dn = NULL;
201                 mods = ads_init_mods(frame);
202                 if (mods == NULL) {
203                         goto done;
204                 }
205                 d_printf("Unregistering SPN %s for %s\n", spn, machine_name);
206                 status = ads_mod_strlist(frame, &mods, "servicePrincipalName", new_spn_array);
207                 if (!ADS_ERR_OK(status)) {
208                         goto done;
209                 }
210
211                 dn = ads_get_dn(ads, frame, res);
212                 if (dn == NULL ) {
213                         goto done;
214                 }
215
216                 status = ads_gen_mod(ads, dn, mods);
217                 if (!ADS_ERR_OK(status)) {
218                         goto done;
219                 }
220         }
221         d_printf("Updated object\n");
222
223         ok = true;
224 done:
225         TALLOC_FREE(frame);
226         return ok;
227 }
228
229 #endif /* HAVE_ADS */