]> andersk Git - moira.git/blob - incremental/winad/krb5_utils.c
From dtanner: updates to Active Directory incremental update program.
[moira.git] / incremental / winad / krb5_utils.c
1 /*--
2     krb5_utils.c
3
4 Abstract:
5
6     ASN.1 encoder for the
7     Kerberos Change Password Protocol (I-D) variant for Windows 2000
8
9 --*/
10
11 #include <krb5.h>
12 #ifdef _WIN32
13 #include "asn1_make.h"
14 #endif
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18 #define NEED_SOCKETS
19 #ifndef _WIN32
20 #include <netdb.h>
21 #include <sys/socket.h>
22 #endif
23 #include <stdio.h>
24 #include <arpa/nameser.h>
25 #include <resolv.h>
26 #include "kpasswd.h"
27
28 #ifndef KRB5_USE_INET
29 #ifdef HAVE_NETINET_IN_H
30 #define KRB5_USE_INET 1
31 #endif
32 #endif
33
34 #ifndef T_SRV
35 #define T_SRV 33
36 #endif
37
38 #ifndef _WIN32
39 typedef krb5_octet asn1_octet;
40 typedef krb5_error_code asn1_error_code;
41 typedef struct code_buffer_rep {
42   char *base, *bound, *next;
43 } asn1buf;
44 typedef enum { UNIVERSAL = 0x00, APPLICATION = 0x40,
45                  CONTEXT_SPECIFIC = 0x80, PRIVATE = 0xC0 } asn1_class;
46 #endif
47
48 static const char rcsid[] = "$Id$";
49
50 asn1_error_code asn1_encode_realm(asn1buf *buf, const krb5_principal val, 
51                                   int *retlen);
52 asn1_error_code asn1_encode_principal_name(asn1buf *buf, 
53                                            const krb5_principal val, 
54                                            int *retlen);
55 asn1_error_code asn1_encode_octetstring(asn1buf *buf, const int len, 
56                                         const asn1_octet *val, int *retlen);
57
58 /* From src/lib/krb5/asn.1/krb5_encode.c */
59
60 /* setup() -- create and initialize bookkeeping variables
61      retval: stores error codes returned from subroutines
62      buf: the coding buffer
63      length: length of the most-recently produced encoding
64      sum: cumulative length of the entire encoding */
65 #define krb5_setup()\
66   asn1_error_code retval;\
67   asn1buf *buf=NULL;\
68   int length, sum=0;\
69 \
70   if(rep == NULL) return ASN1_MISSING_FIELD;\
71 \
72   retval = asn1buf_create(&buf);\
73   if(retval) return retval
74
75
76 /* krb5_addfield -- add a field, or component, to the encoding */
77 #define krb5_addfield(value,tag,encoder)\
78 { retval = encoder(buf,value,&length);\
79   if(retval){\
80     asn1buf_destroy(&buf);\
81     return retval; }\
82   sum += length;\
83   retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
84   if(retval){\
85     asn1buf_destroy(&buf);\
86     return retval; }\
87   sum += length; }
88
89 /* krb5_addlenfield -- add a field whose length must be separately specified */
90 #define krb5_addlenfield(len,value,tag,encoder)\
91 { retval = encoder(buf,len,value,&length);\
92   if(retval){\
93     asn1buf_destroy(&buf);\
94     return retval; }\
95   sum += length;\
96   retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
97   if(retval){\
98     asn1buf_destroy(&buf);\
99     return retval; }\
100   sum += length; }
101
102 /* form a sequence (by adding a sequence header to the current encoding) */
103 #define krb5_makeseq()\
104   retval = asn1_make_sequence(buf,sum,&length);\
105   if(retval){\
106     asn1buf_destroy(&buf);\
107     return retval; }\
108   sum += length
109
110 /* produce the final output and clean up the workspace */
111 #define krb5_cleanup()\
112   retval = asn12krb5_buf(buf,code);\
113   if(retval){\
114     asn1buf_destroy(&buf);\
115     return retval; }\
116   retval = asn1buf_destroy(&buf);\
117   if(retval){\
118     return retval; }\
119 \
120   return(0)
121
122 krb5_error_code encode_krb5_setpw(const krb5_setpw *rep,
123                                   krb5_data ** code)
124 {
125   krb5_setup();
126
127   if (rep->targprinc != NULL)
128     {  /* target principal name is OPTIONAL */
129       krb5_addfield(rep->targprinc,2,asn1_encode_realm);
130       krb5_addfield(rep->targprinc,1,asn1_encode_principal_name);
131     }
132   krb5_addlenfield(rep->newpasswd.length, rep->newpasswd.data, 
133                    0, asn1_encode_octetstring);
134   krb5_makeseq();
135   krb5_cleanup();
136 }
137
138 krb5_error_code
139 krb5_locate_dns_srv(krb5_context context, const krb5_data *realm,
140                     const char *service, const char *protocol,
141                     struct sockaddr **addr_pp, int *naddrs)
142 {
143   int             len;
144   int             out;
145   int             j;
146   int             count;
147   unsigned char   reply[1024];
148   struct hostent  *hp;
149   unsigned char   *p;
150   char            host[128];
151   int             status;
152   int             priority;
153   int             weight;
154   u_short         port;
155   struct sockaddr *addr_p = NULL;
156   struct sockaddr_in *sin_p;
157     
158   out = 0;
159   addr_p = (struct sockaddr *)malloc (sizeof (struct sockaddr));
160   if (addr_p == NULL)
161           return(ENOMEM);
162   count = 1;
163
164 #ifdef HAVE_SNPRINTF
165   snprintf(host, sizeof(host), "%s.%s.%*s.",
166                  service, protocol, realm->length, realm->data);
167 #else
168   sprintf(host, "%s.%s.%*s.",
169                 service, protocol, realm->length, realm->data);
170 #endif
171   len = res_search(host, C_IN, T_SRV, reply, sizeof(reply));
172   if (len >=0)
173     {
174           p = reply;
175             p += sizeof(HEADER);
176             status = dn_expand(reply, reply + len, p, host, sizeof(host));
177           if (status < 0)
178               goto out;
179             p += status;
180           p += 4;
181           while (p < reply + len)
182         {
183                 int type, class, ttl, size;
184                 status = dn_expand(reply, reply + len, p, host, sizeof(host));
185                 if (status < 0)
186                         goto out;
187               p += status;
188                 type = (p[0] << 8) | p[1];
189                 p += 2;
190                 class = (p[0] << 8) | p[1];
191                 p += 2;
192               ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
193                 p += 4;
194                 size = (p[0] << 8) | p[1];
195                 p += 2;
196                 if (type == T_SRV)
197             {
198                           status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
199                         if (status < 0)
200                           goto out;
201                           priority = (p[0] << 8) | p[1];
202                           weight = (p[2] << 8) | p[3];
203                           port = (p[4] << 8) | p[5];
204                         hp = (struct hostent *)gethostbyname(host);
205                         if (hp != 0)
206                 {
207                               switch (hp->h_addrtype)
208                     {
209 #ifdef KRB5_USE_INET
210                                   case AF_INET:
211                                           for (j=0; hp->h_addr_list[j]; j++)
212                           {
213                                               sin_p = (struct sockaddr_in *) &addr_p[out++];
214                                               memset ((char *)sin_p, 0, sizeof(struct sockaddr));
215                                               sin_p->sin_family = hp->h_addrtype;
216                                               sin_p->sin_port = htons(port);
217                                               memcpy((char *)&sin_p->sin_addr,
218                                                     (char *)hp->h_addr_list[j],
219                                                   sizeof(struct in_addr));
220                                             if (out+1 >= count)
221                               {
222                                                       count += 5;
223                                                         addr_p = (struct sockaddr *)
224                                                         realloc ((char *)addr_p,
225                                                               sizeof(struct sockaddr) * count);
226                                                         if (!addr_p)
227                                                           goto out;
228                                                 }
229                                             }
230                                           break;
231 #endif
232                                 default:
233                                         break;
234                                 }
235                             }
236                           p += size;
237                   }
238               }
239     }
240     
241 out:
242   if (out == 0)
243     {
244      free(addr_p);
245      return(KRB5_REALM_CANT_RESOLVE);
246     }
247
248   *addr_pp = addr_p;
249   *naddrs = out;
250   return(0);
251 }
252
253 krb5_error_code 
254 krb5_locate_kpasswd(krb5_context context, const krb5_data *realm,
255                     struct sockaddr **addr_pp, int *naddrs)
256 {
257   krb5_error_code code;
258         code = krb5_locate_dns_srv(context, realm, "_kpasswd", "_udp",
259                                    addr_pp, naddrs);
260   if (code)
261     code = krb5_locate_dns_srv(context, realm, "_kpasswd", "_tcp",
262                                addr_pp, naddrs);
263
264   return(code);
265 }
This page took 0.084495 seconds and 5 git commands to generate.