From: zacheiss Date: Wed, 25 Feb 2009 22:29:50 +0000 (+0000) Subject: New incremental code, existing side by side by winad.incr for now. X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/commitdiff_plain/61a2844b84d8afbb40e87dac6e5d72b45af20b30 New incremental code, existing side by side by winad.incr for now. --- diff --git a/incremental/ldap/Makefile.in b/incremental/ldap/Makefile.in new file mode 100644 index 00000000..b6f64d4c --- /dev/null +++ b/incremental/ldap/Makefile.in @@ -0,0 +1,52 @@ +# $Id$ + +SHELL=/bin/sh +@SET_MAKE@ + +CC=@CC@ +CPPFLAGS=@CPPFLAGS@ +LDAP_CPPFLAGS=@LDAP_CPPFLAGS@ +CFLAGS=@CFLAGS@ +DEFS=@DEFS@ +ALL_CFLAGS=$(LDAP_CPPFLAGS) $(CPPFLAGS) $(CFLAGS) $(DEFS) +LDFLAGS=@LDFLAGS@ +LDAP_LIBS=@LDAP_LIBS@ +LIBS=@LIBS@ +MR_LIBDEP=@MR_LIBDEP@ +INSTALL=@INSTALL@ +INSTALL_PROGRAM=@INSTALL_PROGRAM@ + +srcdir=@srcdir@ +VPATH=@srcdir@ +SRCTOP=@top_srcdir@ +BUILDTOP=../.. +mrbindir=@mrbindir@ + +WINAD_OBJS=winad.o ldap_adgssapi_bind.o krb5_utils.o setpw.o + +TARGET=ldap.incr + +.SUFFIXES: .pc + +.pc.c: + $(PRO_C) $(PRO_C_FLAGS) INAME=$< + +.c.o: + $(CC) -c $(ALL_CFLAGS) $< + +all: $(TARGET) + +clean: + rm -f $(WINAD_OBJS) $(TARGET) + +cleandir distclean: clean + rm -f Makefile + +depend: + +install: + $(INSTALL_PROGRAM) ldap.incr $(mrbindir) + +ldap.incr: $(WINAD_OBJS) $(MR_LIBDEP) + $(CC) -o $@ $(LDAP_LIBS) $(LDFLAGS) $(WINAD_OBJS) -lldap -llber \ + -lgssapi_krb5 $(LIBS) diff --git a/incremental/ldap/auth_con.h b/incremental/ldap/auth_con.h new file mode 100644 index 00000000..9543de35 --- /dev/null +++ b/incremental/ldap/auth_con.h @@ -0,0 +1,36 @@ + +#ifndef KRB5_AUTH_CONTEXT +#define KRB5_AUTH_CONTEXT + +struct _krb5_auth_context { + krb5_magic magic; + krb5_address * remote_addr; + krb5_address * remote_port; + krb5_address * local_addr; + krb5_address * local_port; + krb5_keyblock * keyblock; + krb5_keyblock * send_subkey; + krb5_keyblock * recv_subkey; + + krb5_int32 auth_context_flags; + krb5_ui_4 remote_seq_number; + krb5_ui_4 local_seq_number; + krb5_authenticator *authentp; /* mk_req, rd_req, mk_rep, ...*/ + krb5_cksumtype req_cksumtype; /* mk_safe, ... */ + krb5_cksumtype safe_cksumtype; /* mk_safe, ... */ + krb5_pointer i_vector; /* mk_priv, rd_priv only */ + krb5_rcache rcache; + krb5_enctype * permitted_etypes; /* rd_req */ + krb5_mk_req_checksum_func checksum_func; + void *checksum_func_data; +}; + + +/* Internal auth_context_flags */ +#define KRB5_AUTH_CONN_INITIALIZED 0x00010000 +#define KRB5_AUTH_CONN_USED_W_MK_REQ 0x00020000 +#define KRB5_AUTH_CONN_USED_W_RD_REQ 0x00040000 +#define KRB5_AUTH_CONN_SANE_SEQ 0x00080000 +#define KRB5_AUTH_CONN_HEIMDAL_SEQ 0x00100000 + +#endif diff --git a/incremental/ldap/gssldap-int.h b/incremental/ldap/gssldap-int.h new file mode 100755 index 00000000..c5f24a21 --- /dev/null +++ b/incremental/ldap/gssldap-int.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 1998-2000 Luke Howard. All rights reserved. + * CONFIDENTIAL + * $Id$ + * + * Structures for handling GSS-API binds within LDAP client + * and server libraries. This isn't entirely SASL specific, + * apart from the negotiation state. + */ + +#ifndef _GSSLDAP_INT_H_ +#define _GSSLDAP_INT_H_ + +#define GSSAPI_LDAP_PRINCIPAL_ATTRIBUTE "krbName" +#define GSSAPI_LDAP_SERVICE_NAME "ldap" +#define GSSAPI_LDAP_DN_PREFIX "dn:" +#define GSSAPI_LDAP_DN_PREFIX_LEN (sizeof(GSSAPI_LDAP_DN_PREFIX) - 1) + +#include "gsssasl.h" +#include "gssldap.h" + +/* + * GSS-API SASL negotiation state for the client library + */ +typedef struct gssldap_client_state_desc { + /* LDAP handle */ + LDAP *ld; + + /* dn passed to ldap_gssapi_bind() */ + const char *binddn; + + /* msgid for bind conversation */ + int msgid; + + /* GSS-API context */ + gss_ctx_id_t context; + + /* result code to return from ldap_gssapi_bind() */ + int rc; +} gssldap_client_state_desc, *gssldap_client_state_t; + +/* + * Plugin (server side) state + */ +typedef struct gssldap_server_state_desc { + /* The LDAP connection */ + int conn; + + /* Where in the negotiation we are */ + gsssasl_server_negotiation_desc state; + + /* The GSS-API context */ + gss_ctx_id_t context; + + /* The client name */ + gss_buffer_desc client_name; + + /* SASL authorization identity (with dn: prefix chopped) */ + char *identity; + + /* The next entry in the list */ + struct gssldap_server_state_desc *next; +} gssldap_server_state_desc, *gssldap_server_state_t; + +#endif /* _GSSLDAP_INT_H_ */ diff --git a/incremental/ldap/gssldap.h b/incremental/ldap/gssldap.h new file mode 100755 index 00000000..c41f80ef --- /dev/null +++ b/incremental/ldap/gssldap.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 1998-2000 Luke Howard. All rights reserved. + * CONFIDENTIAL + * $Id$ + * + * Public client API for GSS-API LDAP SASL mechanism. + */ + +#ifndef _GSSLDAP_H_ +#define _GSSLDAP_H_ + +#include +#include + +LDAP_API(int) +LDAP_CALL ldap_adgssapi_bind(LDAP * ld, const char *who, int layer, + char *ldap_domain_name, char *ldap_realm_name, + char *server); +LDAP_API(int) +LDAP_CALL ldap_gssapi_debug(int on); + +#endif /* _GSSLDAP_H_ */ diff --git a/incremental/ldap/gsssasl.h b/incremental/ldap/gsssasl.h new file mode 100755 index 00000000..718d4d5b --- /dev/null +++ b/incremental/ldap/gsssasl.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 1998-2000 Luke Howard. All rights reserved. + * CONFIDENTIAL + * $Id$ + * + * General GSS-API SASL (not LDAP specific) stuff. + */ + +#ifndef _GSSSASL_H_ +#define _GSSSASL_H_ + +#ifdef _WIN32 +#include +#endif + +#ifdef HEIMDAL +#include +#else +#include +#endif +#ifndef _WIN32 +#include +#endif + +#define OM_uint32 ULONG + +#define GSSAPI_SASL_NAME "GSSAPI" + +/* GSS_Accept_Context */ +#define GSSSASL_NEGOTIATE_CONTEXT 0x01 +/* Section 7.2.2 of RFC 2222 */ +#define GSSSASL_SEND_SECURITY_OPTIONS 0x02 +/* Section 7.2.1 of RFC 2222 */ +#define GSSSASL_RECEIVE_SECURITY_OPTIONS 0x03 +#define GSSSASL_COMPLETED 0x04 + +/* Section 7.3 of RFC 2222 */ +#define GSSSASL_NO_SECURITY_LAYER 0x01 +#define GSSSASL_INTEGRITY_PROTECTION 0x02 +#define GSSSASL_PRIVACY_PROTECTION 0x04 + +/* Token for security negotiation (after GSS-API nego) */ +typedef struct gsssasl_security_negotiation_desc { + /* Section 7.2.3 of RFC 2222 */ + int security_layer:8; + /* Section 7.2.[12] of RFC 2222 */ + int token_size:24; + /* Section 7.2.1 of RFC 2222 */ + char identity[1]; +} gsssasl_security_negotiation_desc, *gsssasl_security_negotiation_t; + +typedef int gsssasl_server_negotiation_desc, *gsssasl_server_negotiation_t; + +#endif /* _GSSSASL_H_ */ diff --git a/incremental/ldap/kpasswd.h b/incremental/ldap/kpasswd.h new file mode 100644 index 00000000..300484af --- /dev/null +++ b/incremental/ldap/kpasswd.h @@ -0,0 +1,46 @@ +/*-- +Module Name: + + kpasswd.h + +--*/ + + +typedef struct _krb5_setpw { + krb5_magic magic; + krb5_data newpasswd; + krb5_principal targprinc; +} krb5_setpw; + + +#define MAX_SERVER_NAMES 32 +#ifndef T_SRV +#define T_SRV 33 +#endif +#define LDAP_SERVICE "_ldap" +#define TCP_PROTOCOL "_tcp" + +#define KDC_RECEIVE_TIMEOUT 10 +#define KDC_RECEIVE_ERROR 11 +#define KDC_SEND_ERROR 12 +#define KDC_GETSOCKNAME_ERROR 13 +#define KDC_GETPEERNAME_ERROR 14 + +#ifndef KRB5_KPASSWD_SUCCESS +#define KRB5_KPASSWD_SUCCESS 0 +#define KRB5_KPASSWD_MALFORMED 1 +#define KRB5_KPASSWD_HARDERROR 2 +#define KRB5_KPASSWD_AUTHERROR 3 +#define KRB5_KPASSWD_SOFTERROR 4 +#endif +#define KRB5_KPASSWD_ACCESSDENIED 5 +#define KRB5_KPASSWD_BAD_VERSION 6 +#define KRB5_KPASSWD_INITIAL_FLAG_NEEDED 7 + +#define KRB5_KPASSWD_VERS_CHANGEPW 1 +#define KRB5_KPASSWD_VERS_SETPW 0xff80 + +#ifndef DEFAULT_KPASSWD_PORT +#define DEFAULT_KPASSWD_PORT 464 +#endif + diff --git a/incremental/ldap/krb5_utils.c b/incremental/ldap/krb5_utils.c new file mode 100644 index 00000000..4e8a7aa3 --- /dev/null +++ b/incremental/ldap/krb5_utils.c @@ -0,0 +1,134 @@ +/*-- + krb5_utils.c + +Abstract: + + ASN.1 encoder for the + Kerberos Change Password Protocol (I-D) variant for Windows 2000 + +--*/ + +#include +#include +#ifdef _WIN32 +#include "asn1_make.h" +#endif +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#define NEED_SOCKETS +#ifndef _WIN32 +#include +#include +#endif +#include +#include +#include +#include "kpasswd.h" + +#ifndef KRB5_USE_INET +#ifdef HAVE_NETINET_IN_H +#define KRB5_USE_INET 1 +#endif +#endif + +#ifndef _WIN32 +typedef krb5_octet asn1_octet; +typedef krb5_error_code asn1_error_code; +typedef struct code_buffer_rep { + char *base, *bound, *next; +} asn1buf; +typedef enum { UNIVERSAL = 0x00, APPLICATION = 0x40, + CONTEXT_SPECIFIC = 0x80, PRIVATE = 0xC0 } asn1_class; +#endif + +static const char rcsid[] = "$Id$"; + +asn1_error_code asn1_encode_realm(asn1buf *buf, const krb5_principal val, + int *retlen); +asn1_error_code asn1_encode_principal_name(asn1buf *buf, + const krb5_principal val, + int *retlen); +asn1_error_code asn1_encode_octetstring(asn1buf *buf, const int len, + const asn1_octet *val, int *retlen); + +/* From src/lib/krb5/asn.1/krb5_encode.c */ + +/* setup() -- create and initialize bookkeeping variables + retval: stores error codes returned from subroutines + buf: the coding buffer + length: length of the most-recently produced encoding + sum: cumulative length of the entire encoding */ +#define krb5_setup()\ + asn1_error_code retval;\ + asn1buf *buf=NULL;\ + int length, sum=0;\ +\ + if(rep == NULL) return ASN1_MISSING_FIELD;\ +\ + retval = asn1buf_create(&buf);\ + if(retval) return retval + + +/* krb5_addfield -- add a field, or component, to the encoding */ +#define krb5_addfield(value,tag,encoder)\ +{ retval = encoder(buf,value,&length);\ + if(retval){\ + asn1buf_destroy(&buf);\ + return retval; }\ + sum += length;\ + retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\ + if(retval){\ + asn1buf_destroy(&buf);\ + return retval; }\ + sum += length; } + +/* krb5_addlenfield -- add a field whose length must be separately specified */ +#define krb5_addlenfield(len,value,tag,encoder)\ +{ retval = encoder(buf,len,value,&length);\ + if(retval){\ + asn1buf_destroy(&buf);\ + return retval; }\ + sum += length;\ + retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\ + if(retval){\ + asn1buf_destroy(&buf);\ + return retval; }\ + sum += length; } + +/* form a sequence (by adding a sequence header to the current encoding) */ +#define krb5_makeseq()\ + retval = asn1_make_sequence(buf,sum,&length);\ + if(retval){\ + asn1buf_destroy(&buf);\ + return retval; }\ + sum += length + +/* produce the final output and clean up the workspace */ +#define krb5_cleanup()\ + retval = asn12krb5_buf(buf,code);\ + if(retval){\ + asn1buf_destroy(&buf);\ + return retval; }\ + retval = asn1buf_destroy(&buf);\ + if(retval){\ + return retval; }\ +\ + return(0) + +krb5_error_code encode_krb5_setpw(const krb5_setpw *rep, + krb5_data ** code) +{ + krb5_setup(); + + if (rep->targprinc != NULL) + { /* target principal name is OPTIONAL */ + krb5_addfield(rep->targprinc,2,asn1_encode_realm); + krb5_addfield(rep->targprinc,1,asn1_encode_principal_name); + } + krb5_addlenfield(rep->newpasswd.length, rep->newpasswd.data, + 0, asn1_encode_octetstring); + krb5_makeseq(); + krb5_cleanup(); +} + diff --git a/incremental/ldap/ldap-int.h b/incremental/ldap/ldap-int.h new file mode 100755 index 00000000..f3439282 --- /dev/null +++ b/incremental/ldap/ldap-int.h @@ -0,0 +1,707 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#ifndef _LDAPINT_H +#define _LDAPINT_H + +#include +#include +#include +#include +#ifdef hpux +#include +#include +#endif /* hpux */ + +#ifdef _WINDOWS +#ifndef FD_SETSIZE +# define FD_SETSIZE 256 /* number of connections we support */ +#endif +# define WIN32_LEAN_AND_MEAN +# include +# include +#elif defined(macintosh) +#include "ldap-macos.h" +# include +#elif defined(XP_OS2) +#include +#else /* _WINDOWS */ +# include +# include +# include +# include +# include +#if !defined(hpux) && !defined(SUNOS4) && !defined(LINUX1_2) && !defined(LINUX2_0) +# include +#endif /* !defined(hpux) and others */ +#endif /* _WINDOWS */ + +#if defined(BSDI) || defined(LINUX1_2) || defined(SNI) || defined(IRIX) +#include +#endif /* BSDI */ + +#if defined(IRIX) +#include +#endif /* IRIX */ + +#include "lber-int.h" +#include "ldap.h" +#include "ldaprot.h" +#include "ldaplog.h" +#include "portable.h" + +#ifdef LDAP_ASYNC_IO +#ifdef NEED_FILIO +#include /* to get FIONBIO for ioctl() call */ +#else /* NEED_FILIO */ +#include /* to get FIONBIO for ioctl() call */ +#endif /* NEED_FILIO */ +#endif /* LDAP_ASYNC_IO */ + +#ifdef USE_SYSCONF +# include +#endif /* USE_SYSCONF */ + +#if !defined(_WINDOWS) && !defined(macintosh) && !defined(LINUX2_0) +#define NSLDAPI_HAVE_POLL 1 +#endif + +/* SSL version, or 0 if not built with SSL */ +#if defined(NET_SSL) +# define SSL_VERSION 3 +#else +# define SSL_VERSION 0 +#endif + +#define LDAP_URL_URLCOLON "URL:" +#define LDAP_URL_URLCOLON_LEN 4 + +#define LDAP_LDAP_REF_STR LDAP_URL_PREFIX +#define LDAP_LDAP_REF_STR_LEN LDAP_URL_PREFIX_LEN +#define LDAP_LDAPS_REF_STR LDAPS_URL_PREFIX +#define LDAP_LDAPS_REF_STR_LEN LDAPS_URL_PREFIX_LEN + +/* default limit on nesting of referrals */ +#define LDAP_DEFAULT_REFHOPLIMIT 5 +#ifdef LDAP_DNS +#define LDAP_DX_REF_STR "dx://" +#define LDAP_DX_REF_STR_LEN 5 +#endif /* LDAP_DNS */ + +typedef enum { LDAP_CACHE_LOCK, LDAP_MEMCACHE_LOCK, LDAP_MSGID_LOCK, +LDAP_REQ_LOCK, LDAP_RESP_LOCK, LDAP_ABANDON_LOCK, LDAP_CTRL_LOCK, +LDAP_OPTION_LOCK, LDAP_ERR_LOCK, LDAP_CONN_LOCK, LDAP_SELECT_LOCK, +LDAP_RESULT_LOCK, LDAP_PEND_LOCK, LDAP_MAX_LOCK } LDAPLock; + +/* + * This structure represents both ldap messages and ldap responses. + * These are really the same, except in the case of search responses, + * where a response has multiple messages. + */ + +struct ldapmsg { + int lm_msgid; /* the message id */ + int lm_msgtype; /* the message type */ + BerElement *lm_ber; /* the ber encoded message contents */ + struct ldapmsg *lm_chain; /* for search - next msg in the resp */ + struct ldapmsg *lm_next; /* next response */ + int lm_fromcache; /* memcache: origin of message */ +}; + +/* + * structure for tracking LDAP server host, ports, DNs, etc. + */ +typedef struct ldap_server { + char *lsrv_host; + char *lsrv_dn; /* if NULL, use default */ + int lsrv_port; + unsigned long lsrv_options; /* boolean options */ +#define LDAP_SRV_OPT_SECURE 0x01 + struct ldap_server *lsrv_next; +} LDAPServer; + +/* + * structure for representing an LDAP server connection + */ +typedef struct ldap_conn { + Sockbuf *lconn_sb; + BerElement *lconn_ber; /* non-NULL if in midst of msg. */ + int lconn_version; /* LDAP protocol version */ + int lconn_refcnt; + unsigned long lconn_lastused; /* time */ + int lconn_status; +#define LDAP_CONNST_NEEDSOCKET 1 +#define LDAP_CONNST_CONNECTING 2 +#define LDAP_CONNST_CONNECTED 3 +#define LDAP_CONNST_DEAD 4 + LDAPServer *lconn_server; + char *lconn_binddn; /* DN of last successful bind */ + int lconn_bound; /* has a bind been done? */ + char *lconn_krbinstance; + struct ldap_conn *lconn_next; +} LDAPConn; + + +/* + * structure used to track outstanding requests + */ +typedef struct ldapreq { + int lr_msgid; /* the message id */ + int lr_status; /* status of request */ +#define LDAP_REQST_INPROGRESS 1 +#define LDAP_REQST_CHASINGREFS 2 +#define LDAP_REQST_NOTCONNECTED 3 +#define LDAP_REQST_WRITING 4 +#define LDAP_REQST_CONNDEAD 5 /* associated conn. has failed */ + int lr_outrefcnt; /* count of outstanding referrals */ + int lr_origid; /* original request's message id */ + int lr_parentcnt; /* count of parent requests */ + int lr_res_msgtype; /* result message type */ + int lr_res_errno; /* result LDAP errno */ + char *lr_res_error; /* result error string */ + char *lr_res_matched;/* result matched DN string */ + BerElement *lr_ber; /* ber encoded request contents */ + LDAPConn *lr_conn; /* connection used to send request */ + char *lr_binddn; /* request is a bind for this DN */ + struct ldapreq *lr_parent; /* request that spawned this referral */ + struct ldapreq *lr_refnext; /* next referral spawned */ + struct ldapreq *lr_prev; /* previous request */ + struct ldapreq *lr_next; /* next request */ +} LDAPRequest; + +typedef struct ldappend { + void *lp_sema; /* semaphore to post */ + int lp_msgid; /* message id */ + LDAPMessage *lp_result; /* result storage */ + struct ldappend *lp_prev; /* previous pending */ + struct ldappend *lp_next; /* next pending */ +} LDAPPend; + +/* + * structure representing an ldap connection + */ +struct ldap { + struct sockbuf *ld_sbp; /* pointer to socket desc. & buffer */ + char *ld_host; + int ld_version; /* LDAP protocol version */ + char ld_lberoptions; + int ld_deref; + + int ld_timelimit; + int ld_sizelimit; + + struct ldap_filt_desc *ld_filtd; /* from getfilter for ufn searches */ + char *ld_ufnprefix; /* for incomplete ufn's */ + + int ld_errno; + char *ld_error; + char *ld_matched; + int ld_msgid; + + /* do not mess with these */ + LDAPRequest *ld_requests; /* list of outstanding requests */ + LDAPMessage *ld_responses; /* list of outstanding responses */ + int *ld_abandoned; /* array of abandoned requests */ + char *ld_cldapdn; /* DN used in connectionless search */ + + /* it is OK to change these next four values directly */ + int ld_cldaptries; /* connectionless search retry count */ + int ld_cldaptimeout;/* time between retries */ + int ld_refhoplimit; /* limit on referral nesting */ + unsigned long ld_options; /* boolean options */ +#define LDAP_BITOPT_REFERRALS 0x80000000 +#define LDAP_BITOPT_SSL 0x40000000 +#define LDAP_BITOPT_DNS 0x20000000 +#define LDAP_BITOPT_RESTART 0x10000000 +#define LDAP_BITOPT_RECONNECT 0x08000000 +#define LDAP_BITOPT_ASYNC 0x04000000 + + /* do not mess with the rest though */ + char *ld_defhost; /* full name of default server */ + int ld_defport; /* port of default server */ + BERTranslateProc ld_lber_encode_translate_proc; + BERTranslateProc ld_lber_decode_translate_proc; + LDAPConn *ld_defconn; /* default connection */ + LDAPConn *ld_conns; /* list of all server connections */ + void *ld_selectinfo; /* platform specifics for select */ + int ld_selectreadcnt; /* count of read sockets */ + int ld_selectwritecnt; /* count of write sockets */ + LDAP_REBINDPROC_CALLBACK *ld_rebind_fn; + void *ld_rebind_arg; + + /* function pointers, etc. for io */ + struct ldap_io_fns ld_io; +#define ld_read_fn ld_io.liof_read +#define ld_write_fn ld_io.liof_write +#define ld_select_fn ld_io.liof_select +#define ld_socket_fn ld_io.liof_socket +#define ld_ioctl_fn ld_io.liof_ioctl +#define ld_connect_fn ld_io.liof_connect +#define ld_close_fn ld_io.liof_close +#define ld_ssl_enable_fn ld_io.liof_ssl_enable + + /* function pointers, etc. for DNS */ + struct ldap_dns_fns ld_dnsfn; +#define ld_dns_extradata ld_dnsfn.lddnsfn_extradata +#define ld_dns_bufsize ld_dnsfn.lddnsfn_bufsize +#define ld_dns_gethostbyname_fn ld_dnsfn.lddnsfn_gethostbyname +#define ld_dns_gethostbyaddr_fn ld_dnsfn.lddnsfn_gethostbyaddr + + /* function pointers, etc. for threading */ + struct ldap_thread_fns ld_thread; +#define ld_mutex_alloc_fn ld_thread.ltf_mutex_alloc +#define ld_mutex_free_fn ld_thread.ltf_mutex_free +#define ld_mutex_lock_fn ld_thread.ltf_mutex_lock +#define ld_mutex_unlock_fn ld_thread.ltf_mutex_unlock +#define ld_get_errno_fn ld_thread.ltf_get_errno +#define ld_set_errno_fn ld_thread.ltf_set_errno +#define ld_get_lderrno_fn ld_thread.ltf_get_lderrno +#define ld_set_lderrno_fn ld_thread.ltf_set_lderrno +#define ld_lderrno_arg ld_thread.ltf_lderrno_arg + void **ld_mutex; + + /* function pointers, etc. for caching */ + int ld_cache_on; + int ld_cache_strategy; + struct ldap_cache_fns ld_cache; +#define ld_cache_config ld_cache.lcf_config +#define ld_cache_bind ld_cache.lcf_bind +#define ld_cache_unbind ld_cache.lcf_unbind +#define ld_cache_search ld_cache.lcf_search +#define ld_cache_compare ld_cache.lcf_compare +#define ld_cache_add ld_cache.lcf_add +#define ld_cache_delete ld_cache.lcf_delete +#if 0 +#define ld_cache_rename ld_cache.lcf_rename +#endif +#define ld_cache_modify ld_cache.lcf_modify +#define ld_cache_modrdn ld_cache.lcf_modrdn +#define ld_cache_abandon ld_cache.lcf_abandon +#define ld_cache_result ld_cache.lcf_result +#define ld_cache_flush ld_cache.lcf_flush +#define ld_cache_arg ld_cache.lcf_arg + + /* ldapv3 controls */ + LDAPControl **ld_servercontrols; + LDAPControl **ld_clientcontrols; + + /* Preferred language */ + char *ld_preferred_language; + + /* MemCache */ + LDAPMemCache *ld_memcache; + + /* Pending results */ + LDAPPend *ld_pend; /* list of pending results */ + + /* extra thread function pointers */ + struct ldap_extra_thread_fns ld_thread2; +#define ld_mutex_trylock_fn ld_thread2.ltf_mutex_trylock +#define ld_sema_alloc_fn ld_thread2.ltf_sema_alloc +#define ld_sema_free_fn ld_thread2.ltf_sema_free +#define ld_sema_wait_fn ld_thread2.ltf_sema_wait +#define ld_sema_post_fn ld_thread2.ltf_sema_post +}; + +/* allocate/free mutex */ +#define LDAP_MUTEX_ALLOC( ld ) \ + (((ld)->ld_mutex_alloc_fn != NULL) ? (ld)->ld_mutex_alloc_fn() : NULL) + +/* allocate/free mutex */ +#define LDAP_MUTEX_FREE( ld, m ) \ + if ( (ld)->ld_mutex_free_fn != NULL && m != NULL ) { \ + (ld)->ld_mutex_free_fn( m ); \ + } + +/* enter/exit critical sections */ +#define LDAP_MUTEX_TRYLOCK( ld, i ) \ + ( (ld)->ld_mutex_trylock_fn == NULL ) ? 0 : \ + (ld)->ld_mutex_trylock_fn( (ld)->ld_mutex[i] ) +#define LDAP_MUTEX_LOCK( ld, i ) \ + if ( (ld)->ld_mutex_lock_fn != NULL ) { \ + (ld)->ld_mutex_lock_fn( (ld)->ld_mutex[i] ); \ + } +#define LDAP_MUTEX_UNLOCK( ld, i ) \ + if ( (ld)->ld_mutex_unlock_fn != NULL ) { \ + (ld)->ld_mutex_unlock_fn( (ld)->ld_mutex[i] ); \ + } + +/* Backword compatibility locks */ +#define LDAP_MUTEX_BC_LOCK( ld, i ) \ + if( (ld)->ld_mutex_trylock_fn == NULL ) { \ + if ( (ld)->ld_mutex_lock_fn != NULL ) { \ + (ld)->ld_mutex_lock_fn( (ld)->ld_mutex[i] ); \ + } \ + } +#define LDAP_MUTEX_BC_UNLOCK( ld, i ) \ + if( (ld)->ld_mutex_trylock_fn == NULL ) { \ + if ( (ld)->ld_mutex_unlock_fn != NULL ) { \ + (ld)->ld_mutex_unlock_fn( (ld)->ld_mutex[i] ); \ + } \ + } + +/* allocate/free semaphore */ +#define LDAP_SEMA_ALLOC( ld ) \ + (((ld)->ld_sema_alloc_fn != NULL) ? (ld)->ld_sema_alloc_fn() : NULL) +#define LDAP_SEMA_FREE( ld, m ) \ + if ( (ld)->ld_sema_free_fn != NULL && m != NULL ) { \ + (ld)->ld_sema_free_fn( m ); \ + } + +/* wait/post binary semaphore */ +#define LDAP_SEMA_WAIT( ld, lp ) \ + if ( (ld)->ld_sema_wait_fn != NULL ) { \ + (ld)->ld_sema_wait_fn( lp->lp_sema ); \ + } +#define LDAP_SEMA_POST( ld, lp ) \ + if ( (ld)->ld_sema_post_fn != NULL ) { \ + (ld)->ld_sema_post_fn( lp->lp_sema ); \ + } +#define POST( ld, y, z ) \ + if( (ld)->ld_mutex_trylock_fn != NULL ) { \ + nsldapi_post_result( ld, y, z ); \ + } + +/* get/set errno */ +#ifndef macintosh +#define LDAP_SET_ERRNO( ld, e ) \ + if ( (ld)->ld_set_errno_fn != NULL ) { \ + (ld)->ld_set_errno_fn( e ); \ + } else { \ + errno = e; \ + } +#define LDAP_GET_ERRNO( ld ) \ + (((ld)->ld_get_errno_fn != NULL) ? \ + (ld)->ld_get_errno_fn() : errno) +#else /* macintosh */ +#define LDAP_SET_ERRNO( ld, e ) \ + if ( (ld)->ld_set_errno_fn != NULL ) { \ + (ld)->ld_set_errno_fn( e ); \ + } +#define LDAP_GET_ERRNO( ld ) \ + (((ld)->ld_get_errno_fn != NULL) ? \ + (ld)->ld_get_errno_fn() : 0) +#endif + + +/* get/set ldap-specific errno */ +#define LDAP_SET_LDERRNO( ld, e, m, s ) ldap_set_lderrno( ld, e, m, s ) +#define LDAP_GET_LDERRNO( ld, m, s ) ldap_get_lderrno( ld, m, s ) + +/* + * your standard "mimimum of two values" macro + */ +#define NSLDAPI_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/* + * handy macro to check whether LDAP struct is set up for CLDAP or not + */ +#define LDAP_IS_CLDAP( ld ) ( ld->ld_sbp->sb_naddr > 0 ) + +/* + * handy macro to check errno "e" for an "in progress" sort of error + */ +#if defined(macintosh) || defined(_WINDOWS) +#define NSLDAPI_ERRNO_IO_INPROGRESS( e ) ((e) == EWOULDBLOCK || (e) == EAGAIN) +#else +#ifdef EAGAIN +#define NSLDAPI_ERRNO_IO_INPROGRESS( e ) ((e) == EWOULDBLOCK || (e) == EINPROGRESS || (e) == EAGAIN) +#else /* EAGAIN */ +#define NSLDAPI_ERRNO_IO_INPROGRESS( e ) ((e) == EWOULDBLOCK || (e) == EINPROGRESS) +#endif /* EAGAIN */ +#endif /* macintosh || _WINDOWS*/ + +/* + * macro to return the LDAP protocol version we are using + */ +#define NSLDAPI_LDAP_VERSION( ld ) ( (ld)->ld_defconn == NULL ? \ + (ld)->ld_version : \ + (ld)->ld_defconn->lconn_version ) + +/* + * Structures used for handling client filter lists. + */ +#define LDAP_FILT_MAXSIZ 1024 + +struct ldap_filt_list { + char *lfl_tag; + char *lfl_pattern; + char *lfl_delims; + struct ldap_filt_info *lfl_ilist; + struct ldap_filt_list *lfl_next; +}; + +struct ldap_filt_desc { + LDAPFiltList *lfd_filtlist; + LDAPFiltInfo *lfd_curfip; + LDAPFiltInfo lfd_retfi; + char lfd_filter[ LDAP_FILT_MAXSIZ ]; + char *lfd_curval; + char *lfd_curvalcopy; + char **lfd_curvalwords; + char *lfd_filtprefix; + char *lfd_filtsuffix; +}; + +/* + * "internal" globals used to track defaults and memory allocation callbacks: + * (the actual definitions are in open.c) + */ +extern struct ldap nsldapi_ld_defaults; +extern struct ldap_memalloc_fns nsldapi_memalloc_fns; +extern int nsldapi_initialized; + + +/* + * Memory allocation done in liblber should all go through one of the + * following macros. This is so we can plug-in alternative memory + * allocators, etc. as the need arises. + */ +#define NSLDAPI_MALLOC( size ) ldap_x_malloc( size ) +#define NSLDAPI_CALLOC( nelem, elsize ) nsldapi_calloc( nelem, elsize ) +#define NSLDAPI_REALLOC( ptr, size ) nsldapi_realloc( ptr, size ) +#define NSLDAPI_FREE( ptr ) ldap_x_free( ptr ) + + +/* + * macros used to check validity of data structures and parameters + */ +#define NSLDAPI_VALID_LDAP_POINTER( ld ) \ + ( (ld) != NULL ) + +#define NSLDAPI_VALID_LDAPMESSAGE_POINTER( lm ) \ + ( (lm) != NULL ) + +#define NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( lm ) \ + ( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) + +#define NSLDAPI_VALID_LDAPMESSAGE_REFERENCE_POINTER( lm ) \ + ( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) + +#define NSLDAPI_VALID_LDAPMESSAGE_BINDRESULT_POINTER( lm ) \ + ( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_BIND ) + +#define NSLDAPI_VALID_LDAPMESSAGE_EXRESULT_POINTER( lm ) \ + ( (lm) != NULL && (lm)->lm_msgtype == LDAP_RES_EXTENDED ) + +#define NSLDAPI_VALID_LDAPMOD_ARRAY( mods ) \ + ( (mods) != NULL ) + +#define NSLDAPI_VALID_NONEMPTY_LDAPMOD_ARRAY( mods ) \ + ( (mods) != NULL && (mods)[0] != NULL ) + +#define NSLDAPI_IS_SEARCH_ENTRY( code ) \ + ((code) == LDAP_RES_SEARCH_ENTRY) + +#define NSLDAPI_IS_SEARCH_RESULT( code ) \ + ((code) == LDAP_RES_SEARCH_RESULT) + +#define NSLDAPI_SEARCH_RELATED_RESULT( code ) \ + (NSLDAPI_IS_SEARCH_RESULT( code ) || NSLDAPI_IS_SEARCH_ENTRY( code )) + +/* + * in bind.c + */ +char *nsldapi_get_binddn( LDAP *ld ); + +/* + * in cache.c + */ +void nsldapi_add_result_to_cache( LDAP *ld, LDAPMessage *result ); + +/* + * in dsparse.c + */ +int nsldapi_next_line_tokens( char **bufp, long *blenp, char ***toksp ); +void nsldapi_free_strarray( char **sap ); + +/* + * in error.c + */ +int nsldapi_parse_result( LDAP *ld, int msgtype, BerElement *rber, + int *errcodep, char **matchednp, char **errmsgp, char ***referralsp, + LDAPControl ***serverctrlsp ); + +/* + * in open.c + */ +void nsldapi_initialize_defaults( void ); +int nsldapi_open_ldap_connection( LDAP *ld, Sockbuf *sb, char *host, + int defport, char **krbinstancep, int async, int secure ); +int nsldapi_open_ldap_defconn( LDAP *ld ); +void *nsldapi_malloc( size_t size ); +void *nsldapi_calloc( size_t nelem, size_t elsize ); +void *nsldapi_realloc( void *ptr, size_t size ); +void nsldapi_free( void *ptr ); +char *nsldapi_strdup( const char *s ); + +/* + * in os-ip.c + */ +int nsldapi_connect_to_host( LDAP *ld, Sockbuf *sb, char *host, + unsigned long address, int port, int async, int secure ); +void nsldapi_close_connection( LDAP *ld, Sockbuf *sb ); + +int nsldapi_do_ldap_select( LDAP *ld, struct timeval *timeout ); +void *nsldapi_new_select_info( void ); +void nsldapi_free_select_info( void *vsip ); +void nsldapi_mark_select_write( LDAP *ld, Sockbuf *sb ); +void nsldapi_mark_select_read( LDAP *ld, Sockbuf *sb ); +void nsldapi_mark_select_clear( LDAP *ld, Sockbuf *sb ); +int nsldapi_is_read_ready( LDAP *ld, Sockbuf *sb ); +int nsldapi_is_write_ready( LDAP *ld, Sockbuf *sb ); + +/* + * if referral.c + */ +int nsldapi_parse_reference( LDAP *ld, BerElement *rber, char ***referralsp, + LDAPControl ***serverctrlsp ); + + +/* + * in result.c + */ +int ldap_msgdelete( LDAP *ld, int msgid ); +int nsldapi_result_nolock( LDAP *ld, int msgid, int all, int unlock_permitted, + struct timeval *timeout, LDAPMessage **result ); +int nsldapi_wait_result( LDAP *ld, int msgid, int all, struct timeval *timeout, + LDAPMessage **result ); +int nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result ); + +/* + * in request.c + */ +int nsldapi_send_initial_request( LDAP *ld, int msgid, unsigned long msgtype, + char *dn, BerElement *ber ); +int nsldapi_alloc_ber_with_options( LDAP *ld, BerElement **berp ); +void nsldapi_set_ber_options( LDAP *ld, BerElement *ber ); +int nsldapi_ber_flush( LDAP *ld, Sockbuf *sb, BerElement *ber, int freeit, + int async ); +int nsldapi_send_server_request( LDAP *ld, BerElement *ber, int msgid, + LDAPRequest *parentreq, LDAPServer *srvlist, LDAPConn *lc, + char *bindreqdn, int bind ); +LDAPConn *nsldapi_new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb, + int connect, int bind ); +LDAPRequest *nsldapi_find_request_by_msgid( LDAP *ld, int msgid ); +void nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn ); +void nsldapi_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ); +void nsldapi_dump_connection( LDAP *ld, LDAPConn *lconns, int all ); +void nsldapi_dump_requests_and_responses( LDAP *ld ); +int nsldapi_chase_v2_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, + int *totalcountp, int *chasingcountp ); +int nsldapi_chase_v3_refs( LDAP *ld, LDAPRequest *lr, char **refs, + int is_reference, int *totalcountp, int *chasingcountp ); +int nsldapi_append_referral( LDAP *ld, char **referralsp, char *s ); +void nsldapi_connection_lost_nolock( LDAP *ld, Sockbuf *sb ); + +/* + * in search.c + */ +int ldap_build_search_req( LDAP *ld, char *base, int scope, + char *filter, char **attrs, int attrsonly, LDAPControl **serverctrls, + LDAPControl **clientctrls, struct timeval *timeoutp, int sizelimit, + int msgid, BerElement **berp ); + +/* + * in unbind.c + */ +int ldap_ld_free( LDAP *ld, int close ); +int nsldapi_send_unbind( LDAP *ld, Sockbuf *sb ); + +#ifdef LDAP_DNS +/* + * in getdxbyname.c + */ +char **nsldapi_getdxbyname( char *domain ); + +#endif /* LDAP_DNS */ + +/* + * in unescape.c + */ +void nsldapi_hex_unescape( char *s ); + +/* + * in reslist.c + */ +LDAPMessage *ldap_delete_result_entry( LDAPMessage **list, LDAPMessage *e ); +void ldap_add_result_entry( LDAPMessage **list, LDAPMessage *e ); + +/* + * in compat.c + */ +#ifdef hpux +char *nsldapi_compat_ctime_r( const time_t *clock, char *buf, int buflen ); +struct hostent *nsldapi_compat_gethostbyname_r( const char *name, + struct hostent *result, char *buffer, int buflen, int *h_errnop ); +#endif /* hpux */ + +/* + * in control.c + */ +int nsldapi_put_controls( LDAP *ld, LDAPControl **ctrls, int closeseq, + BerElement *ber ); +int nsldapi_get_controls( BerElement *ber, LDAPControl ***controlsp ); +int nsldapi_dup_controls( LDAP *ld, LDAPControl ***ldctrls, + LDAPControl **newctrls ); +int nsldapi_build_control( char *oid, BerElement *ber, int freeber, + char iscritical, LDAPControl **ctrlp ); + + +/* + * in url.c + */ +int nsldapi_url_parse( char *url, LDAPURLDesc **ludpp, int dn_required ); + + +/* + * in charset.c + * + * If we ever want to expose character set translation functionality to + * users of libldap, all of these prototypes will need to be moved to ldap.h + */ +#ifdef STR_TRANSLATION +void ldap_set_string_translators( LDAP *ld, + BERTranslateProc encode_proc, BERTranslateProc decode_proc ); +int ldap_translate_from_t61( LDAP *ld, char **bufp, + unsigned long *lenp, int free_input ); +int ldap_translate_to_t61( LDAP *ld, char **bufp, + unsigned long *lenp, int free_input ); +void ldap_enable_translation( LDAP *ld, LDAPMessage *entry, + int enable ); +#ifdef LDAP_CHARSET_8859 +int ldap_t61_to_8859( char **bufp, unsigned long *buflenp, + int free_input ); +int ldap_8859_to_t61( char **bufp, unsigned long *buflenp, + int free_input ); +#endif /* LDAP_CHARSET_8859 */ +#endif /* STR_TRANSLATION */ + +/* + * in memcache.h + */ +int ldap_memcache_createkey( LDAP *ld, const char *base, int scope, + const char *filter, char **attrs, int attrsonly, + LDAPControl **serverctrls, LDAPControl **clientctrls, + unsigned long *keyp ); +int ldap_memcache_result( LDAP *ld, int msgid, unsigned long key ); +int ldap_memcache_new( LDAP *ld, int msgid, unsigned long key, + const char *basedn ); +int ldap_memcache_append( LDAP *ld, int msgid, int bLast, LDAPMessage *result ); +int ldap_memcache_abandon( LDAP *ld, int msgid ); + +#endif /* _LDAPINT_H */ diff --git a/incremental/ldap/ldap_adgssapi_bind.c b/incremental/ldap/ldap_adgssapi_bind.c new file mode 100755 index 00000000..3fe31c8a --- /dev/null +++ b/incremental/ldap/ldap_adgssapi_bind.c @@ -0,0 +1,1001 @@ +/* + * Copyright (C) 1998-2000 Luke Howard. All rights reserved. + * CONFIDENTIAL + * $Id$ + * + * Implementation of GSS-API client side binding for SASL + */ + +#ifdef _WIN32 +#include +#endif +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#endif + +#include +#include +#include +#include +#include "ldap-int.h" +#include "gssldap-int.h" + +#ifndef _WIN32 +typedef gss_uint32 OM_uint32; +#endif + +#ifndef T_SRV +#define T_SRV 33 +#endif +#define LDAP_SERVICE "_ldap" +#define TCP_PROTOCOL "_tcp" + +int locate_ldap_server(char *domain, char **server_name); +int ldap_delete_tickets(LDAP *ld, char *service_name); +static int negotiate_security_options(gssldap_client_state_t state, + int layer); +int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name, + char *ldap_realm_name); +unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context, + gsssasl_security_negotiation_t inmask, + size_t masklength, gss_buffer_t wrapped_tok); + +int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context, + gss_buffer_t wrapped_tok, + gsssasl_security_negotiation_t *outmask, + size_t *masklength); + +#ifdef GSSSASL_DEBUG +static int debug_ = 1; +#define TRACE(x) do { if (debug_) fprintf(stderr, "%s\n", x); fflush(stderr); } while (0); +#define LDAP_PERROR(ld, x) do { if (debug_) ldap_perror(ld, x); } while (0); +#define LOG_STATUS(msg, min, maj) log_status(msg, min, maj) +#else +#define TRACE(x) +#define LDAP_PERROR(ld, x) +#define LOG_STATUS(msg, min, maj) +#endif /* GSSSASL_DEBUG */ + +#ifdef HACK_SERVICE_NAME +char *__service = NULL; +#endif + +/* + * The read and write fns need to access the context in here and + * there doesn't appear to be a way to pass this info to them. + */ +static gss_ctx_id_t security_context; +static int security_layer = 0; +static unsigned long security_token_size = 0; + +LDAP_CALLBACK int LDAP_C ldap_gssapi_read(LBER_SOCKET sock, void *data, + int len) +{ + OM_uint32 maj_stat; + OM_uint32 min_stat; + OM_uint32 rc; + OM_uint32 pdulen; + gss_buffer_desc recv_tok; + gss_buffer_desc wrapped_tok; + int count; + + if (security_layer & + (GSSSASL_INTEGRITY_PROTECTION | GSSSASL_PRIVACY_PROTECTION)) + { + if (recv(sock, (char *)&pdulen, sizeof(pdulen), 0) != sizeof(pdulen)) + return (0); + wrapped_tok.length = ntohl(pdulen); +#ifdef GSSSASL_DEBUG + if (debug_) + { + fprintf(stderr, "Reading data of %d octets\n", + wrapped_tok.length); + } +#endif /* GSSSASL_DEBUG */ + if ((int)wrapped_tok.length > security_token_size) + return (0); + wrapped_tok.value = malloc(wrapped_tok.length); + if (wrapped_tok.value == NULL) + return (0); + count = recv(sock, wrapped_tok.value, wrapped_tok.length, 0); + if (count != (int)wrapped_tok.length) + { + gss_release_buffer(&rc, &wrapped_tok); + return (0); + } + maj_stat = gss_unwrap(&min_stat, + security_context, + &wrapped_tok, + &recv_tok, + &rc, + (gss_qop_t *) NULL); + if (maj_stat != GSS_S_COMPLETE) + { + gss_release_buffer(&rc, &wrapped_tok); + return maj_stat; + } +#ifdef GSSSASL_DEBUG + if (debug_) + { + fprintf(stderr, "Got %d bytes of %s data\n", + recv_tok.length, rc ? "private" : "signed"); + } +#endif /* GSSSASL_DEBUG */ + if ((int)recv_tok.length > len) + { + gss_release_buffer(&rc, &recv_tok); + gss_release_buffer(&rc, &wrapped_tok); + return GSS_S_FAILURE; + } + memcpy(data, recv_tok.value, recv_tok.length); + pdulen = recv_tok.length; + gss_release_buffer(&rc, &recv_tok); + gss_release_buffer(&rc, &wrapped_tok); + + return pdulen; + } + else + return read(sock, data, len); +} + +LDAP_CALLBACK int LDAP_C ldap_gssapi_write(LBER_SOCKET sock, const void *data, + int len) +{ + OM_uint32 maj_stat; + OM_uint32 min_stat; + OM_uint32 pdulen; + OM_uint32 rc; + gss_buffer_desc send_tok; + gss_buffer_desc wrapped_tok; + unsigned char *ptr; + + if (security_layer & + (GSSSASL_INTEGRITY_PROTECTION | GSSSASL_PRIVACY_PROTECTION)) + { + send_tok.length = len; + send_tok.value = (void *) data; +#ifdef GSSSASL_DEBUG + if (debug_) + { + fprintf(stderr, "Sending %d bytes of data\n", + len); + } +#endif /* GSSSASL_DEBUG */ + maj_stat = gss_wrap(&min_stat, + security_context, + (security_layer & GSSSASL_PRIVACY_PROTECTION) ? 1 : 0, + GSS_C_QOP_DEFAULT, + &send_tok, + &rc, + &wrapped_tok); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; +#ifdef GSSSASL_DEBUG + if (debug_) + { + fprintf(stderr, "Sent %d bytes of %s data\n", + wrapped_tok.length, rc ? "private" : "signed"); + } +#endif /* GSSSASL_DEBUG */ + pdulen = htonl(wrapped_tok.length); + ptr = calloc(1, sizeof(pdulen) + wrapped_tok.length); + memcpy(ptr, &pdulen, sizeof(pdulen)); + memcpy(&ptr[sizeof(pdulen)], wrapped_tok.value, wrapped_tok.length); + rc = send(sock, ptr, sizeof(pdulen) + wrapped_tok.length, 0); + free(ptr); + if (rc == (wrapped_tok.length + sizeof(pdulen))) + rc = len; + gss_release_buffer(&maj_stat, &wrapped_tok); + return rc; + } + else + return send(sock, data, len, 0); +} + +#ifdef GSSSASL_DEBUG +/* + * Dump the token to stderr + */ +static void print_token(gss_buffer_t tok) +{ + int i; + unsigned char *p = tok->value; + + for (i = 0; i < (int)tok->length; i++, p++) + { + fprintf(stderr, "%02x ", *p); + if ((i % 16) == 15) + { + fprintf(stderr, "\n"); + } + } + fprintf(stderr, "\n"); + fflush(stderr); + return; +} + +/* + * Handle a GSS-API error + */ +static void log_status_impl(const char *reason, OM_uint32 res, int type) +{ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc msg; + OM_uint32 msg_ctx; + + msg_ctx = 0; + while (1) + { + maj_stat = gss_display_status(&min_stat, + res, + type, + GSS_C_NULL_OID, + &msg_ctx, + &msg); + + if (debug_) + { + fprintf(stderr, "ldap_adgssapi_bind: %s: %s\n", + (char *) msg.value, + reason); + } + (void) gss_release_buffer(&min_stat, &msg); + if (!msg_ctx) + break; + } + return; +} + +/* + * Cover function to handle a GSS-API error + */ +static void log_status(const char *reason, OM_uint32 maj_stat, + OM_uint32 min_stat) +{ + log_status_impl(reason, maj_stat, GSS_C_GSS_CODE); + log_status_impl(reason, min_stat, GSS_C_MECH_CODE); + return; +} +#endif /* GSSSASL_DEBUG */ + +/* + * Send a GSS-API token as part of a SASL BindRequest + */ +static int send_token(gssldap_client_state_t state, gss_buffer_t send_tok) +{ + struct berval cred; + + TRACE("==> send_token"); + + cred.bv_val = send_tok->value; + cred.bv_len = send_tok->length; + + if (ldap_sasl_bind(state->ld, + state->binddn, + GSSAPI_SASL_NAME, + &cred, + NULL, + NULL, + &state->msgid) != LDAP_SUCCESS) + { + LDAP_PERROR(state->ld, "send_token"); + TRACE("<== send_token"); + return -1; + } + TRACE("<== send_token"); + return 0; +} + +/* + * Parse the final result sent back from the server. + */ +static int parse_bind_result(gssldap_client_state_t state) +{ + LDAPMessage *res = NULL, *msg = NULL; + int rc; + + TRACE("==> parse_bind_result"); + + if (ldap_result(state->ld, + state->msgid, + LDAP_MSG_ALL, + NULL, + &res) <= 0) + { + LDAP_PERROR(state->ld, "ldap_result"); + TRACE("<== parse_bind_result"); + return -1; + } + for (msg = ldap_first_message(state->ld, res); + msg != NULL; + msg = ldap_next_message(state->ld, msg)) + { + if (ldap_msgtype(msg) == LDAP_RES_BIND) + { + ldap_parse_result(state->ld, msg, &rc, NULL, NULL, NULL, NULL, 0); + break; + } + } + + ldap_msgfree(res); + state->msgid = -1; + + TRACE("<== parse_bind_result"); + + if (rc == LDAP_SUCCESS) + { + return 0; + } + state->rc = rc; + return -1; +} + +/* + * Receive a GSS-API token from a SASL BindResponse + * The contents of recv_tok must be freed by the + * caller. + */ +static int recv_token(gssldap_client_state_t state, gss_buffer_t recv_tok) +{ + struct berval *servercred = NULL; + LDAPMessage *res = NULL, *msg = NULL; + int rc; + + TRACE("==> recv_token"); + + if (ldap_result(state->ld, state->msgid, LDAP_MSG_ALL, NULL, &res) <= 0) + { + LDAP_PERROR(state->ld, "ldap_result"); + TRACE("<== recv_token"); + return -1; + } + recv_tok->value = NULL; + recv_tok->length = 0; + + for (msg = ldap_first_message(state->ld, res); + msg != NULL; + msg = ldap_next_message(state->ld, msg)) + { + if (ldap_msgtype(msg) == LDAP_RES_BIND && servercred == NULL) + { + rc = ldap_parse_sasl_bind_result(state->ld, + msg, + &servercred, + 0); + if (rc == LDAP_SUCCESS && servercred != NULL) + { + recv_tok->value = malloc(servercred->bv_len); + if (recv_tok->value != NULL) + { + memcpy(recv_tok->value, servercred->bv_val, servercred->bv_len); + recv_tok->length = servercred->bv_len; + } + break; + } + else + { + state->rc = rc; + } + } + } + + ldap_msgfree(res); + state->msgid = -1; + TRACE("<== recv_token"); + if (servercred != NULL) + { + nslberi_free(servercred); + TRACE("<== recv_token"); + return 0; + } + if (state->rc == LDAP_SUCCESS) + { + state->rc = LDAP_OPERATIONS_ERROR; + } + else + { + LDAP_PERROR(state->ld, "recv_token"); + } + + TRACE("<== recv_token"); + return -1; +} + +/* + * The client calls GSS_Init_sec_context, passing in 0 for + * input_context_handle (initially) and a targ_name equal to output_name + * from GSS_Import_Name called with input_name_type of + * GSS_C_NT_HOSTBASED_SERVICE and input_name_string of + * "service@hostname" where "service" is the service name specified in + * the protocol's profile, and "hostname" is the fully qualified host + * name of the server. The client then responds with the resulting + * output_token. If GSS_Init_sec_context returns GSS_S_CONTINUE_NEEDED, + * then the client should expect the server to issue a token in a + * subsequent challenge. The client must pass the token to another call + * to GSS_Init_sec_context, repeating the actions in this paragraph. + */ +static int client_establish_context(LDAP *ld, gssldap_client_state_t state, + char *service_name, char *ldap_realm_name) +{ + gss_buffer_desc send_tok; + gss_buffer_desc recv_tok; + gss_buffer_desc *token_ptr; + gss_name_t target_name; + OM_uint32 maj_stat; + OM_uint32 min_stat; + gss_OID oid = GSS_C_NULL_OID; + OM_uint32 ret_flags; + + TRACE("==> client_establish_context"); + + memset(&recv_tok, '\0', sizeof(recv_tok)); + send_tok.value = service_name; + send_tok.length = strlen(send_tok.value) + 1; + + maj_stat = gss_import_name(&min_stat, + &send_tok, + (gss_OID) gss_nt_service_name, + &target_name); + if (maj_stat) + return -1; + if (ldap_reset_principal(ld, service_name, target_name, ldap_realm_name)) + { + TRACE("<== client_establish_context"); + return -1; + } + + token_ptr = GSS_C_NO_BUFFER; + state->context = GSS_C_NO_CONTEXT; + + do + { + maj_stat = gss_init_sec_context(&min_stat, + GSS_C_NO_CREDENTIAL, + &state->context, + target_name, + oid, + GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, + 0, + NULL, + token_ptr, + NULL, + &send_tok, + &ret_flags, + NULL); + + if (token_ptr != GSS_C_NO_BUFFER) + (void) gss_release_buffer(&min_stat, &recv_tok); + + if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) + { + LOG_STATUS("initializing context", maj_stat, min_stat); + (void) gss_release_name(&min_stat, &target_name); + TRACE("<== client_establish_context"); + return -1; + } +#ifdef GSSSASL_DEBUG + if (debug_) + { + fprintf(stderr, "Sending init_sec_context token (size=%d)...\n", + send_tok.length); + fflush(stderr); + print_token(&send_tok); + } +#endif + if (send_token(state, &send_tok) < 0) + { + TRACE("Send_token failed"); + (void) gss_release_buffer(&min_stat, &send_tok); + (void) gss_release_name(&min_stat, &target_name); + TRACE("<== client_establish_context"); + return -1; + } + (void) gss_release_buffer(&min_stat, &send_tok); + if (maj_stat == GSS_S_CONTINUE_NEEDED) + { + TRACE("continue needed..."); + if (recv_token(state, &recv_tok) < 0) + { + TRACE("recv_token failed"); + (void) gss_release_name(&min_stat, &target_name); + TRACE("<== client_establish_context"); + return -1; + } +#ifdef GSSSASL_DEBUG + if (debug_) + { + fprintf(stderr, "Received token (size=%d)...\n", + recv_tok.length); + fflush(stderr); + print_token(&recv_tok); + } +#endif + token_ptr = &recv_tok; + } + } while (maj_stat == GSS_S_CONTINUE_NEEDED); + + (void) gss_release_name(&min_stat, &target_name); + + TRACE("<== client_establish_context"); + return 0; +} + +/* + * When GSS_Init_sec_context returns GSS_S_COMPLETE, the client takes + * the following actions: If the last call to GSS_Init_sec_context + * returned an output_token, then the client responds with the + * output_token, otherwise the client responds with no data. The client + * should then expect the server to issue a token in a subsequent + * challenge. The client passes this token to GSS_Unwrap and interprets + * the first octet of resulting cleartext as a bit-mask specifying the + * security layers supported by the server and the second through fourth + * octets as the maximum size output_message to send to the server. The + * client then constructs data, with the first octet containing the + * bit-mask specifying the selected security layer, the second through + * fourth octets containing in network byte order the maximum size + * output_message the client is able to receive, and the remaining + * octets containing the authorization identity. The client passes the + * data to GSS_Wrap with conf_flag set to FALSE, and responds with the + * generated output_message. The client can then consider the server + * authenticated. + */ +static int negotiate_security_options(gssldap_client_state_t state, + int layer) +{ + OM_uint32 maj_stat; + OM_uint32 min_stat; + gss_buffer_desc recv_tok; + gss_buffer_desc send_tok; + OM_uint32 rc; + OM_uint32 ret; + size_t mask_length; + gsssasl_security_negotiation_t send_mask; + gsssasl_security_negotiation_t recv_mask; + + TRACE("==> negotiate_security_options"); + + memset(&send_tok, '\0', sizeof(send_tok)); + memset(&recv_tok, '\0', sizeof(recv_tok)); + if ((rc = recv_token(state, &recv_tok)) < 0) + { + TRACE("<== negotiate_security_options (recv_token failed)"); + return rc; + } +#ifdef GSSSASL_DEBUG + if (debug_) + { + fprintf(stderr, "Received token (size=%d)...\n", + recv_tok.length); + fflush(stderr); + print_token(&recv_tok); + } +#endif /* GSSSASL_DEBUG */ + + maj_stat = gsssasl_unpack_security_token(&min_stat, + state->context, + &recv_tok, + &recv_mask, + &mask_length); + + if (maj_stat != GSS_S_COMPLETE) + { + LOG_STATUS("unpacking security negotiation token", + maj_stat, + min_stat); + TRACE("<== negotiate_security_options (unpack failed)"); + return -1; + } +#ifdef GSSSASL_DEBUG + if (debug_) + { + fprintf(stderr, "Received security token level %d size %d\n", + recv_mask->security_layer, + recv_mask->token_size); + } +#endif + if ((~recv_mask->security_layer) & layer) + { + free(recv_mask); + TRACE("<== negotiate_security_options (unsupported security layer)"); + return -1; + } + mask_length = sizeof(recv_mask); + send_mask = NSLDAPI_MALLOC(mask_length); + if (send_mask == NULL) + { + free(recv_mask); + TRACE("<== negotiate_security_options (malloc failed)"); + return -1; + } + memset(send_mask, '\0', mask_length); + send_mask->security_layer = layer; + send_mask->token_size = recv_mask->token_size; + memcpy(send_mask->identity, "", strlen("")); + free(recv_mask); + +#ifdef GSSSASL_DEBUG + if (debug_) + { + fprintf(stderr, "Sending security token level %d size %d\n", + send_mask->security_layer, + send_mask->token_size); + } +#endif + maj_stat = gsssasl_pack_security_token(&min_stat, + state->context, + send_mask, + mask_length, + &send_tok); + if (maj_stat != GSS_S_COMPLETE) + { + LOG_STATUS("packing security negotiation token", maj_stat, min_stat); + NSLDAPI_FREE(send_mask); + TRACE("<== negotiate_security_options (pack failed)"); + return -1; + } + if ((rc = send_token(state, &send_tok)) < 0) + { + NSLDAPI_FREE(send_mask); + TRACE("<== negotiate_security_options (send_token failed)"); + return rc; + } + rc = parse_bind_result(state); + + ret = rc; + if (rc == 0) + { + security_context = state->context; + security_layer = layer; + security_token_size = ntohl(send_mask->token_size); +#ifdef _WIN32 + security_token_size >>= 8; +#endif + } + + NSLDAPI_FREE(send_mask); + if (send_tok.value != NULL) + gss_release_buffer(&rc, &send_tok); + if (recv_tok.value != NULL) + gss_release_buffer(&rc, &recv_tok); + TRACE("<== negotiate_security_options"); + return ret; +} + +#ifdef GSSSASL_DEBUG +/* + * Temporary function to enable debugging + */ +LDAP_API(int) +LDAP_CALL ldap_gssapi_debug(int on) +{ + int old = debug_; + debug_ = on; + return old; +} +#endif /* GSSSASL_DEBUG */ + +/* + * Public function for doing a GSS-API SASL bind + */ +LDAP_API(int) + LDAP_CALL ldap_adgssapi_bind(LDAP *ld, const char *who, int layer, + char *ldap_domain_name, + char *ldap_realm_name, char *server) +{ + gssldap_client_state_desc state; + char *service_name; + OM_uint32 min_stat; + int rc; + int i; + struct ldap_io_fns iofns; + char *realm; + + if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL) + { + return -1; + } + + for (i = 0; i < (int)strlen(ld->ld_defhost); i++) + ld->ld_defhost[i] = toupper(ld->ld_defhost[i]); + + service_name = + NSLDAPI_MALLOC(sizeof(GSSAPI_LDAP_SERVICE_NAME "@") + + strlen(server)); + if (service_name == NULL) + { + return -1; + } + strcpy(service_name, GSSAPI_LDAP_SERVICE_NAME "@"); + strcat(service_name, lowercase(server)); + free(realm); + +#ifdef GSSSASL_DEBUG + if (debug_) + { + fprintf(stderr, "LDAP service name: %s\n", service_name); + fflush(stderr); + } +#endif + + state.msgid = -1; + state.ld = ld; + state.binddn = who; + state.context = GSS_C_NO_CONTEXT; + state.rc = LDAP_OPERATIONS_ERROR; + + rc = client_establish_context(ld, &state, service_name, ldap_realm_name); + if (rc == 0) + { + rc = negotiate_security_options(&state, layer); + } + if (rc == 0) + { +#ifdef GSSSASL_DEBUG + gss_buffer_desc tname; + gss_buffer_desc sname; + gss_name_t targ_name; + gss_name_t src_name; + OM_uint32 context_flags; + OM_uint32 lifetime; + OM_uint32 maj_stat; + int is_open; + int is_local; + gss_OID mechanism; + gss_OID name_type; + + maj_stat = gss_inquire_context(&min_stat, + state.context, + &src_name, + &targ_name, + &lifetime, + &mechanism, + &context_flags, + &is_local, + &is_open); + if (maj_stat != GSS_S_COMPLETE) + { + LOG_STATUS("inquiring context", maj_stat, min_stat); + return LDAP_OPERATIONS_ERROR; + } + maj_stat = gss_display_name(&min_stat, + src_name, + &sname, + &name_type); + if (maj_stat != GSS_S_COMPLETE) + { + LOG_STATUS("displaying source name", maj_stat, min_stat); + return LDAP_OPERATIONS_ERROR; + } + maj_stat = gss_display_name(&min_stat, + targ_name, + &tname, + (gss_OID *) NULL); + if (maj_stat != GSS_S_COMPLETE) + { + LOG_STATUS("displaying target name", maj_stat, min_stat); + return LDAP_OPERATIONS_ERROR; + } + if (debug_) + { + fprintf(stderr, + "\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n", + (int) sname.length, (char *) sname.value, + (int) tname.length, (char *) tname.value, lifetime, + context_flags, + (is_local) ? "locally initiated" : "remotely initiated", + (is_open) ? "open" : "closed"); + fflush(stderr); + } + (void) gss_release_name(&min_stat, &src_name); + (void) gss_release_name(&min_stat, &targ_name); + (void) gss_release_buffer(&min_stat, &sname); + (void) gss_release_buffer(&min_stat, &tname); +#endif + state.rc = LDAP_SUCCESS; + } + + if (state.rc == LDAP_SUCCESS) + { + if (layer == GSSSASL_PRIVACY_PROTECTION) + { + memset(&iofns, 0, sizeof(iofns)); + iofns.liof_read = ldap_gssapi_read; + iofns.liof_write = ldap_gssapi_write; + state.rc = ldap_set_option(ld, LDAP_OPT_IO_FN_PTRS, &iofns); + } + } + + NSLDAPI_FREE(service_name); + LDAP_SET_LDERRNO(ld, state.rc, NULL, NULL); + + return state.rc; +} + +/* Wrap and encode a security negotiation token */ +unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat, + gss_ctx_id_t context, + gsssasl_security_negotiation_t inmask, + size_t masklength, gss_buffer_t wrapped_tok) +{ + OM_uint32 maj_stat; + OM_uint32 rc; + gss_buffer_desc send_tok; + + wrapped_tok->length = 0; + wrapped_tok->value = NULL; + +/* + if (masklength < sizeof(gsssasl_security_negotiation_desc)) + return GSS_S_FAILURE; +*/ + + inmask->token_size = inmask->token_size; + + send_tok.length = masklength; + send_tok.value = inmask; + + maj_stat = gss_wrap(min_stat, + context, + 0, + GSS_C_QOP_DEFAULT, + &send_tok, + (int *)&rc, + wrapped_tok); + +/* inmask->token_size = ntohl(inmask->token_size);*/ + + return maj_stat; +} + +/* Unwrap and decode a security negotiation token. */ +int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context, + gss_buffer_t wrapped_tok, + gsssasl_security_negotiation_t *outmask, + size_t *masklength) +{ + OM_uint32 maj_stat; + OM_uint32 rc; + gss_buffer_desc recv_tok; + + *masklength = 0; + *outmask = NULL; + memset(&recv_tok, '\0', sizeof(recv_tok)); + + maj_stat = gss_unwrap(min_stat, + context, + wrapped_tok, + &recv_tok, + (int *)&rc, + (gss_qop_t *) NULL); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + +/* +#ifdef _WIN32 + if (recv_tok.length < sizeof(gsssasl_security_negotiation_desc)) + { + gss_release_buffer(&rc, &recv_tok); + return GSS_S_FAILURE; + } +#endif +*/ + + /* + * we're lazy and don't copy the token. This could cause + * problems if libgssapi uses a different malloc! + */ + *masklength = recv_tok.length; + *outmask = (gsssasl_security_negotiation_t) recv_tok.value; + if (*outmask == NULL) + { + gss_release_buffer(&rc, &recv_tok); + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} + +int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name, + char *ldap_realm_name) +{ + krb5_context context = NULL; + krb5_principal princ; + krb5_principal princ1; + krb5_principal temp_princ; + char *realm; + char *server_name = NULL; + int i; + + princ = (krb5_principal)(target_name); + + if (krb5_init_context(&context)) + return(-1); + + realm = strdup(ldap_realm_name); + for (i = 0; i < (int)strlen(realm); i++) + realm[i] = toupper(realm[i]); + server_name = strdup(ld->ld_defhost); + for (i = 0; i < (int)strlen(server_name); i++) + server_name[i] = tolower(server_name[i]); + + temp_princ = malloc(sizeof(*princ)); + memcpy(temp_princ, princ, sizeof(*princ)); + + krb5_build_principal(context, &princ1, strlen(realm), realm, "ldap", + server_name, NULL); + + memcpy(princ, princ1, sizeof(*princ1)); + free(princ1); + krb5_free_principal(context, temp_princ); + + if (realm != NULL) + free(realm); + if (server_name != NULL) + free(server_name); + if (context != NULL) + krb5_free_context(context); + return(0); +} + +int ldap_delete_tickets(LDAP *ld, char *service_name) +{ + int i; + int rc; + krb5_context context = NULL; + krb5_ccache v5Cache = NULL; + krb5_creds creds; + krb5_cc_cursor v5Cursor; + krb5_error_code code; + char *sServerName; + + if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL) + { + return -1; + } + + for (i = 0; i < (int)strlen(ld->ld_defhost); i++) + ld->ld_defhost[i] = toupper(ld->ld_defhost[i]); + + rc = -1; + + if (krb5_init_context(&context)) + return(rc); + + if (krb5_cc_default(context, &v5Cache)) + goto cleanup; + if (krb5_cc_start_seq_get(context, v5Cache, &v5Cursor)) + goto cleanup; + + memset(&creds, '\0', sizeof(creds)); + + while (!(code = krb5_cc_next_cred(context, v5Cache, &v5Cursor, &creds))) + { + if (krb5_unparse_name(context, creds.server, &sServerName)) + { + krb5_free_cred_contents(context, &creds); + continue; + } + if (!memcmp(sServerName, service_name, strlen(service_name))) + { + krb5_cc_remove_cred(context, v5Cache, 0, &creds); + } + continue; + } + + if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND)) + { + krb5_cc_end_seq_get(context, v5Cache, &v5Cursor); + } + rc = 0; + +cleanup: + if ((v5Cache != NULL) && (context != NULL)) + krb5_cc_close(context, v5Cache); + if (context != NULL) + krb5_free_context(context); + return(rc); +} diff --git a/incremental/ldap/setpw.c b/incremental/ldap/setpw.c new file mode 100644 index 00000000..b3e4e73d --- /dev/null +++ b/incremental/ldap/setpw.c @@ -0,0 +1,897 @@ +#define LDAP_AUTH_OTHERKIND 0x86L +#define LDAP_AUTH_NEGOTIATE (LDAP_AUTH_OTHERKIND | 0x0400) +/*-- + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +Copyright (C) 1999 Microsoft Corporation. All rights reserved. + +Module Name: + + setpw.c + +Abstract: + + Set a user's password using the + Kerberos Change Password Protocol (I-D) variant for Windows 2000 + +--*/ +/* + * lib/krb5/os/changepw.c + * + * Copyright 1990 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + + +#define NEED_SOCKETS +#ifndef _WIN32 +#include "port-sockets.h" +#endif +#include +#include +#include +#ifdef _WIN32 +#include +#include "krb5_err.h" +#else +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include "kpasswd.h" +#include "gsssasl.h" +#include "gssldap.h" + +#define PW_LENGTH 25 +#define KDC_PORT 464 +#define ULONG unsigned long + +#ifndef krb5_is_krb_error +#define krb5_is_krb_error(dat)\ + ((dat) && (dat)->length && ((dat)->data[0] == 0x7e ||\ + (dat)->data[0] == 0x5e)) +#endif + +#ifdef _WIN32 +extern krb5_error_code decode_krb5_error + (const krb5_data *output, krb5_error **rep); +#define sleep(Seconds) Sleep(Seconds * 1000) +#define gethostbyname(Server) rgethostbyname(Server) +#endif + +/* Win32 defines. */ +#if defined(_WIN32) && !defined(__CYGWIN32__) +#ifndef ECONNABORTED +#define ECONNABORTED WSAECONNABORTED +#endif +#ifndef ECONNREFUSED +#define ECONNREFUSED WSAECONNREFUSED +#endif +#ifndef EHOSTUNREACH +#define EHOSTUNREACH WSAEHOSTUNREACH +#endif +#endif /* _WIN32 && !__CYGWIN32__ */ + +static const char rcsid[] = "$Id$"; + +static int frequency[26][26] = +{ {4, 20, 28, 52, 2, 11, 28, 4, 32, 4, 6, 62, 23, 167, 2, 14, 0, 83, 76, +127, 7, 25, 8, 1, 9, 1}, /* aa - az */ + {13, 0, 0, 0, 55, 0, 0, 0, 8, 2, 0, 22, 0, 0, 11, 0, 0, 15, 4, 2, 13, 0, +0, 0, 15, 0}, /* ba - bz */ + {32, 0, 7, 1, 69, 0, 0, 33, 17, 0, 10, 9, 1, 0, 50, 3, 0, 10, 0, 28, 11, +0, 0, 0, 3, 0}, /* ca - cz */ + {40, 16, 9, 5, 65, 18, 3, 9, 56, 0, 1, 4, 15, 6, 16, 4, 0, 21, 18, 53, +19, 5, 15, 0, 3, 0}, /* da - dz */ + {84, 20, 55, 125, 51, 40, 19, 16, 50, 1, 4, 55, 54, 146, 35, 37, 6, 191, +149, 65, 9, 26, 21, 12, 5, 0}, /* ea - ez */ + {19, 3, 5, 1, 19, 21, 1, 3, 30, 2, 0, 11, 1, 0, 51, 0, 0, 26, 8, 47, 6, +3, 3, 0, 2, 0}, /* fa - fz */ + {20, 4, 3, 2, 35, 1, 3, 15, 18, 0, 0, 5, 1, 4, 21, 1, 1, 20, 9, 21, 9, +0, 5, 0, 1, 0}, /* ga - gz */ + {101, 1, 3, 0, 270, 5, 1, 6, 57, 0, 0, 0, 3, 2, 44, 1, 0, 3, 10, 18, 6, +0, 5, 0, 3, 0}, /* ha - hz */ + {40, 7, 51, 23, 25, 9, 11, 3, 0, 0, 2, 38, 25, 202, 56, 12, 1, 46, 79, +117, 1, 22, 0, 4, 0, 3}, /* ia - iz */ + {3, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, +0, 0}, /* ja - jz */ + {1, 0, 0, 0, 11, 0, 0, 0, 13, 0, 0, 0, 0, 2, 0, 0, 0, 0, 6, 2, 1, 0, 2, +0, 1, 0}, /* ka - kz */ + {44, 2, 5, 12, 62, 7, 5, 2, 42, 1, 1, 53, 2, 2, 25, 1, 1, 2, 16, 23, 9, +0, 1, 0, 33, 0}, /* la - lz */ + {52, 14, 1, 0, 64, 0, 0, 3, 37, 0, 0, 0, 7, 1, 17, 18, 1, 2, 12, 3, 8, +0, 1, 0, 2, 0}, /* ma - mz */ + {42, 10, 47, 122, 63, 19, 106, 12, 30, 1, 6, 6, 9, 7, 54, 7, 1, 7, 44, +124, 6, 1, 15, 0, 12, 0}, /* na - nz */ + {7, 12, 14, 17, 5, 95, 3, 5, 14, 0, 0, 19, 41, 134, 13, 23, 0, 91, 23, +42, 55, 16, 28, 0, 4, 1}, /* oa - oz */ + {19, 1, 0, 0, 37, 0, 0, 4, 8, 0, 0, 15, 1, 0, 27, 9, 0, 33, 14, 7, 6, 0, +0, 0, 0, 0}, /* pa - pz */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, +0, 0, 0}, /* qa - qz */ + {83, 8, 16, 23, 169, 4, 8, 8, 77, 1, 10, 5, 26, 16, 60, 4, 0, 24, 37, +55, 6, 11, 4, 0, 28, 0}, /* ra - rz */ + {65, 9, 17, 9, 73, 13, 1, 47, 75, 3, 0, 7, 11, 12, 56, 17, 6, 9, 48, +116, 35, 1, 28, 0, 4, 0}, /* sa - sz */ + {57, 22, 3, 1, 76, 5, 2, 330, 126, 1, 0, 14, 10, 6, 79, 7, 0, 49, 50, +56, 21, 2, 27, 0, 24, 0}, /* ta - tz */ + {11, 5, 9, 6, 9, 1, 6, 0, 9, 0, 1, 19, 5, 31, 1, 15, 0, 47, 39, 31, 0, +3, 0, 0, 0, 0}, /* ua - uz */ + {7, 0, 0, 0, 72, 0, 0, 0, 28, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, +0, 3, 0}, /* va - vz */ + {36, 1, 1, 0, 38, 0, 0, 33, 36, 0, 0, 4, 1, 8, 15, 0, 0, 0, 4, 2, 0, 0, +1, 0, 0, 0}, /* wa - wz */ + {1, 0, 2, 0, 0, 1, 0, 0, 3, 0, 0, 0, 0, 0, 1, 5, 0, 0, 0, 3, 0, 0, 1, 0, +0, 0}, /* xa - xz */ + {14, 5, 4, 2, 7, 12, 12, 6, 10, 0, 0, 3, 7, 5, 17, 3, 0, 4, 16, 30, 0, +0, 5, 0, 0, 0}, /* ya - yz */ + {1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0}}; /* za - zz */ + +/* + * This MUST be equal to the sum of the equivalent rows above. + */ + +static int row_sums[26] = +{796,160,284,401,1276,262,199,539,777, + 16,39,351,243,751,662,181,17,683, + 662,968,248,115,180,17,162,5}; + +/* + * Frequencies of starting characters + */ + +static int start_freq [26] = +{1299,425,725,271,375,470,93,223,1009, + 24,20,355,379,319,823,618,21,317, + 962,1991,271,104,516,6,16,14}; + +/* + * This MUST be equal to the sum of all elements in the above array. + */ + +struct sockaddr_in kdc_server; +SOCKET kdc_socket; +krb5_context context; +krb5_ccache ccache; +krb5_auth_context auth_context = NULL; +krb5_data ap_req; +krb5_creds *credsp = NULL; +krb5_creds creds; +char connected_server[128]; + +static int total_sum = 11646; + +int get_krb5_error(krb5_error_code rc, char *in, char *out); +int ad_connect(LDAP **ldap_handle, char *ldap_domain, char *dn_path, + char *Win2kPassword, char *Win2kUser, char *default_server, + int connect_to_kdc, char **ServerList, char *ldap_realm, + char *ldap_port); +int ad_kdc_connect(char *connectedServer); +int ad_server_connect(char *connectedServer, char *domain); +void ad_kdc_disconnect(); +int compare_elements(const void *arg1, const void *arg2); +int convert_domain_to_dn(char *domain, char *dnp); +int set_password(char *user, char *password, char *domain); + +int locate_ldap_server(char *domain, char **server_name); + +long myrandom(); +void generate_password(char *password); + +#ifdef WIN32 +krb5_error_code encode_krb5_setpw + PROTOTYPE((const krb5_setpw *rep, krb5_data ** code)); +#endif + +krb5_error_code make_setpw_req(krb5_context context, krb5_auth_context auth_context, + krb5_data *ap_req, krb5_principal targprinc, + char *passwd, krb5_data *packet) +{ + krb5_error_code ret; + krb5_setpw setpw; + krb5_data cipherpw; + krb5_data *encoded_setpw; + krb5_replay_data replay; + char *ptr; + register int count = 2; + + memset(&setpw, 0, sizeof(krb5_setpw)); + if (ret = krb5_auth_con_setflags(context, auth_context, + KRB5_AUTH_CONTEXT_DO_SEQUENCE)) + return(ret); + setpw.targprinc = targprinc; + setpw.newpasswd.length = strlen(passwd); + setpw.newpasswd.data = passwd; + if ((ret = encode_krb5_setpw(&setpw, &encoded_setpw))) + return( ret ); + if (ret = krb5_mk_priv(context, auth_context, + encoded_setpw, &cipherpw, &replay)) + return(ret); + packet->length = 6 + ap_req->length + cipherpw.length; + packet->data = (char *) malloc(packet->length); + ptr = packet->data; + /* Length */ + *ptr++ = (packet->length>>8) & 0xff; + *ptr++ = packet->length & 0xff; + /* version */ + *ptr++ = (char)0xff; + *ptr++ = (char)0x80; + /* ap_req length, big-endian */ + *ptr++ = (ap_req->length>>8) & 0xff; + *ptr++ = ap_req->length & 0xff; + /* ap-req data */ + memcpy(ptr, ap_req->data, ap_req->length); + ptr += ap_req->length; + /* krb-priv of password */ + memcpy(ptr, cipherpw.data, cipherpw.length); + free(cipherpw.data); +/* krb5_free_data_contents(context, &cipherpw);*/ + krb5_free_data(context, encoded_setpw); + return(0); +} + +krb5_error_code get_setpw_rep(krb5_context context, krb5_auth_context auth_context, + krb5_data *packet, int *result_code, + krb5_data *result_data) +{ + char *ptr; + int plen; + int vno; + krb5_data ap_rep; + krb5_error_code ret; + krb5_data cipherresult; + krb5_data clearresult; + krb5_error *krberror; + krb5_replay_data replay; + krb5_ap_rep_enc_part *ap_rep_enc; + + if (packet->length < 4) + return(KRB5KRB_AP_ERR_MODIFIED); + ptr = packet->data; + if (krb5_is_krb_error(packet)) + { + ret = decode_krb5_error(packet, &krberror); + if (ret) + return(ret); + ret = krberror->error; + krb5_free_error(context, krberror); + return(ret); + } + /* verify length */ + plen = (*ptr++ & 0xff); + plen = (plen<<8) | (*ptr++ & 0xff); + if (plen != (int)packet->length) + return(KRB5KRB_AP_ERR_MODIFIED); + vno = (*ptr++ & 0xff); + vno = (vno<<8) | (*ptr++ & 0xff); + if (vno != KRB5_KPASSWD_VERS_SETPW && vno != KRB5_KPASSWD_VERS_CHANGEPW) + return(KRB5KDC_ERR_BAD_PVNO); + /* read, check ap-rep length */ + ap_rep.length = (*ptr++ & 0xff); + ap_rep.length = (ap_rep.length<<8) | (*ptr++ & 0xff); + if (ptr + ap_rep.length >= packet->data + packet->length) + return(KRB5KRB_AP_ERR_MODIFIED); + if (ap_rep.length) + { + /* verify ap_rep */ + ap_rep.data = ptr; + ptr += ap_rep.length; + if (ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc)) + return(ret); + krb5_free_ap_rep_enc_part(context, ap_rep_enc); + /* extract and decrypt the result */ + cipherresult.data = ptr; + cipherresult.length = (packet->data + packet->length) - ptr; + /* XXX there's no api to do this right. The problem is that + if there's a remote subkey, it will be used. This is + not what the spec requires */ + ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult, + &replay); + if (ret) + return(ret); + } + else + { + cipherresult.data = ptr; + cipherresult.length = (packet->data + packet->length) - ptr; + + if (ret = krb5_rd_error(context, &cipherresult, &krberror)) + return(ret); + + clearresult = krberror->e_data; + } + if (clearresult.length < 2) + { + ret = KRB5KRB_AP_ERR_MODIFIED; + goto cleanup; + } + ptr = clearresult.data; + *result_code = (*ptr++ & 0xff); + *result_code = (*result_code<<8) | (*ptr++ & 0xff); + if ((*result_code < KRB5_KPASSWD_SUCCESS) || + (*result_code > KRB5_KPASSWD_ACCESSDENIED)) + { + ret = KRB5KRB_AP_ERR_MODIFIED; + goto cleanup; + } + /* all success replies should be authenticated/encrypted */ + if ((ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS)) + { + ret = KRB5KRB_AP_ERR_MODIFIED; + goto cleanup; + } + result_data->length = (clearresult.data + clearresult.length) - ptr; + if (result_data->length) + { + result_data->data = (char *) malloc(result_data->length); + memcpy(result_data->data, ptr, result_data->length); + } + else + result_data->data = NULL; + ret = 0; +cleanup: + if (ap_rep.length) + free(clearresult.data); + else + krb5_free_error(context, krberror); + return(ret); +} + +krb5_error_code kdc_set_password(krb5_context context, krb5_ccache ccache, + char *newpw, char *user, char *domain, + int *result_code) +{ + krb5_data chpw_snd; + krb5_data chpw_rcv; + krb5_data result_string; + krb5_address local_kaddr; + krb5_address remote_kaddr; + char userrealm[256]; + char temp[256]; + krb5_error_code code; + struct sockaddr local_addr; + struct sockaddr remote_addr; + int i; + int addrlen; + int cc; + int local_result_code; + int nfds; + krb5_principal targprinc; + struct timeval TimeVal; + fd_set readfds; + + memset(&local_addr, 0, sizeof(local_addr)); + memset(&local_kaddr, 0, sizeof(local_kaddr)); + memset(&result_string, 0, sizeof(result_string)); + memset(&remote_kaddr, 0, sizeof(remote_kaddr)); + memset(&chpw_snd, 0, sizeof(krb5_data)); + memset(&chpw_rcv, 0, sizeof(krb5_data)); + memset(userrealm, '\0', sizeof(userrealm)); + targprinc = NULL; + + chpw_rcv.length = 1500; + chpw_rcv.data = (char *) calloc(1, chpw_rcv.length); + + for (i = 0; i < (int)strlen(domain); i++) + userrealm[i] = toupper(domain[i]); + + sprintf(temp, "%s@%s", user, userrealm); + krb5_parse_name(context, temp, &targprinc); + + if (credsp == NULL) + { + memset(&creds, 0, sizeof(creds)); + memset(&ap_req, 0, sizeof(krb5_data)); + sprintf(temp, "%s@%s", "kadmin/changepw", userrealm); + if (code = krb5_parse_name(context, temp, &creds.server)) + goto cleanup; + if (code = krb5_cc_get_principal(context, ccache, &creds.client)) + goto cleanup; + if (code = krb5_get_credentials(context, 0, ccache, &creds, &credsp)) + goto cleanup; + if (code = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY, + NULL, credsp, &ap_req)) + goto cleanup; + } + + addrlen = sizeof(local_addr); + if (getsockname(kdc_socket, &local_addr, &addrlen) < 0) + { + code = KDC_GETSOCKNAME_ERROR; + goto cleanup; + } + if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) + { + local_kaddr.addrtype = ADDRTYPE_INET; + local_kaddr.length = + sizeof(((struct sockaddr_in *) &local_addr)->sin_addr); + local_kaddr.contents = + (char *) &(((struct sockaddr_in *) &local_addr)->sin_addr); + } + else + { + krb5_address **addrs; + krb5_os_localaddr(context, &addrs); + local_kaddr.magic = addrs[0]->magic; + local_kaddr.addrtype = addrs[0]->addrtype; + local_kaddr.length = addrs[0]->length; + local_kaddr.contents = calloc(1, addrs[0]->length); + memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length); + krb5_free_addresses(context, addrs); + } + + addrlen = sizeof(remote_addr); + if (getpeername(kdc_socket, &remote_addr, &addrlen) < 0) + { + code = KDC_GETPEERNAME_ERROR; + goto cleanup; + } + remote_kaddr.addrtype = ADDRTYPE_INET; + remote_kaddr.length = sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr); + remote_kaddr.contents = (char *) &(((struct sockaddr_in *) &remote_addr)->sin_addr); + + if (code = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL)) + goto cleanup; + if (code = make_setpw_req(context, auth_context, &ap_req, + targprinc, newpw, &chpw_snd)) + goto cleanup; + + for (i = 0; i < 3; i++) + { + if ((cc = sendto(kdc_socket, chpw_snd.data, chpw_snd.length, 0, + NULL, + 0)) != (int)chpw_snd.length) + { + code = KDC_SEND_ERROR; + sleep(1); + continue; + } + + TimeVal.tv_sec = 3; + TimeVal.tv_usec = 0; + FD_ZERO(&readfds); + FD_SET(kdc_socket, &readfds); + nfds = kdc_socket + 1; + code = select(nfds, &readfds, NULL, NULL, &TimeVal); + if ((code == 0) || (code == SOCKET_ERROR)) + { + code = KDC_RECEIVE_TIMEOUT; + sleep(1); + continue; + } + + if ((cc = recvfrom(kdc_socket, chpw_rcv.data, chpw_rcv.length, 0, + NULL, NULL)) < 0) + { + code = KDC_RECEIVE_TIMEOUT; + sleep(1); + continue; + } + chpw_rcv.length = cc; + if (code = krb5_auth_con_setaddrs(context, auth_context, NULL, &remote_kaddr)) + { + sleep(1); + continue; + } + local_result_code = 0; + code = get_setpw_rep(context, auth_context, &chpw_rcv, + &local_result_code, &result_string); + + if (local_result_code) + { + if (local_result_code == KRB5_KPASSWD_SOFTERROR) + local_result_code = KRB5_KPASSWD_SUCCESS; + *result_code = local_result_code; + } + if ((code == 0) && (local_result_code == 0)) + break; + sleep(1); + } + +cleanup: + if (chpw_snd.data != NULL) + free(chpw_snd.data); + if (chpw_rcv.data != NULL) + free(chpw_rcv.data); + if (targprinc != NULL) + krb5_free_principal(context, targprinc); + return(code); +} + +int set_password(char *user, char *password, char *domain) +{ + int res_code; + krb5_error_code retval; + char pw[PW_LENGTH+1]; + + memset(pw, '\0', sizeof(pw)); + if (strlen(password) != 0) + strcpy(pw, password); + else + generate_password(pw); + res_code = 0; + retval = kdc_set_password(context, ccache, pw, user, domain, &res_code); + + if (res_code) + return(res_code); + return(retval); +} + +void generate_password(char *password) +{ + int i; + int j; + int row_position; + int nchars; + int position; + int word; + int line; + char *pwp; + + for (line = 22; line; --line) + { + for (word = 7; word; --word) + { + position = myrandom()%total_sum; + for(row_position = 0, j = 0; position >= row_position; row_position += start_freq[j], j++) + continue; + *(pwp = password) = j + 'a' - 1; + for (nchars = PW_LENGTH-1; nchars; --nchars) + { + i = *pwp - 'a'; + pwp++; + position = myrandom()%row_sums[i]; + for (row_position = 0, j = 0; position >= row_position; row_position += frequency[i][j], j++) + continue; + *pwp = j + 'a' - 1; + } + *(++pwp)='\0'; + return; + } + putchar('\n'); + } +} + +long myrandom() +{ + static int init = 0; + int pid; +#ifdef _WIN32 + struct _timeb timebuffer; +#else + struct timeval tv; +#endif + + if (!init) + { + init = 1; + pid = getpid(); +#ifdef _WIN32 + _ftime(&timebuffer); + srand(timebuffer.time ^ timebuffer.millitm ^ pid); +#else + gettimeofday(&tv, (struct timezone *) NULL); + srandom(tv.tv_sec ^ tv.tv_usec ^ pid); +#endif + } + return (rand()); +} + +int get_krb5_error(krb5_error_code rc, char *in, char *out) +{ + int krb5Error; + int retval; + + retval = 1; + + if (rc < 0) + { + krb5Error = ((int)(rc & 255)); + sprintf(out, "%s: %s(%ld)", in, error_message(rc), krb5Error); + } + else + { + switch (rc) + { + case KDC_RECEIVE_TIMEOUT: + { + retval = 0; + sprintf(out, "%s: %s(%d)", in, "Receive timeout", rc); + break; + } + case KDC_RECEIVE_ERROR: + { + retval = 0; + sprintf(out, "%s: %s(%d)", in, "Receive error", rc); + break; + } + case KRB5_KPASSWD_MALFORMED: + { + sprintf(out, "%s: %s(%d)", in, "malformed password", rc); + break; + } + case KRB5_KPASSWD_HARDERROR: + { + sprintf(out, "%s: %s(%d)", in, "hard error", rc); + break; + } + case KRB5_KPASSWD_AUTHERROR: + { + retval = 0; + sprintf(out, "%s: %s(%d)", in, "authentication error", rc); + break; + } + case KRB5_KPASSWD_SOFTERROR: + { + retval = 0; + sprintf(out, "%s: %s(%d)", in, "soft error", rc); + break; + } + case KRB5_KPASSWD_ACCESSDENIED: + { + sprintf(out, "%s: %s(%d)", in, "Access denied", rc); + break; + } + case KDC_SEND_ERROR: + { + retval = 0; + sprintf(out, "%s: %s(%d)", in, "Send error", rc); + break; + } + case KDC_GETSOCKNAME_ERROR: + { + retval = 0; + sprintf(out, "%s: %s(%d)", in, "Socket error - getsockname", rc); + break; + } + case KDC_GETPEERNAME_ERROR: + { + retval = 0; + sprintf(out, "%s: %s(%d)", in, "Socket error - getpeername", rc); + break; + } + default: + { + sprintf(out, "%s: %s(%d)", in, "unknown error", rc); + break; + } + } + } + return(retval); +} + +int ad_connect(LDAP **ldap_handle, char *ldap_domain, char *dn_path, + char *Win2kPassword, char *Win2kUser, char *default_server, + int connect_to_kdc, char **ServerList, char *ldap_realm, + char *ldap_port) +{ + int i; + int k; + int Count; + char *server_name[MAX_SERVER_NAMES]; + static char temp[128]; + ULONG version = LDAP_VERSION3; + ULONG rc; + int Max_wait_time = 1000; + int Max_size_limit = LDAP_NO_LIMIT; + + if (strlen(ldap_domain) == 0) + return(1); + + if (strlen(ldap_port) == 0) + return(1); + + convert_domain_to_dn(ldap_domain, dn_path); + if (strlen(dn_path) == 0) + return(1); + + Count = 0; + while (ServerList[Count] != NULL) + ++Count; + + if ((Count == 0) && (connect_to_kdc)) + return(1); + + for (i = 0; i < Count; i++) + { + if (ServerList[i] == NULL) + continue; + + if (((*ldap_handle) = ldap_open(ServerList[i], atoi(ldap_port))) != NULL) + { + rc = ldap_set_option((*ldap_handle), LDAP_OPT_PROTOCOL_VERSION, + &version); + rc = ldap_set_option((*ldap_handle), LDAP_OPT_TIMELIMIT, + (void *)&Max_wait_time); + rc = ldap_set_option((*ldap_handle), LDAP_OPT_SIZELIMIT, + (void *)&Max_size_limit); + rc = ldap_set_option((*ldap_handle), LDAP_OPT_REFERRALS, + LDAP_OPT_OFF); + rc = ldap_adgssapi_bind((*ldap_handle), "", + GSSSASL_NO_SECURITY_LAYER, ldap_domain, + ldap_realm, ServerList[i]); + if (rc == LDAP_SUCCESS) + { + if (connect_to_kdc) + { + if (!ad_server_connect(ServerList[i], ldap_domain)) + { + ldap_unbind_s((*ldap_handle)); + (*ldap_handle) = NULL; + continue; + } + } + if (strlen(default_server) == 0) + strcpy(default_server, ServerList[i]); + strcpy(connected_server, ServerList[i]); + break; + } + else + { + (*ldap_handle) = NULL; + } + } + } + if ((*ldap_handle) == NULL) + return(1); + return(0); +} + +int ad_server_connect(char *connectedServer, char *domain) +{ + krb5_error_code rc; + krb5_creds creds; + krb5_creds *credsp; + char temp[256]; + char userrealm[256]; + int i; + unsigned short port = KDC_PORT; + + context = NULL; + credsp = NULL; + memset(&ccache, 0, sizeof(ccache)); + memset(&creds, 0, sizeof(creds)); + memset(userrealm, '\0', sizeof(userrealm)); + + rc = 0; + if (krb5_init_context(&context)) + goto cleanup; + if (krb5_cc_default(context, &ccache)) + goto cleanup; + + for (i = 0; i < (int)strlen(domain); i++) + userrealm[i] = toupper(domain[i]); + sprintf(temp, "%s@%s", "kadmin/changepw", userrealm); + if (krb5_parse_name(context, temp, &creds.server)) + goto cleanup; + if (krb5_cc_get_principal(context, ccache, &creds.client)) + goto cleanup; + if (krb5_get_credentials(context, 0, ccache, &creds, &credsp)) + goto cleanup; + + rc = ad_kdc_connect(connectedServer); + + +cleanup: + if (!rc) + { + krb5_cc_close(context, ccache); + krb5_free_context(context); + } + krb5_free_cred_contents(context, &creds); + if (credsp != NULL) + krb5_free_creds(context, credsp); + return(rc); +} + + +int ad_kdc_connect(char *connectedServer) +{ + struct hostent *hp; + int rc; + + rc = 0; + hp = gethostbyname(connectedServer); + if (hp == NULL) + goto cleanup; + memset(&kdc_server, 0, sizeof(kdc_server)); + memcpy(&(kdc_server.sin_addr),hp->h_addr_list[0],hp->h_length); + kdc_server.sin_family = hp->h_addrtype; + kdc_server.sin_port = htons(KDC_PORT); + + if ((kdc_socket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) + goto cleanup; + if (connect(kdc_socket, (struct sockaddr*)&kdc_server, sizeof(kdc_server)) == SOCKET_ERROR) + goto cleanup; + rc = 1; + +cleanup: + return(rc); +} + +void ad_kdc_disconnect() +{ + + if (auth_context != NULL) + { + krb5_auth_con_free(context, auth_context); + if (ap_req.data != NULL) + free(ap_req.data); + krb5_free_cred_contents(context, &creds); + if (credsp != NULL) + krb5_free_creds(context, credsp); + } + credsp = NULL; + auth_context = NULL; + if (context != NULL) + { + krb5_cc_close(context, ccache); + krb5_free_context(context); + } + closesocket(kdc_socket); + +} + +int convert_domain_to_dn(char *domain, char *dnp) +{ + char *fp; + char *dp; + char dn[512]; + + memset(dn, '\0', sizeof(dn)); + strcpy(dn, "dc="); + dp = dn+3; + for (fp = domain; *fp; fp++) + { + if (*fp == '.') + { + strcpy(dp, ",dc="); + dp += 4; + } + else + *dp++ = *fp; + } + + strcpy(dnp, dn); + return 0; +} + +int compare_elements(const void *arg1, const void *arg2) +{ + int rc; + + rc = strcmp((char*)arg1, (char*)arg2); + if (rc < 0) + return(1); + if (rc > 0) + return(-1); + return(rc); +} diff --git a/incremental/ldap/winad.c b/incremental/ldap/winad.c new file mode 100755 index 00000000..76877cdc --- /dev/null +++ b/incremental/ldap/winad.c @@ -0,0 +1,8922 @@ +/* $Header$ +/* ldap.incr arguments example + * + * arguments when moira creates the account - ignored by ldap.incr since the + * account is unusable. users 0 11 #45198 45198 /bin/cmd cmd Last First Middle + * 0 950000001 2000 121049 + * + * login, unix_uid, shell, winconsoleshell, last, + * first, middle, status, mitid, type, moiraid + * + * arguments for creating or updating a user account + * users 11 11 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF + * 121058 PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last + * First Middle 1 950000001 STAFF 121058 PathToHomeDir PathToProfileDir + * users 11 11 #45206 45206 /bin/cmd cmd Last First Middle 0 950000001 STAFF + * 121058 PathToHomeDir PathToProfileDir newuser 45206 /bin/cmd cmd Last + * First Middle 2 950000001 STAFF 121058 PathToHomeDir PathToProfileDir + * + * login, unix_uid, shell, winconsoleshell, last, first, middle, status, + * mitid, type, moiraid + * + * arguments for deactivating/deleting a user account + * users 11 11 username 45206 /bin/cmd cmd Last First Middle 1 950000001 STAFF + * 121058 PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last + * First Middle 3 950000001 STAFF 121058 PathToHomeDir PathToProfileDir + * users 11 11 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF + * 121058 PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last + * First Middle 3 950000001 STAFF 121058 PathToHomeDir PathToProfileDir + * + * login, unix_uid, shell, winconsoleshell, last, first, middle, status, + * mitid, type, moiraid + * + * arguments for reactivating a user account + * users 11 11 username 45206 /bin/cmd cmd Last First Middle 3 950000001 STAFF + * 121058 username 45206 /bin/cmd cmd Last First Middle 1 950000001 STAFF + * 121058 + * users 11 11 username 45206 /bin/cmd cmd Last First Middle 3 950000001 STAFF + * 121058 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF 12105 + * + * login, unix_uid, shell, winconsoleshell, last, first, middle, status, + * mitid, type, moiraid + * + * arguments for changing user name + * users 11 11 oldusername 45206 /bin/cmd cmd Last First Middle 1 950000001 + * STAFF 121058 PathToHomeDir PathToProfileDir newusername 45206 /bin/cmd cmd + * Last First Middle 1 950000001 STAFF 121058 PathToHomeDir PathToProfileDir + * + * login, unix_uid, shell, winconsoleshell, last, first, middle, status, + * mitid, type, moiraid + * + * arguments for expunging a user + * users 11 0 username 45198 /bin/cmd cmd Last First Middle 0 950000001 2000 + * 121049 + * + * login, unix_uid, shell, winconsoleshell, last, first, middle, status, + * mitid, type, moiraid + * + * arguments for creating a "special" group/list + * list 0 11 listname 1 1 0 0 0 -1 NONE 0 description 92616 + * + * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, + * acl_id, description, moiraid + * + * arguments for creating a "mail" group/list + * list 0 11 listname 1 1 0 1 0 -1 NONE 0 description 92616 + * + * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, + * acl_id, description, moiraid + * + * arguments for creating a "group" group/list + * list 0 11 listname 1 1 0 0 1 -1 NONE 0 description 92616 + * + * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, + * acl_id, description, moiraid + * + * arguments for creating a "group/mail" group/list + * list 0 11 listname 1 1 0 1 1 -1 NONE 0 description 92616 + * + * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, + * acl_id, description, moiraid + * + * arguments to add a USER member to group/list + * imembers 0 12 listname USER userName 1 1 0 0 0 -1 1 92616 121047 + * + * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist, + * gid, userStatus, moiraListId, moiraUserId + * + * arguments to add a STRING or KERBEROS member to group/list + * imembers 0 10 listname STRING stringName 1 1 0 0 0 -1 92616 + * imembers 0 10 listlistnameName KERBEROS kerberosName 1 1 0 0 0 -1 92616 + * + * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist, + * gid, moiraListId + * + * NOTE: group members of type LIST are ignored. + * + * arguments to remove a USER member to group/list + * imembers 12 0 listname USER userName 1 1 0 0 0 -1 1 92616 121047 + * + * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist, + * gid, userStatus, moiraListId, moiraUserId + * + * arguments to remove a STRING or KERBEROS member to group/list + * imembers 10 0 listname STRING stringName 1 1 0 0 0 -1 92616 + * imembers 10 0 listname KERBEROS kerberosName 1 1 0 0 0 -1 92616 + * + * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist, + * gid, moiraListId + * + * NOTE: group members of type LIST are ignored. + * + * arguments for renaming a group/list + * list 11 11 oldlistname 1 1 0 0 0 -1 NONE 0 description 92616 newlistname 1 + * 1 0 0 0 -1 description 0 92616 + * + * name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, + * acl_id, description, moiraListId + * + * arguments for deleting a group/list + * list 11 0 listname 1 1 0 0 0 -1 NONE 0 description 92616 + * + * name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, + * acl_id, description, moiraListId + * + * arguments for adding a file system + * filesys 0 12 username AFS ATHENA.MIT.EDU + * /afs/athena.mit.edu/user/n/e/username /mit/username w descripton username + * wheel 1 HOMEDIR 101727 + * + * arguments for deleting a file system + * filesys 12 0 username AFS ATHENA.MIT.EDU + * /afs/athena.mit.edu/user/n/e/username /mit/username w descripton username + * wheel 1 HOMEDIR 101727 + * + * arguments when moira creates a container (OU). + * containers 0 8 machines/test/bottom description location contact USER + * 105316 2222 [none] + * + * arguments when moira deletes a container (OU). + * containers 8 0 machines/test/bottom description location contact USER + * 105316 2222 groupname + * + * arguments when moira modifies a container information (OU). + * containers 8 8 machines/test/bottom description location contact USER + * 105316 2222 groupname machines/test/bottom description1 location contact + * USER 105316 2222 groupname + * + * arguments when moira adds a machine from an OU + * table name, beforec, afterc, machine_name, container_name, mach_id, cnt_id + * mcntmap 0 5 DAVIDT.MIT.EDU dttest/dttest1 76767 46 groupname + * + * arguments when moira removes a machine from an OU + * table name, beforec, afterc, machine_name, container_name, mach_id, cnt_id + * mcntmap 0 5 DAVIDT.MIT.EDU dttest/dttest1 76767 46 groupname + * +*/ + +#include + +#ifdef _WIN32 +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kpasswd.h" + +#ifdef _WIN32 +#ifndef ECONNABORTED +#define ECONNABORTED WSAECONNABORTED +#endif +#ifndef ECONNREFUSED +#define ECONNREFUSED WSAECONNREFUSED +#endif +#ifndef EHOSTUNREACH +#define EHOSTUNREACH WSAEHOSTUNREACH +#endif +#define krb5_xfree free +#define F_OK 0 +#define sleep(A) Sleep(A * 1000); +#endif /* _WIN32 */ + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include + +#define CFG_PATH "/moira/ldap/" +#define WINADCFG "ldap.cfg" +#define strnicmp(A,B,C) strncasecmp(A,B,C) +#define UCHAR unsigned char + +#define UF_SCRIPT 0x0001 +#define UF_ACCOUNTDISABLE 0x0002 +#define UF_HOMEDIR_REQUIRED 0x0008 +#define UF_LOCKOUT 0x0010 +#define UF_PASSWD_NOTREQD 0x0020 +#define UF_PASSWD_CANT_CHANGE 0x0040 +#define UF_DONT_EXPIRE_PASSWD 0x10000 + +#define UF_TEMP_DUPLICATE_ACCOUNT 0x0100 +#define UF_NORMAL_ACCOUNT 0x0200 +#define UF_INTERDOMAIN_TRUST_ACCOUNT 0x0800 +#define UF_WORKSTATION_TRUST_ACCOUNT 0x1000 +#define UF_SERVER_TRUST_ACCOUNT 0x2000 + +#define OWNER_SECURITY_INFORMATION (0x00000001L) +#define GROUP_SECURITY_INFORMATION (0x00000002L) +#define DACL_SECURITY_INFORMATION (0x00000004L) +#define SACL_SECURITY_INFORMATION (0x00000008L) + +#ifndef BYTE +#define BYTE unsigned char +#endif +typedef unsigned int DWORD; +typedef unsigned long ULONG; + +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +} GUID; + +typedef struct _SID_IDENTIFIER_AUTHORITY { + BYTE Value[6]; +} SID_IDENTIFIER_AUTHORITY, *PSID_IDENTIFIER_AUTHORITY; + +typedef struct _SID { + BYTE Revision; + BYTE SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + DWORD SubAuthority[512]; +} SID; +#endif/*!WIN32*/ + +#ifndef WINADCFG +#define WINADCFG "ldap.cfg" +#endif + +#ifndef CFG_PATH +#define CFG_PATH "" +#endif + +#define AFS "/afs/" +#define WINAFS "\\\\afs\\all\\" + +#define ADS_GROUP_TYPE_GLOBAL_GROUP 0x00000002 +#define ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP 0x00000004 +#define ADS_GROUP_TYPE_LOCAL_GROUP 0x00000004 +#define ADS_GROUP_TYPE_UNIVERSAL_GROUP 0x00000008 +#define ADS_GROUP_TYPE_SECURITY_ENABLED 0x80000000 + +#define QUERY_VERSION -1 +#define PRIMARY_REALM "ATHENA.MIT.EDU" +#define PRIMARY_DOMAIN "win.mit.edu" +#define PRODUCTION_PRINCIPAL "sms" +#define TEST_PRINCIPAL "smstest" + +#define SUBSTITUTE 1 +#define REPLACE 2 + +#define USERS 0 +#define GROUPS 1 + +#define MEMBER_ADD 1 +#define MEMBER_REMOVE 2 +#define MEMBER_CHANGE_NAME 3 +#define MEMBER_ACTIVATE 4 +#define MEMBER_DEACTIVATE 5 +#define MEMBER_CREATE 6 + +#define MOIRA_ALL 0x0 +#define MOIRA_USERS 0x1 +#define MOIRA_KERBEROS 0x2 +#define MOIRA_STRINGS 0x4 +#define MOIRA_LISTS 0x8 + +#define CHECK_GROUPS 1 +#define CLEANUP_GROUPS 2 + +#define AD_NO_GROUPS_FOUND -1 +#define AD_WRONG_GROUP_DN_FOUND -2 +#define AD_MULTIPLE_GROUPS_FOUND -3 +#define AD_INVALID_NAME -4 +#define AD_LDAP_FAILURE -5 +#define AD_INVALID_FILESYS -6 +#define AD_NO_ATTRIBUTE_FOUND -7 +#define AD_NO_OU_FOUND -8 +#define AD_NO_USER_FOUND -9 + +/* container arguments */ +#define CONTAINER_NAME 0 +#define CONTAINER_DESC 1 +#define CONTAINER_LOCATION 2 +#define CONTAINER_CONTACT 3 +#define CONTAINER_TYPE 4 +#define CONTAINER_ID 5 +#define CONTAINER_ROWID 6 +#define CONTAINER_GROUP_NAME 7 + +/*mcntmap arguments*/ +#define OU_MACHINE_NAME 0 +#define OU_CONTAINER_NAME 1 +#define OU_MACHINE_ID 2 +#define OU_CONTAINER_ID 3 +#define OU_CONTAINER_GROUP 4 + +typedef struct lk_entry { + int op; + int length; + int ber_value; + char *dn; + char *attribute; + char *value; + char *member; + char *type; + char *list; + struct lk_entry *next; +} LK_ENTRY; + +#define STOP_FILE "/moira/ldap/noldap" +#define file_exists(file) (access((file), F_OK) == 0) + +#define N_SD_BER_BYTES 5 +#define LDAP_BERVAL struct berval +#define MAX_SERVER_NAMES 32 + +#define HIDDEN_GROUP "HiddenGroup.g" +#define HIDDEN_GROUP_WITH_ADMIN "HiddenGroupWithAdmin.g" +#define NOT_HIDDEN_GROUP "NotHiddenGroup.g" +#define NOT_HIDDEN_GROUP_WITH_ADMIN "NotHiddenGroupWithAdmin.g" + +#define ADDRESS_LIST_PREFIX "CN=MIT Directory,CN=All Address Lists,\ +CN=Address Lists Container,CN=Massachusetts Institute of Technology,\ +CN=Microsoft Exchange,CN=Services,CN=Configuration," + +#define ADD_ATTR(t, v, o) \ + mods[n] = malloc(sizeof(LDAPMod)); \ + mods[n]->mod_op = o; \ + mods[n]->mod_type = t; \ + mods[n++]->mod_values = v + +#define DEL_ATTR(t, o) \ + DelMods[i] = malloc(sizeof(LDAPMod)); \ + DelMods[i]->mod_op = o; \ + DelMods[i]->mod_type = t; \ + DelMods[i++]->mod_values = NULL + +#define DOMAIN_SUFFIX "MIT.EDU" +#define DOMAIN "DOMAIN:" +#define PRINCIPALNAME "PRINCIPAL:" +#define SERVER "SERVER:" +#define MSSFU "SFU:" +#define SFUTYPE "30" +#define GROUP_SUFFIX "GROUP_SUFFIX:" +#define GROUP_TYPE "GROUP_TYPE:" +#define SET_GROUP_ACE "SET_GROUP_ACE:" +#define SET_PASSWORD "SET_PASSWORD:" +#define EXCHANGE "EXCHANGE:" +#define REALM "REALM:" +#define ACTIVE_DIRECTORY "ACTIVE_DIRECTORY:" +#define PORT "PORT:" +#define PROCESS_MACHINE_CONTAINER "PROCESS_MACHINE_CONTAINER:" +#define MAX_DOMAINS 10 +char DomainNames[MAX_DOMAINS][128]; + +LK_ENTRY *member_base = NULL; + +char PrincipalName[128]; +static char tbl_buf[1024]; +char kerberos_ou[] = "OU=kerberos,OU=moira"; +char contact_ou[] = "OU=strings,OU=moira"; +char user_ou[] = "OU=users,OU=moira"; +char group_ou_distribution[1024]; +char group_ou_root[1024]; +char group_ou_security[1024]; +char group_ou_neither[1024]; +char group_ou_both[1024]; +char orphans_machines_ou[] = "OU=Machines,OU=Orphans"; +char orphans_other_ou[] = "OU=Other,OU=Orphans"; +char security_template_ou[] = "OU=security_templates"; +char *whoami; +char ldap_domain[256]; +char ldap_realm[256]; +char ldap_port[256]; +char *ServerList[MAX_SERVER_NAMES]; +char default_server[256]; +static char tbl_buf[1024]; +char group_suffix[256]; +char exchange_acl[256]; +int mr_connections = 0; +int callback_rc; +int UseSFU30 = 0; +int UseGroupSuffix = 1; +int UseGroupUniversal = 0; +int SetGroupAce = 1; +int SetPassword = 1; +int Exchange = 0; +int ProcessMachineContainer = 1; +int ActiveDirectory = 1; +int UpdateDomainList; + +extern int set_password(char *user, char *password, char *domain); + +int ad_get_group(LDAP *ldap_handle, char *dn_path, char *group_name, + char *group_membership, char *MoiraId, char *attribute, + LK_ENTRY **linklist_base, int *linklist_count, + char *rFilter); +void AfsToWinAfs(char* path, char* winPath); +int ad_connect(LDAP **ldap_handle, char *ldap_domain, char *dn_path, + char *Win2kPassword, char *Win2kUser, char *default_server, + int connect_to_kdc, char **ServerList, char *ldap_realm, + char *ldap_port); +void ad_kdc_disconnect(); +int ad_server_connect(char *connectedServer, char *domain); +int attribute_update(LDAP *ldap_handle, char *distinguished_name, + char *attribute_value, char *attribute, char *user_name); +int BEREncodeSecurityBits(ULONG uBits, char *pBuffer); +int checkADname(LDAP *ldap_handle, char *dn_path, char *Name); +int check_winad(void); +int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, + char *MoiraId); +/* containers */ +int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, + char *distinguishedName, int count, char **av); +void container_check(LDAP *ldap_handle, char *dn_path, char *name); +int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av); +int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av); +int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, + char *distinguishedName, int count, + char **av); +void container_get_dn(char *src, char *dest); +void container_get_name(char *src, char *dest); +int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName); +int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, + char **before, int afterc, char **after); +int container_update(LDAP *ldap_handle, char *dn_path, int beforec, + char **before, int afterc, char **after); + +int GetAceInfo(int ac, char **av, void *ptr); +int get_group_membership(char *group_membership, char *group_ou, + int *security_flag, char **av); +int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, + char *machine_ou, char *pPtr); +int Moira_container_group_create(char **after); +int Moira_container_group_delete(char **before); +int Moira_groupname_create(char *GroupName, char *ContainerName, + char *ContainerRowID); +int Moira_container_group_update(char **before, char **after); +int Moira_process_machine_container_group(char *MachineName, char* groupName, + int DeleteMachine); +int Moira_addGroupToParent(char *origContainerName, char *GroupName); +int Moira_getContainerGroup(int ac, char **av, void *ptr); +int Moira_getGroupName(char *origContainerName, char *GroupName, + int ParentFlag); +int Moira_setContainerGroup(char *ContainerName, char *GroupName); +int ProcessAce(LDAP *ldap_handle, char *dn_path, char *group_name, char *Type, + int UpdateGroup, int *ProcessGroup, char *maillist); +int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, + char *group_name, char *group_ou, char *group_membership, + int group_security_flag, int type, char *maillist); +int process_lists(int ac, char **av, void *ptr); +int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, + char *TargetGroupName, int HiddenGroup, + char *AceType, char *AceName); +int ProcessMachineName(int ac, char **av, void *ptr); +int ReadConfigFile(char *DomainName); +int ReadDomainList(); +void StringTrim(char *StringToTrim); +char *escape_string(char *s); +int save_query_info(int argc, char **argv, void *hint); +int user_create(int ac, char **av, void *ptr); +int user_change_status(LDAP *ldap_handle, char *dn_path, + char *user_name, char *MoiraId, int operation); +int user_delete(LDAP *ldap_handle, char *dn_path, + char *u_name, char *MoiraId); +int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, + char *user_name); +int user_update(LDAP *ldap_handle, char *dn_path, char *user_name, + char *uid, char *MitId, char *MoiraId, int State, + char *WinHomeDir, char *WinProfileDir, char *first, + char *middle, char *last, char *shell, char *class); +void change_to_lower_case(char *ptr); +int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou); +int contact_remove_email(LDAP *ld, char *bind_path, + LK_ENTRY **linklist_entry, int linklist_current); +int group_create(int ac, char **av, void *ptr); +int group_delete(LDAP *ldap_handle, char *dn_path, + char *group_name, char *group_membership, char *MoiraId); +int group_rename(LDAP *ldap_handle, char *dn_path, + char *before_group_name, char *before_group_membership, + char *before_group_ou, int before_security_flag, + char *before_desc, char *after_group_name, + char *after_group_membership, char *after_group_ou, + int after_security_flag, char *after_desc, + char *MoiraId, char *filter, char *maillist); +int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name); +int machine_GetMoiraContainer(int ac, char **av, void *ptr); +int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, + char *machine_name, char *container_name); +int machine_move_to_ou(LDAP *ldap_handle, char *dn_path, + char *MoiraMachineName, char *DestinationOu); +int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, + char *group_name, char *group_ou, char *group_membership, + int group_security_flag, int updateGroup, char *maillist); +int member_list_build(int ac, char **av, void *ptr); +int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, + char *group_ou, char *group_membership, + char *user_name, char *pUserOu, char *MoiraId); +int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, + char *group_ou, char *group_membership, char *user_name, + char *pUserOu, char *MoiraId); +int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, + char *group_ou, char *group_membership, + int group_security_flag, char *MoiraId); +int SetHomeDirectory(LDAP *ldap_handle, char *user_name, + char *DistinguishedName, + char *WinHomeDir, char *WinProfileDir, + char **homedir_v, char **winProfile_v, + char **drives_v, LDAPMod **mods, + int OpType, int n); +int sid_update(LDAP *ldap_handle, char *dn_path); +void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n); +int check_string(char *s); +int check_container_name(char* s); + +int mr_connect_cl(char *server, char *client, int version, int auth); +void do_container(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, int afterc); +void do_filesys(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, int afterc); +void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, int afterc); +void do_user(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, int afterc); +void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, int afterc); +void do_mcntmap(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, int afterc); +int linklist_create_entry(char *attribute, char *value, + LK_ENTRY **linklist_entry); +int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, + char **attr_array, LK_ENTRY **linklist_base, + int *linklist_count, unsigned long ScopeType); +void linklist_free(LK_ENTRY *linklist_base); + +int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, + char *distinguished_name, LK_ENTRY **linklist_current); +int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, + LK_ENTRY **linklist_base, int *linklist_count); +int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry, + char *Attribute, char *distinguished_name, + LK_ENTRY **linklist_current); + +int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, + char *oldValue, char *newValue, + char ***modvalues, int type); +void free_values(char **modvalues); + +int convert_domain_to_dn(char *domain, char **bind_path); +void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry, + char *distinguished_name); +int moira_disconnect(void); +int moira_connect(void); +void print_to_screen(const char *fmt, ...); +int GetMachineName(char *MachineName); +int tickets_get_k5(); +int destroy_cache(void); +int dest_tkt(void); + +int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, + char **homeServerName); + +int main(int argc, char **argv) +{ + unsigned long rc; + int beforec; + int afterc; + int i; + int j; + int k; + int OldUseSFU30; + char *table; + char **before; + char **after; + LDAP *ldap_handle; + char dn_path[256]; + char *orig_argv[64]; + + whoami = ((whoami = (char *)strrchr(argv[0], '/')) ? whoami+1 : argv[0]); + + if (argc < 4) + { + com_err(whoami, 0, "Unable to process %s", "argc < 4"); + exit(1); + } + + if (argc < (4 + atoi(argv[2]) + atoi(argv[3]))) + { + com_err(whoami, 0, "Unable to process %s", + "argc < (4 + beforec + afterc)"); + exit(1); + } + + if (!strcmp(argv[1], "filesys")) + exit(0); + + for (i = 1; i < argc; i++) + { + strcat(tbl_buf, argv[i]); + strcat(tbl_buf, " "); + } + + com_err(whoami, 0, "%s", tbl_buf); + + if (check_winad()) + { + com_err(whoami, 0, "%s failed", "check_winad()"); + exit(1); + } + + initialize_sms_error_table(); + initialize_krb_error_table(); + + UpdateDomainList = 0; + memset(DomainNames, '\0', sizeof(DomainNames[0]) * MAX_DOMAINS); + + if (ReadDomainList()) + { + com_err(whoami, 0, "%s failed", "ReadDomainList()"); + exit(1); + } + + for (i = 0; i < argc; i++) + orig_argv[i] = NULL; + + for (k = 0; k < MAX_DOMAINS; k++) + { + if (strlen(DomainNames[k]) == 0) + continue; + for (i = 0; i < argc; i++) + { + if (orig_argv[i] != NULL) + free(orig_argv[i]); + orig_argv[i] = strdup(argv[i]); + } + + memset(PrincipalName, '\0', sizeof(PrincipalName)); + memset(ldap_domain, '\0', sizeof(ldap_domain)); + memset(ServerList, '\0', sizeof(ServerList[0]) * MAX_SERVER_NAMES); + memset(default_server, '\0', sizeof(default_server)); + memset(dn_path, '\0', sizeof(dn_path)); + memset(group_suffix, '\0', sizeof(group_suffix)); + memset(exchange_acl, '\0', sizeof(exchange_acl)); + + UseSFU30 = 0; + UseGroupSuffix = 1; + UseGroupUniversal = 0; + SetGroupAce = 1; + SetPassword = 1; + Exchange = 0; + ProcessMachineContainer = 1; + ActiveDirectory = 1; + + sprintf(group_suffix, "%s", "_group"); + sprintf(exchange_acl, "%s", "exchange-acl"); + + beforec = atoi(orig_argv[2]); + afterc = atoi(orig_argv[3]); + table = orig_argv[1]; + before = &orig_argv[4]; + after = &orig_argv[4 + beforec]; + + if (afterc == 0) + after = NULL; + + if (beforec == 0) + before = NULL; + + if (ReadConfigFile(DomainNames[k])) + continue; + + if(ActiveDirectory) + { + sprintf(group_ou_distribution, "OU=mail,OU=lists,OU=moira"); + sprintf(group_ou_root, "OU=lists,OU=moira"); + sprintf(group_ou_security, "OU=group,OU=lists,OU=moira"); + sprintf(group_ou_neither, "OU=special,OU=lists,OU=moira"); + sprintf(group_ou_both, "OU=mail,OU=group,OU=lists,OU=moira"); + } + else + { + sprintf(group_ou_distribution, "OU=lists,OU=moira"); + sprintf(group_ou_root, "OU=lists,OU=moira"); + sprintf(group_ou_security, "OU=lists,OU=moira"); + sprintf(group_ou_neither, "OU=lists,OU=moira"); + sprintf(group_ou_both, "OU=lists,OU=moira"); + } + + OldUseSFU30 = UseSFU30; + + for (i = 0; i < 5; i++) + { + ldap_handle = (LDAP *)NULL; + if (!(rc = ad_connect(&ldap_handle, ldap_domain, dn_path, "", "", + default_server, SetPassword, ServerList, + ldap_realm, ldap_port))) + { + com_err(whoami, 0, "connected to domain %s", DomainNames[k]); + break; + } + } + + if ((rc) || (ldap_handle == NULL)) + { + critical_alert("incremental", + "ldap.incr cannot connect to any server in " + "domain %s", DomainNames[k]); + continue; + } + + for (i = 0; i < (int)strlen(table); i++) + table[i] = tolower(table[i]); + + if (!strcmp(table, "users")) + do_user(ldap_handle, dn_path, ldap_domain, before, beforec, after, + afterc); + else if (!strcmp(table, "list")) + do_list(ldap_handle, dn_path, ldap_domain, before, beforec, after, + afterc); + else if (!strcmp(table, "imembers")) + do_member(ldap_handle, dn_path, ldap_domain, before, beforec, after, + afterc); + else if (!strcmp(table, "containers")) + do_container(ldap_handle, dn_path, ldap_domain, before, beforec, after, + afterc); + else if (!strcmp(table, "mcntmap")) + do_mcntmap(ldap_handle, dn_path, ldap_domain, before, beforec, after, + afterc); + + if(SetPassword) + ad_kdc_disconnect(); + + for (i = 0; i < MAX_SERVER_NAMES; i++) + { + if (ServerList[i] != NULL) + { + free(ServerList[i]); + ServerList[i] = NULL; + } + } + + rc = ldap_unbind_s(ldap_handle); + } + + exit(0); +} + +void do_mcntmap(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, int afterc) +{ + char MoiraContainerName[128]; + char ADContainerName[128]; + char MachineName[1024]; + char OriginalMachineName[1024]; + long rc; + int DeleteMachine; + char MoiraContainerGroup[64]; + + if (!ProcessMachineContainer) + { + com_err(whoami, 0, "Process machines and containers disabled, skipping"); + return; + } + + DeleteMachine = 0; + memset(ADContainerName, '\0', sizeof(ADContainerName)); + memset(MoiraContainerName, '\0', sizeof(MoiraContainerName)); + + if ((beforec == 0) && (afterc == 0)) + return; + + if (rc = moira_connect()) + { + critical_alert("AD incremental", + "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + if ((beforec != 0) && (afterc == 0)) /*remove a machine*/ + { + strcpy(OriginalMachineName, before[OU_MACHINE_NAME]); + strcpy(MachineName, before[OU_MACHINE_NAME]); + strcpy(MoiraContainerGroup, before[OU_CONTAINER_GROUP]); + DeleteMachine = 1; + com_err(whoami, 0, "removing machine %s from %s", + OriginalMachineName, before[OU_CONTAINER_NAME]); + } + else if ((beforec == 0) && (afterc != 0)) /*add a machine*/ + { + strcpy(OriginalMachineName, after[OU_MACHINE_NAME]); + strcpy(MachineName, after[OU_MACHINE_NAME]); + strcpy(MoiraContainerGroup, after[OU_CONTAINER_GROUP]); + com_err(whoami, 0, "adding machine %s to container %s", + OriginalMachineName, after[OU_CONTAINER_NAME]); + } + else + { + moira_disconnect(); + return; + } + + rc = GetMachineName(MachineName); + + if (strlen(MachineName) == 0) + { + moira_disconnect(); + com_err(whoami, 0, "Unable to find alais for machine %s in Moira", + OriginalMachineName); + return; + } + + Moira_process_machine_container_group(MachineName, MoiraContainerGroup, + DeleteMachine); + + if (machine_check(ldap_handle, dn_path, MachineName)) + { + com_err(whoami, 0, "Unable to find machine %s (alias %s) in AD.", + OriginalMachineName, MachineName); + moira_disconnect(); + return; + } + + memset(MoiraContainerName, '\0', sizeof(MoiraContainerName)); + machine_get_moira_container(ldap_handle, dn_path, MachineName, + MoiraContainerName); + + if (strlen(MoiraContainerName) == 0) + { + com_err(whoami, 0, "Unable to fine machine %s (alias %s) container " + "in Moira - moving to orphans OU.", + OriginalMachineName, MachineName); + machine_move_to_ou(ldap_handle, dn_path, MachineName, + orphans_machines_ou); + moira_disconnect(); + return; + } + + container_get_dn(MoiraContainerName, ADContainerName); + + if (MoiraContainerName[strlen(MoiraContainerName) - 1] != '/') + strcat(MoiraContainerName, "/"); + + container_check(ldap_handle, dn_path, MoiraContainerName); + machine_move_to_ou(ldap_handle, dn_path, MachineName, ADContainerName); + moira_disconnect(); + return; +} + +void do_container(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, int afterc) +{ + long rc; + + if (!ProcessMachineContainer) + { + com_err(whoami, 0, "Process machines and containers disabled, skipping"); + return; + } + + if ((beforec == 0) && (afterc == 0)) + return; + + if (rc = moira_connect()) + { + critical_alert("AD incremental", "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + if ((beforec != 0) && (afterc == 0)) /*delete a new container*/ + { + com_err(whoami, 0, "deleting container %s", before[CONTAINER_NAME]); + container_delete(ldap_handle, dn_path, beforec, before); + Moira_container_group_delete(before); + moira_disconnect(); + return; + } + + if ((beforec == 0) && (afterc != 0)) /*create a container*/ + { + com_err(whoami, 0, "creating container %s", after[CONTAINER_NAME]); + container_check(ldap_handle, dn_path, after[CONTAINER_NAME]); + container_create(ldap_handle, dn_path, afterc, after); + Moira_container_group_create(after); + moira_disconnect(); + return; + } + + if (strcasecmp(before[CONTAINER_NAME], after[CONTAINER_NAME])) + { + com_err(whoami, 0, "renaming container %s to %s", + before[CONTAINER_NAME], after[CONTAINER_NAME]); + container_rename(ldap_handle, dn_path, beforec, before, afterc, after); + Moira_container_group_update(before, after); + moira_disconnect(); + return; + } + + com_err(whoami, 0, "updating container %s information", + after[CONTAINER_NAME]); + container_update(ldap_handle, dn_path, beforec, before, afterc, after); + Moira_container_group_update(before, after); + moira_disconnect(); + return; +} + +#define L_LIST_DESC 9 +#define L_LIST_ID 10 + +void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, int afterc) +{ + int updateGroup; + int ProcessGroup; + long rc; + char group_membership[6]; + char list_id[32]; + int security_flag; + char filter[128]; + char group_ou[256]; + char before_list_id[32]; + char before_group_membership[1]; + int before_security_flag; + char before_group_ou[256]; + LK_ENTRY *ptr = NULL; + + if (beforec == 0 && afterc == 0) + return; + + memset(list_id, '\0', sizeof(list_id)); + memset(before_list_id, '\0', sizeof(before_list_id)); + memset(before_group_ou, '\0', sizeof(before_group_ou)); + memset(before_group_membership, '\0', sizeof(before_group_membership)); + memset(group_ou, '\0', sizeof(group_ou)); + memset(group_membership, '\0', sizeof(group_membership)); + updateGroup = 0; + + if (beforec > L_GID) + { + if (beforec < L_LIST_ID) + return; + if (beforec > L_LIST_DESC) + { + strcpy(before_list_id, before[L_LIST_ID]); + } + before_security_flag = 0; + get_group_membership(before_group_membership, before_group_ou, + &before_security_flag, before); + } + + if (afterc > L_GID) + { + if (afterc < L_LIST_ID) + return; + if (afterc > L_LIST_DESC) + { + strcpy(list_id, after[L_LIST_ID]); + } + security_flag = 0; + get_group_membership(group_membership, group_ou, &security_flag, after); + } + + if ((beforec == 0) && (afterc == 0)) /*this case should never happen*/ + return; + + updateGroup = 0; + + if (beforec) + { + updateGroup = 1; + + if ((rc = process_group(ldap_handle, dn_path, before_list_id, + before[L_NAME], before_group_ou, + before_group_membership, + before_security_flag, CHECK_GROUPS, + before[L_MAILLIST]))) + { + if (rc == AD_NO_GROUPS_FOUND) + updateGroup = 0; + else + { + if ((rc == AD_WRONG_GROUP_DN_FOUND) || + (rc == AD_MULTIPLE_GROUPS_FOUND)) + { + rc = process_group(ldap_handle, dn_path, before_list_id, + before[L_NAME], before_group_ou, + before_group_membership, + before_security_flag, CLEANUP_GROUPS, + before[L_MAILLIST]); + } + if ((rc != AD_NO_GROUPS_FOUND) && (rc != 0)) + { + com_err(whoami, 0, "Unable to process list %s", + before[L_NAME]); + return; + } + if (rc == AD_NO_GROUPS_FOUND) + updateGroup = 0; + } + } + } + + if ((beforec != 0) && (afterc != 0)) + { + if (((strcmp(after[L_NAME], before[L_NAME])) || + ((!strcmp(after[L_NAME], before[L_NAME])) && + (strcmp(before_group_ou, group_ou)))) && + (updateGroup == 1)) + { + com_err(whoami, 0, "Changing list name from %s to %s", + before[L_NAME], after[L_NAME]); + + if ((strlen(before_group_ou) == 0) || + (strlen(before_group_membership) == 0) || + (strlen(group_ou) == 0) || (strlen(group_membership) == 0)) + { + com_err(whoami, 0, "%s", "Unable to find the group OU's"); + return; + } + + memset(filter, '\0', sizeof(filter)); + + if ((rc = group_rename(ldap_handle, dn_path, + before[L_NAME], before_group_membership, + before_group_ou, before_security_flag, + before[L_LIST_DESC], after[L_NAME], + group_membership, group_ou, security_flag, + after[L_LIST_DESC], + list_id, filter, after[L_MAILLIST]))) + { + if (rc != AD_NO_GROUPS_FOUND) + { + com_err(whoami, 0, + "Unable to change list name from %s to %s", + before[L_NAME], after[L_NAME]); + return; + } + updateGroup = 0; + } + beforec = 0; + } + else + beforec = 0; + } + + if (beforec) + { + if ((strlen(before_group_ou) == 0) || + (strlen(before_group_membership) == 0)) + { + com_err(whoami, 0, + "Unable to find the group OU for group %s", before[L_NAME]); + return; + } + + com_err(whoami, 0, "Deleting group %s", before[L_NAME]); + rc = group_delete(ldap_handle, dn_path, before[L_NAME], + before_group_membership, before_list_id); + return; + } + + if (afterc) + { + if (!updateGroup) + { + com_err(whoami, 0, "Creating group %s", after[L_NAME]); + + if (rc = process_group(ldap_handle, dn_path, list_id, after[L_NAME], + group_ou, group_membership, + security_flag, CHECK_GROUPS, + after[L_MAILLIST])) + { + if (rc != AD_NO_GROUPS_FOUND) + { + if ((rc == AD_WRONG_GROUP_DN_FOUND) || + (rc == AD_MULTIPLE_GROUPS_FOUND)) + { + rc = process_group(ldap_handle, dn_path, list_id, + after[L_NAME], + group_ou, group_membership, + security_flag, CLEANUP_GROUPS, + after[L_MAILLIST]); + } + + if (rc) + { + com_err(whoami, 0, + "Unable to create list %s", after[L_NAME]); + return; + } + } + } + } + else + com_err(whoami, 0, "Updating group %s information", after[L_NAME]); + + if (rc = moira_connect()) + { + critical_alert("AD incremental", + "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + ProcessGroup = 0; + + if (ProcessAce(ldap_handle, dn_path, after[L_NAME], "LIST", 0, + &ProcessGroup, after[L_MAILLIST])) + return; + + if (ProcessGroup) + { + if (ProcessAce(ldap_handle, dn_path, after[L_NAME], "LIST", 1, + &ProcessGroup, after[L_MAILLIST])) + return; + } + + if (make_new_group(ldap_handle, dn_path, list_id, after[L_NAME], + group_ou, group_membership, security_flag, + updateGroup, after[L_MAILLIST])) + { + moira_disconnect(); + return; + } + + if (atoi(after[L_ACTIVE])) + { + populate_group(ldap_handle, dn_path, after[L_NAME], group_ou, + group_membership, security_flag, list_id); + } + + moira_disconnect(); + } + return; +} + +#define LM_EXTRA_ACTIVE (LM_END) +#define LM_EXTRA_PUBLIC (LM_END+1) +#define LM_EXTRA_HIDDEN (LM_END+2) +#define LM_EXTRA_MAILLIST (LM_END+3) +#define LM_EXTRA_GROUP (LM_END+4) +#define LM_EXTRA_GID (LM_END+5) +#define LMN_LIST_ID (LM_END+6) +#define LM_LIST_ID (LM_END+7) +#define LM_USER_ID (LM_END+8) +#define LM_EXTRA_END (LM_END+9) + +void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, int afterc) +{ + LK_ENTRY *group_base; + int group_count; + char filter[128]; + char *attr_array[3]; + char group_name[128]; + char user_name[128]; + char user_type[128]; + char moira_list_id[32]; + char moira_user_id[32]; + char group_membership[1]; + char group_ou[256]; + char machine_ou[256]; + char member[256]; + char *args[16]; + char **ptr; + char *av[7]; + char *call_args[7]; + char *pUserOu; + char *s; + char NewMachineName[1024]; + int security_flag; + int rc; + int ProcessGroup; + char *save_argv[U_END]; + + pUserOu = NULL; + ptr = NULL; + memset(moira_list_id, '\0', sizeof(moira_list_id)); + memset(moira_user_id, '\0', sizeof(moira_user_id)); + + if (afterc) + { + if (afterc < LM_EXTRA_GID) + return; + + if (!atoi(after[LM_EXTRA_ACTIVE])) + { + com_err(whoami, 0, + "Unable to add %s to group %s : group not active", + after[2], after[0]); + return; + } + + ptr = after; + + if (!strcasecmp(ptr[LM_TYPE], "LIST")) + return; + + strcpy(user_name, after[LM_MEMBER]); + strcpy(group_name, after[LM_LIST]); + strcpy(user_type, after[LM_TYPE]); + + if (!strcasecmp(ptr[LM_TYPE], "MACHINE")) + { + if (afterc > LM_EXTRA_GROUP) + { + strcpy(moira_list_id, after[LMN_LIST_ID]); + strcpy(moira_user_id, after[LM_LIST_ID]); + } + } + else if (!strcasecmp(ptr[LM_TYPE], "USER")) + { + if (afterc > LMN_LIST_ID) + { + strcpy(moira_list_id, after[LM_LIST_ID]); + strcpy(moira_user_id, after[LM_USER_ID]); + } + } + else + { + if (afterc > LM_EXTRA_GID) + strcpy(moira_list_id, after[LMN_LIST_ID]); + } + } + else if (beforec) + { + if (beforec < LM_EXTRA_GID) + return; + if (!atoi(before[LM_EXTRA_ACTIVE])) + { + com_err(whoami, 0, + "Unable to add %s to group %s : group not active", + before[2], before[0]); + return; + } + + ptr = before; + + if (!strcasecmp(ptr[LM_TYPE], "LIST")) + return; + + strcpy(user_name, before[LM_MEMBER]); + strcpy(group_name, before[LM_LIST]); + strcpy(user_type, before[LM_TYPE]); + + if (!strcasecmp(ptr[LM_TYPE], "MACHINE")) + { + if (beforec > LM_EXTRA_GROUP) + { + strcpy(moira_list_id, before[LMN_LIST_ID]); + strcpy(moira_user_id, before[LM_LIST_ID]); + } + } + else if (!strcasecmp(ptr[LM_TYPE], "USER")) + { + if (beforec > LMN_LIST_ID) + { + strcpy(moira_list_id, before[LM_LIST_ID]); + strcpy(moira_user_id, before[LM_USER_ID]); + } + } + else + { + if (beforec > LM_EXTRA_GID) + strcpy(moira_list_id, before[LMN_LIST_ID]); + } + } + + if (ptr == NULL) + { + com_err(whoami, 0, + "Unable to process group : beforec = %d, afterc = %d", + beforec, afterc); + return; + } + + args[L_NAME] = ptr[LM_LIST]; + args[L_ACTIVE] = ptr[LM_EXTRA_ACTIVE]; + args[L_PUBLIC] = ptr[LM_EXTRA_PUBLIC]; + args[L_HIDDEN] = ptr[LM_EXTRA_HIDDEN]; + args[L_MAILLIST] = ptr[LM_EXTRA_MAILLIST]; + args[L_GROUP] = ptr[LM_EXTRA_GROUP]; + args[L_GID] = ptr[LM_EXTRA_GID]; + + security_flag = 0; + memset(group_ou, '\0', sizeof(group_ou)); + get_group_membership(group_membership, group_ou, &security_flag, args); + + if (strlen(group_ou) == 0) + { + com_err(whoami, 0, "Unable to find the group OU for group %s", + group_name); + return; + } + + if (rc = process_group(ldap_handle, dn_path, moira_list_id, group_name, + group_ou, group_membership, security_flag, + CHECK_GROUPS, args[L_MAILLIST])) + { + if (rc != AD_NO_GROUPS_FOUND) + { + if (rc = process_group(ldap_handle, dn_path, moira_list_id, + group_name, group_ou, group_membership, + security_flag, CLEANUP_GROUPS, + args[L_MAILLIST])) + { + if (rc != AD_NO_GROUPS_FOUND) + { + if (afterc) + com_err(whoami, 0, "Unable to add %s to group %s - " + "unable to process group", user_name, group_name); + else + com_err(whoami, 0, "Unable to remove %s from group %s - " + "unable to process group", user_name, group_name); + return; + } + } + } + } + + if (rc == AD_NO_GROUPS_FOUND) + { + if (rc = moira_connect()) + { + critical_alert("AD incremental", + "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + com_err(whoami, 0, "creating group %s", group_name); + ProcessGroup = 0; + + if (ProcessAce(ldap_handle, dn_path, ptr[LM_LIST], "LIST", 0, + &ProcessGroup, ptr[LM_EXTRA_MAILLIST])) + return; + + if (ProcessGroup) + { + if (ProcessAce(ldap_handle, dn_path, ptr[LM_LIST], "LIST", 1, + &ProcessGroup, ptr[LM_EXTRA_MAILLIST])) + return; + } + + if (make_new_group(ldap_handle, dn_path, moira_list_id, ptr[LM_LIST], + group_ou, group_membership, security_flag, 0, + ptr[LM_EXTRA_MAILLIST])) + { + moira_disconnect(); + return; + } + + if (atoi(ptr[LM_EXTRA_ACTIVE])) + { + populate_group(ldap_handle, dn_path, ptr[LM_LIST], group_ou, + group_membership, security_flag, moira_list_id); + } + + moira_disconnect(); + } + + rc = 0; + + if (beforec) + { + com_err(whoami, 0, "removing user %s from list %s", user_name, + group_name); + pUserOu = user_ou; + + if (!strcasecmp(ptr[LM_TYPE], "MACHINE")) + { + memset(machine_ou, '\0', sizeof(machine_ou)); + memset(NewMachineName, '\0', sizeof(NewMachineName)); + if (get_machine_ou(ldap_handle, dn_path, ptr[LM_MEMBER], + machine_ou, NewMachineName)) + return; + if (ptr[LM_MEMBER] != NULL) + free(ptr[LM_MEMBER]); + ptr[LM_MEMBER] = strdup(NewMachineName); + pUserOu = machine_ou; + } + + if (!strcasecmp(ptr[LM_TYPE], "STRING")) + { + strcpy(member, ptr[LM_MEMBER]); + + if (Exchange) + { + if((s = strchr(member, '@')) == (char *) NULL) + { + strcat(member, "@mit.edu"); + + if (ptr[LM_MEMBER] != NULL) + free(ptr[LM_MEMBER]); + ptr[LM_MEMBER] = strdup(member); + } + + if(!strncasecmp(&member[strlen(member) - 6], ".LOCAL", 6)) + { + s = strrchr(member, '.'); + *s = '\0'; + strcat(s, ".mit.edu"); + + if (ptr[LM_MEMBER] != NULL) + free(ptr[LM_MEMBER]); + ptr[LM_MEMBER] = strdup(member); + } + } + + if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], + contact_ou)) + return; + + pUserOu = contact_ou; + } + else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS")) + { + if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], + kerberos_ou)) + return; + + pUserOu = kerberos_ou; + } + + if (rc = moira_connect()) { + critical_alert("AD incremental", + "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + if (rc = populate_group(ldap_handle, dn_path, group_name, + group_ou, group_membership, + security_flag, moira_list_id)) + com_err(whoami, 0, "Unable to remove %s from group %s", user_name, + group_name); + + moira_disconnect(); + + if (!strcasecmp(ptr[LM_TYPE], "STRING")) + { + if (rc = moira_connect()) + { + critical_alert("AD incremental", + "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + if (rc = populate_group(ldap_handle, dn_path, group_name, + group_ou, group_membership, security_flag, + moira_list_id)) + com_err(whoami, 0, "Unable to remove %s from group %s", + user_name, group_name); + + moira_disconnect(); + } + return; + } + + com_err(whoami, 0, "Adding %s to list %s", user_name, group_name); + pUserOu = user_ou; + + if (!strcasecmp(ptr[LM_TYPE], "MACHINE")) + { + memset(machine_ou, '\0', sizeof(machine_ou)); + memset(NewMachineName, '\0', sizeof(NewMachineName)); + + if (get_machine_ou(ldap_handle, dn_path, ptr[LM_MEMBER], machine_ou, + NewMachineName)) + return; + + if (ptr[LM_MEMBER] != NULL) + free(ptr[LM_MEMBER]); + + ptr[LM_MEMBER] = strdup(NewMachineName); + pUserOu = machine_ou; + } + else if (!strcasecmp(ptr[LM_TYPE], "STRING")) + { + strcpy(member, ptr[LM_MEMBER]); + + if (Exchange) + { + if((s = strchr(member, '@')) == (char *) NULL) + { + strcat(member, "@mit.edu"); + + if (ptr[LM_MEMBER] != NULL) + free(ptr[LM_MEMBER]); + ptr[LM_MEMBER] = strdup(member); + } + + if(!strncasecmp(&member[strlen(member) - 6], ".LOCAL", 6)) + { + s = strrchr(member, '.'); + *s = '\0'; + strcat(s, ".mit.edu"); + + if (ptr[LM_MEMBER] != NULL) + free(ptr[LM_MEMBER]); + ptr[LM_MEMBER] = strdup(member); + } + } + + if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], + contact_ou)) + return; + + pUserOu = contact_ou; + } + else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS")) + { + if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], + kerberos_ou)) + return; + + pUserOu = kerberos_ou; + } + else if (!strcasecmp(ptr[LM_TYPE], "USER")) + { + if ((rc = check_user(ldap_handle, dn_path, ptr[LM_MEMBER], + moira_user_id)) == AD_NO_USER_FOUND) + { + if (rc = moira_connect()) + { + critical_alert("AD incremental", + "Error connection to Moira : %s", + error_message(rc)); + return; + } + + com_err(whoami, 0, "creating user %s", ptr[LM_MEMBER]); + av[0] = ptr[LM_MEMBER]; + call_args[0] = (char *)ldap_handle; + call_args[1] = dn_path; + call_args[2] = moira_user_id; + call_args[3] = NULL; + + callback_rc = 0; + + if (Exchange) + { + group_count = 0; + group_base = NULL; + + sprintf(filter, "(&(objectClass=group)(cn=%s))", ptr[LM_MEMBER]); + attr_array[0] = "cn"; + attr_array[1] = NULL; + if ((rc = linklist_build(ldap_handle, dn_path, filter, + attr_array, &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process user %s : %s", + ptr[LM_MEMBER], ldap_err2string(rc)); + return; + } + + if (group_count) + { + com_err(whoami, 0, "Object already exists with name %s", + ptr[LM_MEMBER]); + return; + } + + linklist_free(group_base); + group_count = 0; + group_base = NULL; + } + + if (rc = mr_query("get_user_account_by_login", 1, av, + save_query_info, save_argv)) + { + moira_disconnect(); + com_err(whoami, 0, "Unable to create user %s : %s", + ptr[LM_MEMBER], error_message(rc)); + return; + } + + if (rc = user_create(U_END, save_argv, call_args)) + { + moira_disconnect(); + com_err(whoami, 0, "Unable to create user %s", ptr[LM_MEMBER]); + return; + } + + if (callback_rc) + { + moira_disconnect(); + com_err(whoami, 0, "Unable to create user %s", ptr[LM_MEMBER]); + return; + } + } + else + { + if (rc != 0) + return; + } + pUserOu = user_ou; + } + + if (rc = moira_connect()) { + critical_alert("AD incremental", + "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + if (rc = populate_group(ldap_handle, dn_path, group_name, + group_ou, group_membership, security_flag, + moira_list_id)) + com_err(whoami, 0, "Unable to add %s to group %s", user_name, + group_name); + + moira_disconnect(); + + if (!strcasecmp(ptr[LM_TYPE], "STRING")) + { + if (rc = moira_connect()) + { + critical_alert("AD incremental", + "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + if (rc = populate_group(ldap_handle, dn_path, group_name, + group_ou, group_membership, security_flag, + moira_list_id)) + com_err(whoami, 0, "Unable to add %s to group %s", + user_name, group_name); + + moira_disconnect(); + } + + return; +} + + +#define U_USER_ID 10 +#define U_HOMEDIR 11 +#define U_PROFILEDIR 12 + +void do_user(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, + char **before, int beforec, char **after, + int afterc) +{ + LK_ENTRY *group_base; + int group_count; + char filter[128]; + char *attr_array[3]; + int rc; + char *av[7]; + char after_user_id[32]; + char before_user_id[32]; + char *call_args[7]; + char *save_argv[U_END]; + + if ((beforec == 0) && (afterc == 0)) + return; + + memset(after_user_id, '\0', sizeof(after_user_id)); + memset(before_user_id, '\0', sizeof(before_user_id)); + + if (beforec > U_USER_ID) + strcpy(before_user_id, before[U_USER_ID]); + + if (afterc > U_USER_ID) + strcpy(after_user_id, after[U_USER_ID]); + + if ((beforec == 0) && (afterc == 0)) /*this case should never happen */ + return; + + if ((beforec == 0) && (afterc != 0)) + { + /*this case only happens when the account*/ + /*account is first created but not usable*/ + + com_err(whoami, 0, "Unable to process user %s because the user account " + "is not yet usable", after[U_NAME]); + return; + } + + /*this case only happens when the account is expunged */ + + if ((beforec != 0) && (afterc == 0)) + { + if (atoi(before[U_STATE]) == 0) + { + com_err(whoami, 0, "expunging user %s from AD", before[U_NAME]); + user_delete(ldap_handle, dn_path, before[U_NAME], before_user_id); + } + else + { + com_err(whoami, 0, "Unable to process because user %s has been " + "previously expungeded", before[U_NAME]); + } + return; + } + + /*process anything that gets here*/ + + if ((rc = check_user(ldap_handle, dn_path, before[U_NAME], + before_user_id)) == AD_NO_USER_FOUND) + { + if (!check_string(after[U_NAME])) + return; + + if (rc = moira_connect()) + { + critical_alert("AD incremental", + "Error connection to Moira : %s", + error_message(rc)); + return; + } + + com_err(whoami, 0, "creating user %s", after[U_NAME]); + + av[0] = after[U_NAME]; + call_args[0] = (char *)ldap_handle; + call_args[1] = dn_path; + call_args[2] = after_user_id; + call_args[3] = NULL; + callback_rc = 0; + + if (Exchange) + { + group_count = 0; + group_base = NULL; + + sprintf(filter, "(&(objectClass=group)(cn=%s))", after[U_NAME]); + attr_array[0] = "cn"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process user %s : %s", + after[U_NAME], ldap_err2string(rc)); + return; + } + + if (group_count >= 1) + { + com_err(whoami, 0, "Object already exists with name %s", + after[U_NAME]); + return; + } + + linklist_free(group_base); + group_count = 0; + group_base = NULL; + } + + if (rc = mr_query("get_user_account_by_login", 1, av, + save_query_info, save_argv)) + { + moira_disconnect(); + com_err(whoami, 0, "Unable to create user %s : %s", + after[U_NAME], error_message(rc)); + return; + } + + if (rc = user_create(U_END, save_argv, call_args)) + { + com_err(whoami, 0, "Unable to create user %s : %s", + after[U_NAME], error_message(rc)); + return; + } + + if (callback_rc) + { + moira_disconnect(); + com_err(whoami, 0, "Unable to create user %s", after[U_NAME]); + return; + } + + return; + } + else + { + if (rc != 0) + return; + } + + if (strcmp(before[U_NAME], after[U_NAME])) + { + if ((check_string(before[U_NAME])) && (check_string(after[U_NAME]))) + { + com_err(whoami, 0, "changing user %s to %s", + before[U_NAME], after[U_NAME]); + + if ((rc = user_rename(ldap_handle, dn_path, before[U_NAME], + after[U_NAME])) != LDAP_SUCCESS) + { + return; + } + } + } + + com_err(whoami, 0, "updating user %s information", after[U_NAME]); + rc = user_update(ldap_handle, dn_path, after[U_NAME], + after[U_UID], after[U_MITID], + after_user_id, atoi(after[U_STATE]), + after[U_HOMEDIR], after[U_PROFILEDIR], + after[U_FIRST], after[U_MIDDLE], after[U_LAST], + after[U_SHELL], after[U_CLASS]); + + return; +} + +int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, + char *oldValue, char *newValue, + char ***modvalues, int type) +{ + LK_ENTRY *linklist_ptr; + int i; + char *cPtr; + + if (((*modvalues) = calloc(1, + (modvalue_count + 1) * sizeof(char *))) == NULL) + { + return(1); + } + + for (i = 0; i < (modvalue_count + 1); i++) + (*modvalues)[i] = NULL; + + if (modvalue_count != 0) + { + linklist_ptr = linklist_base; + for (i = 0; i < modvalue_count; i++) + { + if ((oldValue != NULL) && (newValue != NULL)) + { + if ((cPtr = (char *)strstr(linklist_ptr->value, oldValue)) + != (char *)NULL) + { + if (type == REPLACE) + { + if (((*modvalues)[i] = calloc(1, strlen(newValue) + 1)) + == NULL) + return(1); + memset((*modvalues)[i], '\0', strlen(newValue) + 1); + strcpy((*modvalues)[i], newValue); + } + else + { + if (((*modvalues)[i] = calloc(1, + (int)(cPtr - linklist_ptr->value) + + (linklist_ptr->length - + strlen(oldValue)) + + strlen(newValue) + 1)) == NULL) + return(1); + memset((*modvalues)[i], '\0', + (int)(cPtr - linklist_ptr->value) + + (linklist_ptr->length - strlen(oldValue)) + + strlen(newValue) + 1); + memcpy((*modvalues)[i], linklist_ptr->value, + (int)(cPtr - linklist_ptr->value)); + strcat((*modvalues)[i], newValue); + strcat((*modvalues)[i], + &linklist_ptr->value[(int)(cPtr - + linklist_ptr->value) + strlen(oldValue)]); + } + } + else + { + (*modvalues)[i] = calloc(1, linklist_ptr->length + 1); + memset((*modvalues)[i], '\0', linklist_ptr->length + 1); + memcpy((*modvalues)[i], linklist_ptr->value, + linklist_ptr->length); + } + } + else + { + (*modvalues)[i] = calloc(1, linklist_ptr->length + 1); + memset((*modvalues)[i], '\0', linklist_ptr->length + 1); + memcpy((*modvalues)[i], linklist_ptr->value, + linklist_ptr->length); + } + linklist_ptr = linklist_ptr->next; + } + (*modvalues)[i] = NULL; + } + return(0); +} + + +int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, + char **attr_array, LK_ENTRY **linklist_base, + int *linklist_count, unsigned long ScopeType) +{ + ULONG rc; + LDAPMessage *ldap_entry; + + rc = 0; + ldap_entry = NULL; + (*linklist_base) = NULL; + (*linklist_count) = 0; + + if ((rc = ldap_search_s(ldap_handle, dn_path, ScopeType, + search_exp, attr_array, 0, + &ldap_entry)) != LDAP_SUCCESS) + { + if (rc != LDAP_SIZELIMIT_EXCEEDED) + return(0); + } + + rc = retrieve_entries(ldap_handle, ldap_entry, linklist_base, + linklist_count); + + ldap_msgfree(ldap_entry); + return(rc); +} + +int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, + LK_ENTRY **linklist_base, int *linklist_count) +{ + char distinguished_name[1024]; + LK_ENTRY *linklist_ptr; + int rc; + + if ((ldap_entry = ldap_first_entry(ldap_handle, ldap_entry)) == NULL) + return(0); + + memset(distinguished_name, '\0', sizeof(distinguished_name)); + get_distinguished_name(ldap_handle, ldap_entry, distinguished_name); + + if ((rc = retrieve_attributes(ldap_handle, ldap_entry, distinguished_name, + linklist_base)) != 0) + return(rc); + + while ((ldap_entry = ldap_next_entry(ldap_handle, ldap_entry)) != NULL) + { + memset(distinguished_name, '\0', sizeof(distinguished_name)); + get_distinguished_name(ldap_handle, ldap_entry, distinguished_name); + + if ((rc = retrieve_attributes(ldap_handle, ldap_entry, + distinguished_name, linklist_base)) != 0) + return(rc); + } + + linklist_ptr = (*linklist_base); + (*linklist_count) = 0; + + while (linklist_ptr != NULL) + { + ++(*linklist_count); + linklist_ptr = linklist_ptr->next; + } + + return(0); +} + +int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, + char *distinguished_name, LK_ENTRY **linklist_current) +{ + char *Attribute; + BerElement *ptr; + + ptr = NULL; + + if ((Attribute = ldap_first_attribute(ldap_handle, ldap_entry, + &ptr)) != NULL) + { + retrieve_values(ldap_handle, ldap_entry, Attribute, distinguished_name, + linklist_current); + ldap_memfree(Attribute); + while ((Attribute = ldap_next_attribute(ldap_handle, ldap_entry, + ptr)) != NULL) + { + retrieve_values(ldap_handle, ldap_entry, Attribute, + distinguished_name, linklist_current); + ldap_memfree(Attribute); + } + } + + ldap_ber_free(ptr, 0); + + return(0); +} + +int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry, + char *Attribute, char *distinguished_name, + LK_ENTRY **linklist_current) +{ + char **str_value; + char temp[256]; + void **Ptr; + int use_bervalue; + LK_ENTRY *linklist_previous; + LDAP_BERVAL **ber_value; + DWORD ber_length; + +#ifdef LDAP_DEBUG + SID *sid; + GUID *guid; + int i; + int intValue; + DWORD *subauth; + SID_IDENTIFIER_AUTHORITY *sid_auth; + unsigned char *subauth_count; +#endif /*LDAP_BEGUG*/ + + use_bervalue = 0; + memset(temp, '\0', sizeof(temp)); + + if ((!strcmp(Attribute, "objectSid")) || + (!strcmp(Attribute, "objectGUID"))) + use_bervalue = 1; + + if (use_bervalue) + { + ber_value = ldap_get_values_len(ldap_handle, ldap_entry, Attribute); + Ptr = (void **)ber_value; + str_value = NULL; + } + else + { + str_value = ldap_get_values(ldap_handle, ldap_entry, Attribute); + Ptr = (void **)str_value; + ber_value = NULL; + } + + if (Ptr != NULL) + { + for (; *Ptr; Ptr++) + { + if ((linklist_previous = calloc(1, sizeof(LK_ENTRY))) == NULL) + return(1); + + memset(linklist_previous, '\0', sizeof(LK_ENTRY)); + linklist_previous->next = (*linklist_current); + (*linklist_current) = linklist_previous; + + if (((*linklist_current)->attribute = calloc(1, + strlen(Attribute) + 1)) == NULL) + return(1); + + memset((*linklist_current)->attribute, '\0', strlen(Attribute) + 1); + strcpy((*linklist_current)->attribute, Attribute); + + if (use_bervalue) + { + ber_length = (*(LDAP_BERVAL **)Ptr)->bv_len; + + if (((*linklist_current)->value = calloc(1, ber_length)) == NULL) + return(1); + + memset((*linklist_current)->value, '\0', ber_length); + memcpy((*linklist_current)->value, + (*(LDAP_BERVAL **)Ptr)->bv_val, ber_length); + (*linklist_current)->length = ber_length; + } + else + { + if (((*linklist_current)->value = calloc(1, + strlen(*Ptr) + 1)) == NULL) + return(1); + + memset((*linklist_current)->value, '\0', strlen(*Ptr) + 1); + (*linklist_current)->length = strlen(*Ptr); + strcpy((*linklist_current)->value, *Ptr); + } + + (*linklist_current)->ber_value = use_bervalue; + + if (((*linklist_current)->dn = calloc(1, + strlen(distinguished_name) + 1)) == NULL) + return(1); + + memset((*linklist_current)->dn, '\0', + strlen(distinguished_name) + 1); + strcpy((*linklist_current)->dn, distinguished_name); + +#ifdef LDAP_DEBUG + if (!strcmp(Attribute, "objectGUID")) + { + guid = (GUID *)((*linklist_current)->value); + sprintf(temp, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], + guid->Data4[3], guid->Data4[4], guid->Data4[5], + guid->Data4[6], guid->Data4[7]); + print_to_screen(" %20s : {%s}\n", Attribute, temp); + } + else if (!strcmp(Attribute, "objectSid")) + { + sid = (SID *)((*(LDAP_BERVAL **)Ptr)->bv_val); + +#ifdef _WIN32 + print_to_screen(" Revision = %d\n", sid->Revision); + print_to_screen(" SID Identifier Authority:\n"); + sid_auth = &sid->IdentifierAuthority; + if (sid_auth->Value[0]) + print_to_screen(" SECURITY_NULL_SID_AUTHORITY\n"); + else if (sid_auth->Value[1]) + print_to_screen(" SECURITY_WORLD_SID_AUTHORITY\n"); + else if (sid_auth->Value[2]) + print_to_screen(" SECURITY_LOCAL_SID_AUTHORITY\n"); + else if (sid_auth->Value[3]) + print_to_screen(" SECURITY_CREATOR_SID_AUTHORITY\n"); + else if (sid_auth->Value[5]) + print_to_screen(" SECURITY_NT_AUTHORITY\n"); + else + print_to_screen(" UNKNOWN SID AUTHORITY\n"); + subauth_count = GetSidSubAuthorityCount(sid); + print_to_screen(" SidSubAuthorityCount = %d\n", + *subauth_count); + print_to_screen(" SidSubAuthority:\n"); + for (i = 0; i < *subauth_count; i++) + { + if ((subauth = GetSidSubAuthority(sid, i)) != NULL) + print_to_screen(" %u\n", *subauth); + } +#endif + } + else if ((!memcmp(Attribute, "userAccountControl", + strlen("userAccountControl"))) || + (!memcmp(Attribute, "sAMAccountType", + strlen("sAmAccountType")))) + { + intValue = atoi(*Ptr); + print_to_screen(" %20s : %ld\n",Attribute, intValue); + + if (!memcmp(Attribute, "userAccountControl", + strlen("userAccountControl"))) + { + if (intValue & UF_ACCOUNTDISABLE) + print_to_screen(" %20s : %s\n", + "", "Account disabled"); + else + print_to_screen(" %20s : %s\n", + "", "Account active"); + if (intValue & UF_HOMEDIR_REQUIRED) + print_to_screen(" %20s : %s\n", + "", "Home directory required"); + if (intValue & UF_LOCKOUT) + print_to_screen(" %20s : %s\n", + "", "Account locked out"); + if (intValue & UF_PASSWD_NOTREQD) + print_to_screen(" %20s : %s\n", + "", "No password required"); + if (intValue & UF_PASSWD_CANT_CHANGE) + print_to_screen(" %20s : %s\n", + "", "Cannot change password"); + if (intValue & UF_TEMP_DUPLICATE_ACCOUNT) + print_to_screen(" %20s : %s\n", + "", "Temp duplicate account"); + if (intValue & UF_NORMAL_ACCOUNT) + print_to_screen(" %20s : %s\n", + "", "Normal account"); + if (intValue & UF_INTERDOMAIN_TRUST_ACCOUNT) + print_to_screen(" %20s : %s\n", + "", "Interdomain trust account"); + if (intValue & UF_WORKSTATION_TRUST_ACCOUNT) + print_to_screen(" %20s : %s\n", + "", "Workstation trust account"); + if (intValue & UF_SERVER_TRUST_ACCOUNT) + print_to_screen(" %20s : %s\n", + "", "Server trust account"); + } + } + else + { + print_to_screen(" %20s : %s\n",Attribute, *Ptr); + } +#endif /*LDAP_DEBUG*/ + } + + if (str_value != NULL) + ldap_value_free(str_value); + + if (ber_value != NULL) + ldap_value_free_len(ber_value); + } + + (*linklist_current) = linklist_previous; + + return(0); +} + +int moira_connect(void) +{ + long rc; + char HostName[64]; + + if (!mr_connections++) + { + +#ifdef _WIN32 + memset(HostName, '\0', sizeof(HostName)); + strcpy(HostName, "ttsp"); + rc = mr_connect_cl(HostName, "ldap.incr", QUERY_VERSION, 1); +#else + struct utsname uts; + uname(&uts); + rc = mr_connect_cl(uts.nodename, "ldap.incr", QUERY_VERSION, 1); +#endif /*WIN32*/ + + return rc; + } + + return 0; +} + +int check_winad(void) +{ + int i; + + for (i = 0; file_exists(STOP_FILE); i++) + { + if (i > 30) + { + critical_alert("AD incremental", + "WINAD incremental failed (%s exists): %s", + STOP_FILE, tbl_buf); + return(1); + } + + sleep(60); + } + + return(0); +} + +int moira_disconnect(void) +{ + + if (!--mr_connections) + { + mr_disconnect(); + } + + return 0; +} + +void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry, + char *distinguished_name) +{ + char *CName; + + CName = ldap_get_dn(ldap_handle, ldap_entry); + + if (CName == NULL) + return; + + strcpy(distinguished_name, CName); + ldap_memfree(CName); +} + +int linklist_create_entry(char *attribute, char *value, + LK_ENTRY **linklist_entry) +{ + (*linklist_entry) = calloc(1, sizeof(LK_ENTRY)); + + if (!(*linklist_entry)) + { + return(1); + } + + memset((*linklist_entry), '\0', sizeof(LK_ENTRY)); + (*linklist_entry)->attribute = calloc(1, strlen(attribute) + 1); + memset((*linklist_entry)->attribute, '\0', strlen(attribute) + 1); + strcpy((*linklist_entry)->attribute, attribute); + (*linklist_entry)->value = calloc(1, strlen(value) + 1); + memset((*linklist_entry)->value, '\0', strlen(value) + 1); + strcpy((*linklist_entry)->value, value); + (*linklist_entry)->length = strlen(value); + (*linklist_entry)->next = NULL; + + return(0); +} + +void print_to_screen(const char *fmt, ...) +{ + va_list pvar; + + va_start(pvar, fmt); + vfprintf(stderr, fmt, pvar); + fflush(stderr); + va_end(pvar); +} + +int get_group_membership(char *group_membership, char *group_ou, + int *security_flag, char **av) +{ + int maillist_flag; + int group_flag; + + maillist_flag = atoi(av[L_MAILLIST]); + group_flag = atoi(av[L_GROUP]); + + if (security_flag != NULL) + (*security_flag) = 0; + + if ((maillist_flag) && (group_flag)) + { + if (group_membership != NULL) + group_membership[0] = 'B'; + + if (security_flag != NULL) + (*security_flag) = 1; + + if (group_ou != NULL) + strcpy(group_ou, group_ou_both); + } + else if ((!maillist_flag) && (group_flag)) + { + if (group_membership != NULL) + group_membership[0] = 'S'; + + if (security_flag != NULL) + (*security_flag) = 1; + + if (group_ou != NULL) + strcpy(group_ou, group_ou_security); + } + else if ((maillist_flag) && (!group_flag)) + { + if (group_membership != NULL) + group_membership[0] = 'D'; + + if (group_ou != NULL) + strcpy(group_ou, group_ou_distribution); + } + else + { + if (group_membership != NULL) + group_membership[0] = 'N'; + + if (group_ou != NULL) + strcpy(group_ou, group_ou_neither); + } + + return(0); +} + +int group_rename(LDAP *ldap_handle, char *dn_path, + char *before_group_name, char *before_group_membership, + char *before_group_ou, int before_security_flag, + char *before_desc, char *after_group_name, + char *after_group_membership, char *after_group_ou, + int after_security_flag, char *after_desc, + char *MoiraId, char *filter, char *maillist) +{ + LDAPMod *mods[20]; + char old_dn[512]; + char new_dn[512]; + char new_dn_path[512]; + char sam_name[256]; + char mail[256]; + char mail_nickname[256]; + char proxy_address[256]; + char address_book[256]; + char *attr_array[3]; + char *mitMoiraId_v[] = {NULL, NULL}; + char *name_v[] = {NULL, NULL}; + char *samAccountName_v[] = {NULL, NULL}; + char *groupTypeControl_v[] = {NULL, NULL}; + char *mail_v[] = {NULL, NULL}; + char *proxy_address_v[] = {NULL, NULL}; + char *mail_nickname_v[] = {NULL, NULL}; + char *report_to_originator_v[] = {NULL, NULL}; + char *address_book_v[] = {NULL, NULL}; + char *legacy_exchange_dn_v[] = {NULL, NULL}; + u_int groupTypeControl; + char groupTypeControlStr[80]; + char contact_mail[256]; + int n; + int i; + int rc; + LK_ENTRY *group_base; + int group_count; + int MailDisabled = 0; + + if(UseGroupUniversal) + groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP; + else + groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP; + + if (!check_string(before_group_name)) + { + com_err(whoami, 0, + "Unable to process invalid LDAP list name %s", + before_group_name); + return(AD_INVALID_NAME); + } + + if (!check_string(after_group_name)) + { + com_err(whoami, 0, + "Unable to process invalid LDAP list name %s", after_group_name); + return(AD_INVALID_NAME); + } + + if (Exchange) + { + if(atoi(maillist)) + { + group_count = 0; + group_base = NULL; + + sprintf(filter, "(&(objectClass=user)(cn=%s))", after_group_name); + attr_array[0] = "cn"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process group %s : %s", + after_group_name, ldap_err2string(rc)); + return(rc); + } + + if (group_count) + { + com_err(whoami, 0, "Object already exists with name %s", + after_group_name); + MailDisabled++; + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + } + + group_count = 0; + group_base = NULL; + + if (rc = ad_get_group(ldap_handle, dn_path, before_group_name, + before_group_membership, + MoiraId, "samAccountName", &group_base, + &group_count, filter)) + return(rc); + + if (group_count == 0) + { + return(AD_NO_GROUPS_FOUND); + } + + if (group_count != 1) + { + com_err(whoami, 0, "Unable to process multiple groups with " + "MoiraId = %s exist in the AD", MoiraId); + return(AD_MULTIPLE_GROUPS_FOUND); + } + + strcpy(old_dn, group_base->dn); + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + attr_array[0] = "sAMAccountName"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to get list %s dn : %s", + after_group_name, ldap_err2string(rc)); + return(rc); + } + + if (group_count != 1) + { + com_err(whoami, 0, + "Unable to get sAMAccountName for group %s", + before_group_name); + return(AD_LDAP_FAILURE); + } + + strcpy(sam_name, group_base->value); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + sprintf(new_dn_path, "%s,%s", after_group_ou, dn_path); + sprintf(new_dn, "cn=%s", after_group_name); + sprintf(mail, "%s@%s", after_group_name, lowercase(ldap_domain)); + sprintf(contact_mail, "%s@mit.edu", after_group_name); + sprintf(proxy_address, "SMTP:%s@%s", after_group_name, + lowercase(ldap_domain)); + sprintf(mail_nickname, "%s", after_group_name); + + com_err(whoami, 0, "Old %s New %s,%s", old_dn, new_dn, new_dn_path); + + if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, new_dn_path, + TRUE, NULL, NULL)) != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to rename list from %s to %s : %s", + before_group_name, after_group_name, ldap_err2string(rc)); + return(rc); + } + + name_v[0] = after_group_name; + + if (!strncmp(&sam_name[strlen(sam_name) - strlen(group_suffix)], + group_suffix, strlen(group_suffix))) + { + sprintf(sam_name, "%s%s", after_group_name, group_suffix); + } + else + { + com_err(whoami, 0, + "Unable to rename list from %s to %s : sAMAccountName not found", + before_group_name, after_group_name); + return(rc); + } + + samAccountName_v[0] = sam_name; + + if (after_security_flag) + groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED; + + sprintf(groupTypeControlStr, "%ld", groupTypeControl); + groupTypeControl_v[0] = groupTypeControlStr; + mitMoiraId_v[0] = MoiraId; + + sprintf(new_dn, "cn=%s,%s,%s", after_group_name, after_group_ou, dn_path); + rc = attribute_update(ldap_handle, new_dn, after_desc, "description", + after_group_name); + n = 0; + ADD_ATTR("samAccountName", samAccountName_v, LDAP_MOD_REPLACE); + ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE); + ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE); + ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_REPLACE); + + if (Exchange) + { + if(atoi(maillist) && !MailDisabled && email_isvalid(mail)) + { + mail_nickname_v[0] = mail_nickname; + proxy_address_v[0] = proxy_address; + mail_v[0] = mail; + report_to_originator_v[0] = "TRUE"; + + ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); + ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); + ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE); + ADD_ATTR("reportToOriginator", report_to_originator_v, + LDAP_MOD_REPLACE); + } + else + { + mail_nickname_v[0] = NULL; + proxy_address_v[0] = NULL; + mail_v[0] = NULL; + legacy_exchange_dn_v[0] = NULL; + address_book_v[0] = NULL; + report_to_originator_v[0] = NULL; + + ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); + ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); + ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE); + ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, LDAP_MOD_REPLACE); + ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE); + ADD_ATTR("reportToOriginator", report_to_originator_v, + LDAP_MOD_REPLACE); + } + } + else + { + if(atoi(maillist) && email_isvalid(contact_mail)) + { + mail_v[0] = contact_mail; + ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); + } + } + + mods[n] = NULL; + + if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS) + { + com_err(whoami, 0, + "Unable to modify list data for %s after renaming: %s", + after_group_name, ldap_err2string(rc)); + } + + for (i = 0; i < n; i++) + free(mods[i]); + + return(rc); +} + +int group_create(int ac, char **av, void *ptr) +{ + LDAPMod *mods[20]; + char new_dn[256]; + char group_ou[256]; + char new_group_name[256]; + char sam_group_name[256]; + char cn_group_name[256]; + char mail[256]; + char contact_mail[256]; + char mail_nickname[256]; + char proxy_address[256]; + char address_book[256]; + char *cn_v[] = {NULL, NULL}; + char *objectClass_v[] = {"top", "group", NULL}; + char *objectClass_ldap_v[] = {"top", "microsoftComTop", "securityPrincipal", + "group", "mailRecipient", NULL}; + char info[256]; + char *samAccountName_v[] = {NULL, NULL}; + char *altSecurityIdentities_v[] = {NULL, NULL}; + char *member_v[] = {NULL, NULL}; + char *name_v[] = {NULL, NULL}; + char *desc_v[] = {NULL, NULL}; + char *info_v[] = {NULL, NULL}; + char *mitMoiraId_v[] = {NULL, NULL}; + char *mitMoiraPublic_v[] = {NULL, NULL}; + char *mitMoiraHidden_v[] = {NULL, NULL}; + char *groupTypeControl_v[] = {NULL, NULL}; + char *mail_v[] = {NULL, NULL}; + char *proxy_address_v[] = {NULL, NULL}; + char *mail_nickname_v[] = {NULL, NULL}; + char *report_to_originator_v[] = {NULL, NULL}; + char *address_book_v[] = {NULL, NULL}; + char *legacy_exchange_dn_v[] = {NULL, NULL}; + char *gidNumber_v[] = {NULL, NULL}; + char groupTypeControlStr[80]; + char group_membership[1]; + int i; + int security_flag; + u_int groupTypeControl; + int n; + int rc; + int updateGroup; + int MailDisabled = 0; + char **call_args; + LK_ENTRY *group_base; + int group_count; + char filter[1024]; + char *attr_array[3]; + + call_args = ptr; + + if(UseGroupUniversal) + groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP; + else + groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP; + + if (!check_string(av[L_NAME])) + { + com_err(whoami, 0, "Unable to process invalid LDAP list name %s", + av[L_NAME]); + return(AD_INVALID_NAME); + } + + updateGroup = (int)call_args[4]; + memset(group_ou, 0, sizeof(group_ou)); + memset(group_membership, 0, sizeof(group_membership)); + security_flag = 0; + + get_group_membership(group_membership, group_ou, &security_flag, av); + + strcpy(new_group_name, av[L_NAME]); + sprintf(new_dn, "cn=%s,%s,%s", new_group_name, group_ou, call_args[1]); + sprintf(contact_mail, "%s@mit.edu", av[L_NAME]); + sprintf(mail, "%s@%s", av[L_NAME], lowercase(ldap_domain)); + sprintf(mail_nickname, "%s", av[L_NAME]); + + if (security_flag) + groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED; + + sprintf(sam_group_name, "%s%s", av[L_NAME], group_suffix); + + if (!updateGroup) + { + sprintf(groupTypeControlStr, "%ld", groupTypeControl); + groupTypeControl_v[0] = groupTypeControlStr; + + strcpy(cn_group_name, av[L_NAME]); + + samAccountName_v[0] = sam_group_name; + name_v[0] = new_group_name; + cn_v[0] = new_group_name; + + n = 0; + ADD_ATTR("cn", cn_v, LDAP_MOD_ADD); + + if(ActiveDirectory) + { + ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD); + } + else + { + mitMoiraPublic_v[0] = av[L_PUBLIC]; + mitMoiraHidden_v[0] = av[L_HIDDEN]; + ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD); + ADD_ATTR("mitMoiraPublic", mitMoiraPublic_v, LDAP_MOD_ADD); + ADD_ATTR("mitMoiraHidden", mitMoiraHidden_v, LDAP_MOD_ADD); + + if(atoi(av[L_GROUP])) + { + gidNumber_v[0] = av[L_GID]; + ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_ADD); + } + } + + ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD); + ADD_ATTR("displayName", name_v, LDAP_MOD_ADD); + ADD_ATTR("name", name_v, LDAP_MOD_ADD); + + if (Exchange) + { + if(atoi(av[L_MAILLIST])) + { + group_count = 0; + group_base = NULL; + + sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]); + attr_array[0] = "cn"; + attr_array[1] = NULL; + + if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], + filter, attr_array, &group_base, + &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process group %s : %s", + av[L_NAME], ldap_err2string(rc)); + return(rc); + } + + if (group_count) + { + com_err(whoami, 0, "Object already exists with name %s", + av[L_NAME]); + MailDisabled++; + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + + if(atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) + { + mail_nickname_v[0] = mail_nickname; + report_to_originator_v[0] = "TRUE"; + + ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD); + ADD_ATTR("reportToOriginator", report_to_originator_v, + LDAP_MOD_ADD); + } + } + else + { + if(atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) + { + mail_v[0] = contact_mail; + ADD_ATTR("mail", mail_v, LDAP_MOD_ADD); + } + } + + if (strlen(av[L_DESC]) != 0) + { + desc_v[0] = av[L_DESC]; + ADD_ATTR("description", desc_v, LDAP_MOD_ADD); + } + + ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_ADD); + + if (strlen(av[L_ACE_NAME]) != 0) + { + sprintf(info, "The Administrator of this list is: %s", + av[L_ACE_NAME]); + info_v[0] = info; + ADD_ATTR("info", info_v, LDAP_MOD_ADD); + } + + if (strlen(call_args[5]) != 0) + { + mitMoiraId_v[0] = call_args[5]; + ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD); + } + + mods[n] = NULL; + + rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL); + + for (i = 0; i < n; i++) + free(mods[i]); + + if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS)) + { + com_err(whoami, 0, "Unable to create list %s in AD : %s", + av[L_NAME], ldap_err2string(rc)); + callback_rc = rc; + return(rc); + } + } + + if ((rc == LDAP_ALREADY_EXISTS) || (updateGroup)) + { + rc = attribute_update((LDAP *)call_args[0], new_dn, av[L_DESC], + "description", av[L_NAME]); + sprintf(info, "The Administrator of this list is: %s", av[L_ACE_NAME]); + + rc = attribute_update((LDAP *)call_args[0], new_dn, info, "info", + av[L_NAME]); + + n = 0; + + if (strlen(call_args[5]) != 0) + { + mitMoiraId_v[0] = call_args[5]; + ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE); + } + + if (!(atoi(av[L_ACTIVE]))) + { + member_v[0] = NULL; + ADD_ATTR("member", member_v, LDAP_MOD_REPLACE); + } + + if (!ActiveDirectory) + { + mitMoiraPublic_v[0] = av[L_PUBLIC]; + mitMoiraHidden_v[0] = av[L_HIDDEN]; + ADD_ATTR("mitMoiraPublic", mitMoiraPublic_v, LDAP_MOD_REPLACE); + ADD_ATTR("mitMoiraHidden", mitMoiraHidden_v, LDAP_MOD_REPLACE); + + if(atoi(av[L_GROUP])) + { + gidNumber_v[0] = av[L_GID]; + ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_REPLACE); + } + else + { + ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_REPLACE); + } + } + + if (Exchange) + { + if(atoi(av[L_MAILLIST])) + { + group_count = 0; + group_base = NULL; + + sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]); + attr_array[0] = "cn"; + attr_array[1] = NULL; + + if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], + filter, attr_array, &group_base, + &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process group %s : %s", + av[L_NAME], ldap_err2string(rc)); + return(rc); + } + + if (group_count) + { + com_err(whoami, 0, "Object already exists with name %s", + av[L_NAME]); + MailDisabled++; + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + + if (atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) + { + mail_nickname_v[0] = mail_nickname; + report_to_originator_v[0] = "TRUE"; + + ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); + ADD_ATTR("reportToOriginator", report_to_originator_v, + LDAP_MOD_REPLACE); + } + else + { + mail_v[0] = NULL; + mail_nickname_v[0] = NULL; + proxy_address_v[0] = NULL; + legacy_exchange_dn_v[0] = NULL; + address_book_v[0] = NULL; + report_to_originator_v[0] = NULL; + + ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); + ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE); + ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); + ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, + LDAP_MOD_REPLACE); + ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE); + ADD_ATTR("reportToOriginator", report_to_originator_v, + LDAP_MOD_REPLACE); + } + } + else + { + if (atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) + { + mail_v[0] = contact_mail; + ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); + } + else + { + mail_v[0] = NULL; + ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); + } + } + + mods[n] = NULL; + rc = LDAP_SUCCESS; + + if (n != 0) + { + rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods); + + for (i = 0; i < n; i++) + free(mods[i]); + + if (rc != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to update list %s in AD : %s", + av[L_NAME], ldap_err2string(rc)); + callback_rc = rc; + return(rc); + } + } + } + + ProcessGroupSecurity((LDAP *)call_args[0], call_args[1], av[L_NAME], + atoi(av[L_HIDDEN]), av[L_ACE_TYPE], av[L_ACE_NAME]); + + return(LDAP_SUCCESS); +} + +int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, + char *TargetGroupName, int HiddenGroup, + char *AceType, char *AceName) +{ + char filter_exp[1024]; + char *attr_array[5]; + char search_path[512]; + char root_ou[128]; + char TemplateDn[512]; + char TemplateSamName[128]; + char TargetDn[512]; + char TargetSamName[128]; + char AceSamAccountName[128]; + char AceDn[256]; + unsigned char AceSid[128]; + unsigned char UserTemplateSid[128]; + char acBERBuf[N_SD_BER_BYTES]; + char GroupSecurityTemplate[256]; + char hide_addres_lists[256]; + char address_book[256]; + char *hide_address_lists_v[] = {NULL, NULL}; + char *address_book_v[] = {NULL, NULL}; + char *owner_v[] = {NULL, NULL}; + int AceSidCount; + int UserTemplateSidCount; + int group_count; + int n; + int i; + int rc; + int nVal; + ULONG dwInfo; + int array_count = 0; + LDAPMod *mods[20]; + LK_ENTRY *group_base; + LDAP_BERVAL **ppsValues; + LDAPControl sControl = {"1.2.840.113556.1.4.801", + { N_SD_BER_BYTES, acBERBuf }, + TRUE + }; + LDAPControl *apsServerControls[] = {&sControl, NULL}; + LDAPMessage *psMsg; + + dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION; + BEREncodeSecurityBits(dwInfo, acBERBuf); + + sprintf(search_path, "%s,%s", group_ou_root, dn_path); + sprintf(filter_exp, "(sAMAccountName=%s%s)", TargetGroupName, group_suffix); + attr_array[0] = "sAMAccountName"; + attr_array[1] = NULL; + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE) != 0)) + return(1); + + if (group_count != 1) + { + linklist_free(group_base); + return(1); + } + + strcpy(TargetDn, group_base->dn); + strcpy(TargetSamName, group_base->value); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + UserTemplateSidCount = 0; + memset(UserTemplateSid, '\0', sizeof(UserTemplateSid)); + memset(AceSamAccountName, '\0', sizeof(AceSamAccountName)); + memset(AceSid, '\0', sizeof(AceSid)); + AceSidCount = 0; + group_base = NULL; + group_count = 0; + + if (strlen(AceName) != 0) + { + if (!strcmp(AceType, "LIST")) + { + sprintf(AceSamAccountName, "%s%s", AceName, group_suffix); + strcpy(root_ou, group_ou_root); + } + else if (!strcmp(AceType, "USER")) + { + sprintf(AceSamAccountName, "%s", AceName); + strcpy(root_ou, user_ou); + } + + if (ActiveDirectory) + { + if (strlen(AceSamAccountName) != 0) + { + sprintf(search_path, "%s", dn_path); + sprintf(filter_exp, "(sAMAccountName=%s)", AceSamAccountName); + attr_array[0] = "objectSid"; + attr_array[1] = NULL; + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build(ldap_handle, search_path, filter_exp, + attr_array, &group_base, &group_count, + LDAP_SCOPE_SUBTREE) != 0)) + return(1); + if (group_count == 1) + { + strcpy(AceDn, group_base->dn); + AceSidCount = group_base->length; + memcpy(AceSid, group_base->value, AceSidCount); + } + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + } + else + { + if (strlen(AceSamAccountName) != 0) + { + sprintf(search_path, "%s", dn_path); + sprintf(filter_exp, "(sAMAccountName=%s)", AceSamAccountName); + attr_array[0] = "samAccountName"; + attr_array[1] = NULL; + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build(ldap_handle, search_path, filter_exp, + attr_array, &group_base, &group_count, + LDAP_SCOPE_SUBTREE) != 0)) + return(1); + if (group_count == 1) + { + strcpy(AceDn, group_base->dn); + } + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + } + } + + if (!ActiveDirectory) + { + if (strlen(AceDn) != 0) + { + owner_v[0] = strdup(AceDn); + n = 0; + ADD_ATTR("owner", owner_v, LDAP_MOD_REPLACE); + + mods[n] = NULL; + + rc = ldap_modify_s(ldap_handle, TargetDn, mods); + + for (i = 0; i < n; i++) + free(mods[i]); + + if (rc != LDAP_SUCCESS) + com_err(whoami, 0, "Unable to set owner for group %s : %s", + TargetGroupName, ldap_err2string(rc)); + } + + return(rc); + } + + if (AceSidCount == 0) + { + com_err(whoami, 0, "Group %s: Administrator: %s, Type: %s - does not " + "have an AD SID.", TargetGroupName, AceName, AceType); + com_err(whoami, 0, " Non-admin security group template will be used."); + } + else + { + sprintf(search_path, "%s,%s", security_template_ou, dn_path); + sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u"); + attr_array[0] = "objectSid"; + attr_array[1] = NULL; + + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build(ldap_handle, search_path, filter_exp, + attr_array, &group_base, &group_count, + LDAP_SCOPE_SUBTREE) != 0)) + return(1); + + if ((rc != 0) || (group_count != 1)) + { + com_err(whoami, 0, "Unable to process user security template: %s", + "UserTemplate"); + AceSidCount = 0; + } + else + { + UserTemplateSidCount = group_base->length; + memcpy(UserTemplateSid, group_base->value, UserTemplateSidCount); + } + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + + if (HiddenGroup) + { + if (AceSidCount == 0) + { + strcpy(GroupSecurityTemplate, HIDDEN_GROUP); + sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP); + } + else + { + strcpy(GroupSecurityTemplate, HIDDEN_GROUP_WITH_ADMIN); + sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP_WITH_ADMIN); + } + } + else + { + if (AceSidCount == 0) + { + strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP); + sprintf(filter_exp, "(sAMAccountName=%s)", NOT_HIDDEN_GROUP); + } + else + { + strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP_WITH_ADMIN); + sprintf(filter_exp, "(sAMAccountName=%s)", + NOT_HIDDEN_GROUP_WITH_ADMIN); + } + } + + sprintf(search_path, "%s,%s", security_template_ou, dn_path); + attr_array[0] = "sAMAccountName"; + attr_array[1] = NULL; + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE) != 0)) + return(1); + + if (group_count != 1) + { + linklist_free(group_base); + com_err(whoami, 0, "Unable to process group security template: %s - " + "security not set", GroupSecurityTemplate); + return(1); + } + + strcpy(TemplateDn, group_base->dn); + strcpy(TemplateSamName, group_base->value); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + sprintf(filter_exp, "(sAMAccountName=%s)", TemplateSamName); + rc = ldap_search_ext_s(ldap_handle, + TemplateDn, + LDAP_SCOPE_SUBTREE, + filter_exp, + NULL, + 0, + apsServerControls, + NULL, + NULL, + 0, + &psMsg); + + if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL) + { + com_err(whoami, 0, "Unable to find group security template: %s - " + "security not set", GroupSecurityTemplate); + return(1); + } + + ppsValues = ldap_get_values_len(ldap_handle, psMsg, "ntSecurityDescriptor"); + + if (ppsValues == NULL) + { + com_err(whoami, 0, "Unable to find group security descriptor for group " + "%s - security not set", GroupSecurityTemplate); + return(1); + } + + if (AceSidCount != 0) + { + for (nVal = 0; ppsValues[nVal] != NULL; nVal++) + { + for (i = 0; + i < (int)(ppsValues[nVal]->bv_len - UserTemplateSidCount); i++) + { + if (!memcmp(&ppsValues[nVal]->bv_val[i], UserTemplateSid, + UserTemplateSidCount)) + { + memcpy(&ppsValues[nVal]->bv_val[i], AceSid, AceSidCount); + break; + } + } + } + } + + n = 0; + ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues, + LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); + + if (Exchange) + { + if(HiddenGroup) + { + hide_address_lists_v[0] = "TRUE"; + address_book_v[0] = NULL; + ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, + LDAP_MOD_REPLACE); + ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE); + } else { + hide_address_lists_v[0] = NULL; + ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, + LDAP_MOD_REPLACE); + } + } + + mods[n] = NULL; + + rc = ldap_modify_s(ldap_handle, TargetDn, mods); + + for (i = 0; i < n; i++) + free(mods[i]); + + ldap_value_free_len(ppsValues); + ldap_msgfree(psMsg); + + if (rc != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to set security settings for group %s : %s", + TargetGroupName, ldap_err2string(rc)); + + if (AceSidCount != 0) + { + com_err(whoami, 0, + "Trying to set security for group %s without admin.", + TargetGroupName); + + if (rc = ProcessGroupSecurity(ldap_handle, dn_path, TargetGroupName, + HiddenGroup, "", "")) + { + com_err(whoami, 0, "Unable to set security for group %s.", + TargetGroupName); + return(rc); + } + } + return(rc); + } + + return(rc); +} + +int group_delete(LDAP *ldap_handle, char *dn_path, char *group_name, + char *group_membership, char *MoiraId) +{ + LK_ENTRY *group_base; + char temp[512]; + char filter[128]; + int group_count; + int rc; + + if (!check_string(group_name)) + { + com_err(whoami, 0, + "Unable to process invalid LDAP list name %s", group_name); + return(AD_INVALID_NAME); + } + + memset(filter, '\0', sizeof(filter)); + group_count = 0; + group_base = NULL; + sprintf(temp, "%s,%s", group_ou_root, dn_path); + + if (rc = ad_get_group(ldap_handle, temp, group_name, + group_membership, MoiraId, + "samAccountName", &group_base, + &group_count, filter)) + return(rc); + + if (group_count == 1) + { + if ((rc = ldap_delete_s(ldap_handle, group_base->dn)) != LDAP_SUCCESS) + { + linklist_free(group_base); + com_err(whoami, 0, "Unable to delete list %s from AD : %s", + group_name, ldap_err2string(rc)); + return(rc); + } + linklist_free(group_base); + } + else + { + linklist_free(group_base); + com_err(whoami, 0, "Unable to find list %s in AD.", group_name); + return(AD_NO_GROUPS_FOUND); + } + + return(0); +} + +int BEREncodeSecurityBits(ULONG uBits, char *pBuffer) +{ + *pBuffer++ = 0x30; + *pBuffer++ = 0x03; + *pBuffer++ = 0x02; + *pBuffer++ = 0x00; + return(N_SD_BER_BYTES); +} + +int process_lists(int ac, char **av, void *ptr) +{ + int rc; + int security_flag; + char group_ou[256]; + char group_membership[2]; + char **call_args; + + call_args = ptr; + + security_flag = 0; + memset(group_ou, '\0', sizeof(group_ou)); + memset(group_membership, '\0', sizeof(group_membership)); + get_group_membership(group_membership, group_ou, &security_flag, av); + rc = populate_group((LDAP *)call_args[0], (char *)call_args[1], + av[L_NAME], group_ou, group_membership, + security_flag, ""); + + return(0); +} + +int member_list_build(int ac, char **av, void *ptr) +{ + LK_ENTRY *linklist; + char temp[1024]; + char **call_args; + char *s; + call_args = ptr; + + strcpy(temp, av[ACE_NAME]); + + if (!check_string(temp)) + return(0); + + if (!strcmp(av[ACE_TYPE], "USER")) + { + if (!((int)call_args[3] & MOIRA_USERS)) + return(0); + } + else if (!strcmp(av[ACE_TYPE], "STRING")) + { + if (Exchange) + { + if((s = strchr(temp, '@')) == (char *) NULL) + { + strcat(temp, "@mit.edu"); + } + + if(!strncasecmp(&temp[strlen(temp) - 6], ".LOCAL", 6)) + { + s = strrchr(temp, '.'); + *s = '\0'; + strcat(s, ".mit.edu"); + } + } + + if (!((int)call_args[3] & MOIRA_STRINGS)) + return(0); + + if (contact_create((LDAP *)call_args[0], call_args[1], temp, contact_ou)) + return(0); + + } + else if (!strcmp(av[ACE_TYPE], "LIST")) + { + if (!((int)call_args[3] & MOIRA_LISTS)) + return(0); + } + else if (!strcmp(av[ACE_TYPE], "KERBEROS")) + { + if (!((int)call_args[3] & MOIRA_KERBEROS)) + return(0); + + if (contact_create((LDAP *)call_args[0], call_args[1], temp, + kerberos_ou)) + return(0); + + } + else + return(0); + + linklist = member_base; + + while (linklist) + { + if (!strcasecmp(temp, linklist->member)) + return(0); + + linklist = linklist->next; + } + + linklist = calloc(1, sizeof(LK_ENTRY)); + linklist->op = 1; + linklist->dn = NULL; + linklist->list = calloc(1, strlen(call_args[2]) + 1); + strcpy(linklist->list, call_args[2]); + linklist->type = calloc(1, strlen(av[ACE_TYPE]) + 1); + strcpy(linklist->type, av[ACE_TYPE]); + linklist->member = calloc(1, strlen(temp) + 1); + strcpy(linklist->member, temp); + linklist->next = member_base; + member_base = linklist; + + return(0); +} + +int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, + char *group_ou, char *group_membership, char *user_name, + char *UserOu, char *MoiraId) +{ + char distinguished_name[1024]; + char *modvalues[2]; + char temp[256]; + char filter[128]; + char *attr_array[3]; + int group_count; + int i; + int n; + LDAPMod *mods[20]; + LK_ENTRY *group_base; + ULONG rc; + char *s; + + if (!check_string(group_name)) + return(AD_INVALID_NAME); + + memset(filter, '\0', sizeof(filter)); + group_base = NULL; + group_count = 0; + + if (rc = ad_get_group(ldap_handle, dn_path, group_name, + group_membership, MoiraId, + "samAccountName", &group_base, + &group_count, filter)) + return(rc); + + if (group_count != 1) + { + com_err(whoami, 0, "Unable to find list %s in AD", + group_name); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + goto cleanup; + } + + strcpy(distinguished_name, group_base->dn); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + if(ActiveDirectory) + { + sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path); + } + else + { + if(!strcmp(UserOu, user_ou)) + sprintf(temp, "uid=%s,%s,%s", user_name, UserOu, dn_path); + else + sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path); + } + + modvalues[0] = temp; + modvalues[1] = NULL; + + n = 0; + ADD_ATTR("member", modvalues, LDAP_MOD_DELETE); + mods[n] = NULL; + rc = ldap_modify_s(ldap_handle, distinguished_name, mods); + + for (i = 0; i < n; i++) + free(mods[i]); + + if (rc == LDAP_UNWILLING_TO_PERFORM) + rc = LDAP_SUCCESS; + + if (rc != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to modify list %s members : %s", + group_name, ldap_err2string(rc)); + goto cleanup; + } + + if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou))) + { + if (Exchange) + { + if(!strcmp(UserOu, contact_ou) && + ((s = strstr(user_name, "@mit.edu")) != (char *) NULL)) + { + memset(temp, '\0', sizeof(temp)); + strcpy(temp, user_name); + s = strchr(temp, '@'); + *s = '\0'; + + sprintf(filter, "(&(objectClass=user)(mailNickName=%s))", temp); + + if ((rc = linklist_build(ldap_handle, dn_path, filter, NULL, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE) != 0)) + return(rc); + + if(group_count) + goto cleanup; + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + + sprintf(filter, "(distinguishedName=%s)", temp); + attr_array[0] = "memberOf"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE) != 0)) + return(rc); + + + if(!group_count) + { + com_err(whoami, 0, "Removing unreferenced object %s", temp); + + if ((rc = ldap_delete_s(ldap_handle, temp)) != 0) + return(rc); + } + } + } + + cleanup: + return(rc); +} + +int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, + char *group_ou, char *group_membership, char *user_name, + char *UserOu, char *MoiraId) +{ + char distinguished_name[1024]; + char *modvalues[2]; + char temp[256]; + char filter[128]; + int group_count; + int n; + int i; + LDAPMod *mods[20]; + LK_ENTRY *group_base; + ULONG rc; + + if (!check_string(group_name)) + return(AD_INVALID_NAME); + + rc = 0; + memset(filter, '\0', sizeof(filter)); + group_base = NULL; + group_count = 0; + + if (rc = ad_get_group(ldap_handle, dn_path, group_name, + group_membership, MoiraId, + "samAccountName", &group_base, + &group_count, filter)) + return(rc); + + if (group_count != 1) + { + linklist_free(group_base); + group_base = NULL; + group_count = 0; + com_err(whoami, 0, "Unable to find list %s %d in AD", + group_name, group_count); + return(AD_MULTIPLE_GROUPS_FOUND); + } + + strcpy(distinguished_name, group_base->dn); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + if(ActiveDirectory) + { + sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path); + } + else + { + if(!strcmp(UserOu, user_ou)) + sprintf(temp, "uid=%s,%s,%s", user_name, UserOu, dn_path); + else + sprintf(temp, "cn=%s,%s,%s", user_name, UserOu, dn_path); + } + + modvalues[0] = temp; + modvalues[1] = NULL; + + n = 0; + ADD_ATTR("member", modvalues, LDAP_MOD_ADD); + mods[n] = NULL; + rc = ldap_modify_s(ldap_handle, distinguished_name, mods); + + if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS) + rc = LDAP_SUCCESS; + + if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou))) + { + if (rc == LDAP_UNWILLING_TO_PERFORM) + rc = LDAP_SUCCESS; + } + + for (i = 0; i < n; i++) + free(mods[i]); + + if (rc != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to add %s to list %s as a member : %s", + user_name, group_name, ldap_err2string(rc)); + } + + return(rc); +} + +int contact_remove_email(LDAP *ld, char *bind_path, + LK_ENTRY **linklist_base, int linklist_current) +{ + LK_ENTRY *gPtr; + int rc; + char *mail_v[] = {NULL, NULL}; + LDAPMod *mods[20]; + int n; + int i; + + mail_v[0] = NULL; + + n = 0; + ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); + ADD_ATTR("mailNickName", mail_v, LDAP_MOD_REPLACE); + ADD_ATTR("proxyAddresses", mail_v, LDAP_MOD_REPLACE); + ADD_ATTR("targetAddress", mail_v, LDAP_MOD_REPLACE); + mods[n] = NULL; + + gPtr = (*linklist_base); + + while(gPtr) { + rc = ldap_modify_s(ld, gPtr->dn, mods); + + if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS)) + { + com_err(whoami, 0, "Unable to modify contact %s in AD : %s", + gPtr->dn, ldap_err2string(rc)); + return(rc); + } + + gPtr = gPtr->next; + } + + for (i = 0; i < n; i++) + free(mods[i]); + + return(rc); +} + +int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou) +{ + LDAPMod *mods[20]; + LK_ENTRY *group_base; + int group_count; + char new_dn[256]; + char cn_user_name[256]; + char contact_name[256]; + char mail_nickname[256]; + char proxy_address_internal[256]; + char proxy_address_external[256]; + char target_address[256]; + char internal_contact_name[256]; + char filter[128]; + char mail[256]; + char principal[256]; + char mit_address_book[256]; + char default_address_book[256]; + char contact_address_book[256]; + char uid[256]; + char *email_v[] = {NULL, NULL}; + char *cn_v[] = {NULL, NULL}; + char *contact_v[] = {NULL, NULL}; + char *uid_v[] = {NULL, NULL}; + char *mail_nickname_v[] = {NULL, NULL}; + char *proxy_address_internal_v[] = {NULL, NULL}; + char *proxy_address_external_v[] = {NULL, NULL}; + char *target_address_v[] = {NULL, NULL}; + char *mit_address_book_v[] = {NULL, NULL}; + char *default_address_book_v[] = {NULL, NULL}; + char *contact_address_book_v[] = {NULL, NULL}; + char *hide_address_lists_v[] = {NULL, NULL}; + char *attr_array[3]; + char *objectClass_v[] = {"top", "person", + "organizationalPerson", + "contact", NULL}; + char *objectClass_ldap_v[] = {"top", "person", "microsoftComTop", + "inetOrgPerson", "organizationalPerson", + "contact", "mailRecipient", "eduPerson", + NULL}; + char *name_v[] = {NULL, NULL}; + char *desc_v[] = {NULL, NULL}; + char *s; + int n; + int rc; + int i; + char temp[256]; + char *c; + char *mail_routing_v[] = {NULL, NULL}; + char *principal_v[] = {NULL, NULL}; + + if (!check_string(user)) + { + com_err(whoami, 0, "Unable to process invalid LDAP name %s", user); + return(AD_INVALID_NAME); + } + + strcpy(mail, user); + strcpy(contact_name, mail); + strcpy(internal_contact_name, mail); + + if((s = strchr(internal_contact_name, '@')) != NULL) { + *s = '?'; + } + + sprintf(cn_user_name,"CN=%s,%s,%s", escape_string(contact_name), group_ou, + bind_path); + + sprintf(target_address, "SMTP:%s", contact_name); + sprintf(proxy_address_external, "SMTP:%s", contact_name); + sprintf(mail_nickname, "%s", internal_contact_name); + + cn_v[0] = cn_user_name; + contact_v[0] = contact_name; + uid_v[0] = uid; + name_v[0] = user; + desc_v[0] = "Auto account created by Moira"; + email_v[0] = mail; + proxy_address_internal_v[0] = proxy_address_internal; + proxy_address_external_v[0] = proxy_address_external; + mail_nickname_v[0] = mail_nickname; + target_address_v[0] = target_address; + mit_address_book_v[0] = mit_address_book; + default_address_book_v[0] = default_address_book; + contact_address_book_v[0] = contact_address_book; + strcpy(new_dn, cn_user_name); + n = 0; + + ADD_ATTR("cn", contact_v, LDAP_MOD_ADD); + + if(!ActiveDirectory) + { + if(!strcmp(group_ou, contact_ou)) + sprintf(uid, "%s%s", contact_name, "_strings"); + + if(!strcmp(group_ou, kerberos_ou)) + sprintf(uid, "%s%s", contact_name, "_kerberos"); + + uid_v[0] = uid; + + ADD_ATTR("sn", contact_v, LDAP_MOD_ADD); + ADD_ATTR("uid", uid_v, LDAP_MOD_ADD); + } + + if(ActiveDirectory) + { + ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD); + } + else + { + ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD); + } + + ADD_ATTR("name", name_v, LDAP_MOD_ADD); + ADD_ATTR("displayName", name_v, LDAP_MOD_ADD); + ADD_ATTR("description", desc_v, LDAP_MOD_ADD); + + if (Exchange) + { + if (!strcmp(group_ou, contact_ou) && email_isvalid(mail)) + { + group_count = 0; + group_base = NULL; + + sprintf(filter, "(&(objectClass=user)(cn=%s))", mail); + attr_array[0] = "cn"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ld, bind_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process contact %s : %s", + user, ldap_err2string(rc)); + return(rc); + } + + if (group_count) + { + com_err(whoami, 0, "Object already exists with name %s", + user); + return(1); + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + sprintf(filter, "(&(objectClass=group)(cn=%s))", mail); + attr_array[0] = "cn"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ld, bind_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process contact %s : %s", + user, ldap_err2string(rc)); + return(rc); + } + + if (group_count) + { + com_err(whoami, 0, "Object already exists with name %s", + user); + return(1); + } + + linklist_free(group_base); + group_count = 0; + group_base = NULL; + + sprintf(filter, "(&(objectClass=user)(mail=%s))", mail); + attr_array[0] = "cn"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ld, bind_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process contact %s : %s", + user, ldap_err2string(rc)); + return(rc); + } + + if (group_count) + { + com_err(whoami, 0, "Object already exists with name %s", + user); + return(1); + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + sprintf(filter, "(&(objectClass=group)(mail=%s))", mail); + attr_array[0] = "cn"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ld, bind_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process contact %s : %s", + user, ldap_err2string(rc)); + return(rc); + } + + if (group_count) + { + com_err(whoami, 0, "Object already exists with name %s", + user); + return(1); + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + ADD_ATTR("mail", email_v, LDAP_MOD_ADD); + ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD); + ADD_ATTR("proxyAddresses", proxy_address_external_v, LDAP_MOD_ADD); + ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_ADD); + + hide_address_lists_v[0] = "TRUE"; + ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, + LDAP_MOD_ADD); + } + } + + if(!ActiveDirectory) + { + if((c = strchr(mail, '@')) == NULL) + sprintf(temp, "%s@mit.edu", mail); + else + sprintf(temp, "%s", mail); + + mail_routing_v[0] = temp; + email_v[0] = temp; + principal_v[0] = principal; + + if(!strcmp(group_ou, contact_ou)) + { + ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD); + } + + if(!strcmp(group_ou, contact_ou)) + { + ADD_ATTR("eduPersonPrincipalName", mail_routing_v, LDAP_MOD_ADD); + } + } + + mods[n] = NULL; + + rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL); + + for (i = 0; i < n; i++) + free(mods[i]); + + if (Exchange) + { + if ((rc != LDAP_SUCCESS) && (rc == LDAP_ALREADY_EXISTS) && + !strcmp(group_ou, contact_ou) && email_isvalid(mail)) + { + n = 0; + + ADD_ATTR("mail", email_v, LDAP_MOD_REPLACE); + ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); + ADD_ATTR("proxyAddresses", proxy_address_external_v, + LDAP_MOD_REPLACE); + ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_REPLACE); + + hide_address_lists_v[0] = "TRUE"; + ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, + LDAP_MOD_REPLACE); + + mods[n] = NULL; + rc = ldap_modify_s(ld, new_dn, mods); + + if (rc) + { + com_err(whoami, 0, "Unable to update contact %s", mail); + } + + for (i = 0; i < n; i++) + free(mods[i]); + } + } + + if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS)) + { + n = 0; + ADD_ATTR("cn", contact_v, LDAP_MOD_ADD); + + if(ActiveDirectory) + { + ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD); + } + else + { + ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD); + } + + ADD_ATTR("name", name_v, LDAP_MOD_ADD); + ADD_ATTR("displayName", name_v, LDAP_MOD_ADD); + ADD_ATTR("description", desc_v, LDAP_MOD_ADD); + mods[n] = NULL; + rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL); + + for (i = 0; i < n; i++) + free(mods[i]); + } + + if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS)) + { + com_err(whoami, 0, "Unable to create contact %s : %s", + user, ldap_err2string(rc)); + return(rc); + } + + return(0); +} + +int user_update(LDAP *ldap_handle, char *dn_path, char *user_name, + char *Uid, char *MitId, char *MoiraId, int State, + char *WinHomeDir, char *WinProfileDir, char *first, + char *middle, char *last, char *shell, char *class) +{ + LDAPMod *mods[20]; + LK_ENTRY *group_base; + int group_count; + char distinguished_name[512]; + char displayName[256]; + char *mitMoiraId_v[] = {NULL, NULL}; + char *mitMoiraClass_v[] = {NULL, NULL}; + char *mitMoiraStatus_v[] = {NULL, NULL}; + char *uid_v[] = {NULL, NULL}; + char *mitid_v[] = {NULL, NULL}; + char *homedir_v[] = {NULL, NULL}; + char *winProfile_v[] = {NULL, NULL}; + char *drives_v[] = {NULL, NULL}; + char *userAccountControl_v[] = {NULL, NULL}; + char *alt_recipient_v[] = {NULL, NULL}; + char *hide_address_lists_v[] = {NULL, NULL}; + char *mail_v[] = {NULL, NULL}; + char *gid_v[] = {NULL, NULL}; + char *loginshell_v[] = {NULL, NULL}; + char *principal_v[] = {NULL, NULL}; + char userAccountControlStr[80]; + int n; + int rc; + int i; + int OldUseSFU30; + u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | + UF_PASSWD_CANT_CHANGE; + char filter[128]; + char *attr_array[3]; + char temp[1024]; + char mail[256]; + char contact_mail[256]; + char filter_exp[1024]; + char search_path[512]; + char TemplateDn[512]; + char TemplateSamName[128]; + char alt_recipient[256]; + char principal[256]; + char status[256]; + char acBERBuf[N_SD_BER_BYTES]; + LDAPControl sControl = {"1.2.840.113556.1.4.801", + { N_SD_BER_BYTES, acBERBuf }, + TRUE}; + LDAPControl *apsServerControls[] = {&sControl, NULL}; + LDAPMessage *psMsg; + LDAP_BERVAL **ppsValues; + ULONG dwInfo; + char *argv[3]; + char *homeMDB; + char *homeServerName; + char *save_argv[7]; + char search_string[256]; + char *p, *q; + char *mail_routing_v[] = {NULL, NULL}; + char *c; + + dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION; + BEREncodeSecurityBits(dwInfo, acBERBuf); + + if (!check_string(user_name)) + { + com_err(whoami, 0, "Unable to process invalid LDAP user name %s", + user_name); + return(AD_INVALID_NAME); + } + + memset(contact_mail, '\0', sizeof(contact_mail)); + sprintf(contact_mail, "%s@mit.edu", user_name); + memset(mail, '\0', sizeof(mail)); + sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain)); + memset(alt_recipient, '\0', sizeof(alt_recipient)); + sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, + dn_path); + sprintf(search_string, "@%s", uppercase(ldap_domain)); + + if (Exchange) + { + if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou)) + { + com_err(whoami, 0, "Unable to create user contact %s", contact_mail); + } + } + + group_count = 0; + group_base = NULL; + + memset(displayName, '\0', sizeof(displayName)); + + if (strlen(MoiraId) != 0) + { + if(ActiveDirectory) + { + sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId); + } + else + { + sprintf(filter, + "(&(objectClass=mitPerson)(mitMoiraId=%s))", MoiraId); + } + + attr_array[0] = "cn"; + attr_array[1] = NULL; + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process user %s : %s", + user_name, ldap_err2string(rc)); + return(rc); + } + } + + if (group_count != 1) + { + linklist_free(group_base); + group_base = NULL; + group_count = 0; + sprintf(filter, "(sAMAccountName=%s)", user_name); + attr_array[0] = "cn"; + attr_array[1] = NULL; + sprintf(temp, "%s,%s", user_ou, dn_path); + if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process user %s : %s", + user_name, ldap_err2string(rc)); + return(rc); + } + } + + if (group_count != 1) + { + com_err(whoami, 0, "Unable to find user %s in AD", + user_name); + linklist_free(group_base); + return(AD_NO_USER_FOUND); + } + + strcpy(distinguished_name, group_base->dn); + + linklist_free(group_base); + group_count = 0; + + if(!ActiveDirectory) + { + if (rc = moira_connect()) + { + critical_alert("AD incremental", + "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + argv[0] = user_name; + + if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv))) + { + n = 0; + ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_REPLACE); + mods[n] = NULL; + rc = ldap_modify_s(ldap_handle, distinguished_name, mods); + + if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS) + rc = LDAP_SUCCESS; + + if(rc) + com_err(whoami, 0, + "Unable to set the mailRoutingAddress for %s : %s", + user_name, ldap_err2string(rc)); + + p = strdup(save_argv[3]); + + if((c = strchr(p, ',')) != NULL) + { + q = strtok(p, ","); + StringTrim(q); + + if ((c = strchr(q, '@')) == NULL) + sprintf(temp, "%s@mit.edu", q); + else + sprintf(temp, "%s", q); + + if(email_isvalid(temp) && State != US_DELETED) + { + mail_routing_v[0] = temp; + + n = 0; + ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD); + mods[n] = NULL; + rc = ldap_modify_s(ldap_handle, distinguished_name, mods); + + if (rc == LDAP_ALREADY_EXISTS || + rc == LDAP_TYPE_OR_VALUE_EXISTS) + rc = LDAP_SUCCESS; + + if(rc) + com_err(whoami, 0, + "Unable to set the mailRoutingAddress for %s : %s", + user_name, ldap_err2string(rc)); + } + + while((q = strtok(NULL, ",")) != NULL) { + StringTrim(q); + + if((c = strchr(q, '@')) == NULL) + sprintf(temp, "%s@mit.edu", q); + else + sprintf(temp, "%s", q); + + if(email_isvalid(temp) && State != US_DELETED) + { + mail_routing_v[0] = temp; + + n = 0; + ADD_ATTR("mailRoutingAddress", mail_routing_v, + LDAP_MOD_ADD); + mods[n] = NULL; + rc = ldap_modify_s(ldap_handle, distinguished_name, mods); + + if (rc == LDAP_ALREADY_EXISTS || + rc == LDAP_TYPE_OR_VALUE_EXISTS) + rc = LDAP_SUCCESS; + + if(rc) + com_err(whoami, 0, + "Unable to set the mailRoutingAddress for " + "%s : %s", + user_name, ldap_err2string(rc)); + } + } + } else { + StringTrim(p); + + if((c = strchr(p, '@')) == NULL) + sprintf(temp, "%s@mit.edu", p); + else + sprintf(temp, "%s", p); + + if(email_isvalid(temp) && State != US_DELETED) + { + mail_routing_v[0] = temp; + + n = 0; + ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD); + mods[n] = NULL; + rc = ldap_modify_s(ldap_handle, distinguished_name, mods); + + if (rc == LDAP_ALREADY_EXISTS || + rc == LDAP_TYPE_OR_VALUE_EXISTS) + rc = LDAP_SUCCESS; + + if(rc) + com_err(whoami, 0, + "Unable to set the mailRoutingAddress for %s : %s", + user_name, ldap_err2string(rc)); + } + } + } + moira_disconnect(); + } + + if ((strlen(MitId) != 0) && (MitId[0] == '9')) + rc = attribute_update(ldap_handle, distinguished_name, MitId, + "employeeID", user_name); + else + rc = attribute_update(ldap_handle, distinguished_name, "none", + "employeeID", user_name); + + if(strlen(first)) { + strcat(displayName, first); + } + + if(strlen(middle)) { + if(strlen(first)) + strcat(displayName, " "); + + strcat(displayName, middle); + } + + if(strlen(last)) { + if(strlen(middle) || strlen(first)) + strcat(displayName, " "); + + strcat(displayName, last); + } + + if(strlen(displayName)) + rc = attribute_update(ldap_handle, distinguished_name, displayName, + "displayName", user_name); + else + rc = attribute_update(ldap_handle, distinguished_name, user_name, + "displayName", user_name); + + if(!ActiveDirectory) + { + if(strlen(displayName)) + rc = attribute_update(ldap_handle, distinguished_name, displayName, + "cn", user_name); + else + rc = attribute_update(ldap_handle, distinguished_name, user_name, + "cn", user_name); + } + + if(!ActiveDirectory) + { + rc = attribute_update(ldap_handle, distinguished_name, displayName, + "eduPersonNickname", user_name); + } + + if(strlen(first)) + rc = attribute_update(ldap_handle, distinguished_name, first, + "givenName", user_name); + else + rc = attribute_update(ldap_handle, distinguished_name, "", + "givenName", user_name); + + if(strlen(middle) == 1) + rc = attribute_update(ldap_handle, distinguished_name, middle, + "initials", user_name); + else + rc = attribute_update(ldap_handle, distinguished_name, "", + "initials", user_name); + + if(strlen(last)) + rc = attribute_update(ldap_handle, distinguished_name, last, + "sn", user_name); + else + rc = attribute_update(ldap_handle, distinguished_name, "", + "sn", user_name); + + if(ActiveDirectory) + { + rc = attribute_update(ldap_handle, distinguished_name, Uid, "uid", + user_name); + } + else + { + rc = attribute_update(ldap_handle, distinguished_name, user_name, "uid", + user_name); + } + + rc = attribute_update(ldap_handle, distinguished_name, MoiraId, + "mitMoiraId", user_name); + + n = 0; + uid_v[0] = Uid; + + if(ActiveDirectory) + { + if (!UseSFU30) + { + ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE); + } + else + { + ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_REPLACE); + } + } + else + { + sprintf(principal, "%s@%s", user_name, PRIMARY_REALM); + sprintf(status, "%d", State); + principal_v[0] = principal; + loginshell_v[0] = shell; + mitMoiraClass_v[0] = class; + mitMoiraStatus_v[0] = status; + gid_v[0] = "101"; + ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE); + ADD_ATTR("gidNumber", gid_v, LDAP_MOD_REPLACE); + ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_REPLACE); + ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE); + ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_REPLACE); + ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_REPLACE); + } + + if ((State != US_NO_PASSWD) && (State != US_REGISTERED)) + { + userAccountControl |= UF_ACCOUNTDISABLE; + + if (Exchange) + { + hide_address_lists_v[0] = "TRUE"; + ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, + LDAP_MOD_REPLACE); + } + } + else + { + if (Exchange) + { + hide_address_lists_v[0] = NULL; + ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, + LDAP_MOD_REPLACE); + } + } + + sprintf(userAccountControlStr, "%ld", userAccountControl); + userAccountControl_v[0] = userAccountControlStr; + ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_REPLACE); + + if (Exchange) + { + if (rc = moira_connect()) + { + critical_alert("AD incremental", + "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + argv[0] = user_name; + + if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv))) + { + if(!strcmp(save_argv[1], "EXCHANGE") || + (strstr(save_argv[3], search_string) != NULL)) + { + alt_recipient_v[0] = NULL; + ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE); + + argv[0] = exchange_acl; + argv[1] = "USER"; + argv[2] = user_name; + + rc = mr_query("add_member_to_list", 3, argv, NULL, NULL); + + if ((rc) && (rc != MR_EXISTS)) + { + com_err(whoami, 0, "Unable to add user %s to %s: %s", + user_name, exchange_acl, error_message(rc)); + } + } + else + { + alt_recipient_v[0] = alt_recipient; + ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE); + + argv[0] = exchange_acl; + argv[1] = "USER"; + argv[2] = user_name; + + rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL); + + if ((rc) && (rc != MR_NO_MATCH)) + { + com_err(whoami, 0, + "Unable to remove user %s from %s: %s, %d", + user_name, exchange_acl, error_message(rc), rc); + } + } + } + else + { + alt_recipient_v[0] = alt_recipient; + ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE); + + argv[0] = exchange_acl; + argv[1] = "USER"; + argv[2] = user_name; + + rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL); + + if ((rc) && (rc != MR_NO_MATCH)) + { + com_err(whoami, 0, + "Unable to remove user %s from %s: %s, %d", + user_name, exchange_acl, error_message(rc), rc); + } + } + + moira_disconnect(); + } + else + { + mail_v[0] = contact_mail; + ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); + } + + n = SetHomeDirectory(ldap_handle, user_name, distinguished_name, WinHomeDir, + WinProfileDir, homedir_v, winProfile_v, + drives_v, mods, LDAP_MOD_REPLACE, n); + + if(ActiveDirectory) + { + sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u"); + sprintf(search_path, "%s,%s", security_template_ou, dn_path); + attr_array[0] = "sAMAccountName"; + attr_array[1] = NULL; + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build(ldap_handle, search_path, filter_exp, + attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE) != 0)) + return(1); + + if (group_count != 1) + { + com_err(whoami, 0, "Unable to process user security template: %s - " + "security not set", "UserTemplate.u"); + return(1); + } + + strcpy(TemplateDn, group_base->dn); + strcpy(TemplateSamName, group_base->value); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + rc = ldap_search_ext_s(ldap_handle, search_path, LDAP_SCOPE_SUBTREE, + filter_exp, NULL, 0, apsServerControls, NULL, + NULL, 0, &psMsg); + + if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL) + { + com_err(whoami, 0, "Unable to find user security template: %s - " + "security not set", "UserTemplate.u"); + return(1); + } + + ppsValues = ldap_get_values_len(ldap_handle, psMsg, + "ntSecurityDescriptor"); + + if (ppsValues == NULL) + { + com_err(whoami, 0, "Unable to find user security template: %s - " + "security not set", "UserTemplate.u"); + return(1); + } + + ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues, + LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); + } + + mods[n] = NULL; + + if ((rc = ldap_modify_s(ldap_handle, distinguished_name, + mods)) != LDAP_SUCCESS) + { + OldUseSFU30 = UseSFU30; + SwitchSFU(mods, &UseSFU30, n); + if (OldUseSFU30 != UseSFU30) + rc = ldap_modify_s(ldap_handle, distinguished_name, mods); + if (rc) + { + com_err(whoami, 0, "Unable to modify user data for %s : %s", + user_name, ldap_err2string(rc)); + } + } + + for (i = 0; i < n; i++) + free(mods[i]); + + return(rc); +} + +int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, + char *user_name) +{ + LDAPMod *mods[20]; + char new_dn[256]; + char old_dn[256]; + char upn[256]; + char mail[256]; + char contact_mail[256]; + char proxy_address[256]; + char query_base_dn[256]; + char temp[256]; + char *userPrincipalName_v[] = {NULL, NULL}; + char *altSecurityIdentities_v[] = {NULL, NULL}; + char *name_v[] = {NULL, NULL}; + char *samAccountName_v[] = {NULL, NULL}; + char *mail_v[] = {NULL, NULL}; + char *mail_nickname_v[] = {NULL, NULL}; + char *proxy_address_v[] = {NULL, NULL}; + char *query_base_dn_v[] = {NULL, NULL}; + char *principal_v[] = {NULL, NULL}; + char principal[256]; + int n; + int rc; + int i; + + if (!check_string(before_user_name)) + { + com_err(whoami, 0, + "Unable to process invalid LDAP user name %s", before_user_name); + return(AD_INVALID_NAME); + } + + if (!check_string(user_name)) + { + com_err(whoami, 0, + "Unable to process invalid LDAP user name %s", user_name); + return(AD_INVALID_NAME); + } + + strcpy(user_name, user_name); + + if(ActiveDirectory) + sprintf(old_dn, "cn=%s,%s,%s", before_user_name, user_ou, dn_path); + else + sprintf(old_dn, "uid=%s,%s,%s", before_user_name, user_ou, dn_path); + + if(ActiveDirectory) + sprintf(new_dn, "cn=%s", user_name); + else + sprintf(new_dn, "uid=%s", user_name); + + sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain)); + sprintf(contact_mail, "%s@mit.edu", user_name); + sprintf(proxy_address, "SMTP:%s@%s", user_name, lowercase(ldap_domain)); + sprintf(principal, "%s@%s", user_name, PRIMARY_REALM); + + if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, NULL, TRUE, + NULL, NULL)) != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to rename user from %s to %s : %s", + before_user_name, user_name, ldap_err2string(rc)); + return(rc); + } + + if (Exchange) + { + sprintf(temp, "cn=%s@mit.edu,%s,%s", before_user_name, contact_ou, + dn_path); + + if(rc = ldap_delete_s(ldap_handle, temp)) + { + com_err(whoami, 0, "Unable to delete user contact for %s", + user_name); + } + + if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou)) + { + com_err(whoami, 0, "Unable to create user contact %s", contact_mail); + } + } + + name_v[0] = user_name; + sprintf(upn, "%s@%s", user_name, ldap_domain); + userPrincipalName_v[0] = upn; + principal_v[0] = principal; + sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM); + sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, dn_path); + altSecurityIdentities_v[0] = temp; + samAccountName_v[0] = user_name; + mail_v[0] = mail; + mail_nickname_v[0] = user_name; + proxy_address_v[0] = proxy_address; + query_base_dn_v[0] = query_base_dn; + + n = 0; + ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_REPLACE); + ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_REPLACE); + ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE); + ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_REPLACE); + + if(!ActiveDirectory) + { + ADD_ATTR("uid", samAccountName_v, LDAP_MOD_REPLACE); + ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE); + ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE); + ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_REPLACE); + } + + if (Exchange) + { + ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_REPLACE); + ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); + ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); + ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE); + } + else + { + mail_v[0] = contact_mail; + ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); + } + + mods[n] = NULL; + + if(ActiveDirectory) + sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, dn_path); + else + sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, dn_path); + + if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS) + { + com_err(whoami, 0, + "Unable to modify user data for %s after renaming : %s", + user_name, ldap_err2string(rc)); + } + + for (i = 0; i < n; i++) + free(mods[i]); + + return(rc); +} + +int user_create(int ac, char **av, void *ptr) +{ + LDAPMod *mods[20]; + char new_dn[256]; + char user_name[256]; + char sam_name[256]; + char upn[256]; + char mail[256]; + char contact_mail[256]; + char proxy_address[256]; + char mail_nickname[256]; + char query_base_dn[256]; + char displayName[256]; + char address_book[256]; + char alt_recipient[256]; + char *cn_v[] = {NULL, NULL}; + char *objectClass_v[] = {"top", "person", "organizationalPerson", + "user", NULL}; + char *objectClass_ldap_v[] = {"top", + "eduPerson", "posixAccount", + "apple-user", "shadowAccount", + "microsoftComTop", "securityPrincipal", + "inetOrgPerson", "user", + "organizationalPerson", "person", + "mailRecipient", NULL}; + + char *samAccountName_v[] = {NULL, NULL}; + char *altSecurityIdentities_v[] = {NULL, NULL}; + char *mitMoiraId_v[] = {NULL, NULL}; + char *mitMoiraClass_v[] = {NULL, NULL}; + char *mitMoiraStatus_v[] = {NULL, NULL}; + char *name_v[] = {NULL, NULL}; + char *desc_v[] = {NULL, NULL}; + char *userPrincipalName_v[] = {NULL, NULL}; + char *userAccountControl_v[] = {NULL, NULL}; + char *uid_v[] = {NULL, NULL}; + char *gid_v[] = {NULL, NULL}; + char *mitid_v[] = {NULL, NULL}; + char *homedir_v[] = {NULL, NULL}; + char *winProfile_v[] = {NULL, NULL}; + char *drives_v[] = {NULL, NULL}; + char *mail_v[] = {NULL, NULL}; + char *givenName_v[] = {NULL, NULL}; + char *sn_v[] = {NULL, NULL}; + char *initials_v[] = {NULL, NULL}; + char *displayName_v[] = {NULL, NULL}; + char *proxy_address_v[] = {NULL, NULL}; + char *mail_nickname_v[] = {NULL, NULL}; + char *query_base_dn_v[] = {NULL, NULL}; + char *address_book_v[] = {NULL, NULL}; + char *homeMDB_v[] = {NULL, NULL}; + char *homeServerName_v[] = {NULL, NULL}; + char *mdbUseDefaults_v[] = {NULL, NULL}; + char *mailbox_guid_v[] = {NULL, NULL}; + char *user_culture_v[] = {NULL, NULL}; + char *user_account_control_v[] = {NULL, NULL}; + char *msexch_version_v[] = {NULL, NULL}; + char *alt_recipient_v[] = {NULL, NULL}; + char *hide_address_lists_v[] = {NULL, NULL}; + char *principal_v[] = {NULL, NULL}; + char *loginshell_v[] = {NULL, NULL}; + char userAccountControlStr[80]; + char temp[1024]; + char principal[256]; + char filter_exp[1024]; + char search_path[512]; + char *attr_array[3]; + u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | + UF_PASSWD_CANT_CHANGE; + int n; + int rc; + int i; + int OldUseSFU30; + char **call_args; + char WinHomeDir[1024]; + char WinProfileDir[1024]; + char *homeMDB; + char *homeServerName; + ULONG dwInfo; + char acBERBuf[N_SD_BER_BYTES]; + LK_ENTRY *group_base; + int group_count; + char TemplateDn[512]; + char TemplateSamName[128]; + LDAP_BERVAL **ppsValues; + LDAPControl sControl = {"1.2.840.113556.1.4.801", + { N_SD_BER_BYTES, acBERBuf }, + TRUE}; + LDAPControl *apsServerControls[] = {&sControl, NULL}; + LDAPMessage *psMsg; + char *argv[3]; + char *save_argv[7]; + char search_string[256]; + char *o_v[] = {NULL, NULL}; + char *p, *q; + char *mail_routing_v[] = {NULL, NULL}; + char *c; + + call_args = ptr; + + dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION; + BEREncodeSecurityBits(dwInfo, acBERBuf); + + if (!check_string(av[U_NAME])) + { + callback_rc = AD_INVALID_NAME; + com_err(whoami, 0, "Unable to process invalid LDAP user name %s", + av[U_NAME]); + return(AD_INVALID_NAME); + } + + memset(WinHomeDir, '\0', sizeof(WinHomeDir)); + memset(WinProfileDir, '\0', sizeof(WinProfileDir)); + memset(displayName, '\0', sizeof(displayName)); + memset(query_base_dn, '\0', sizeof(query_base_dn)); + strcpy(WinHomeDir, av[U_WINHOMEDIR]); + strcpy(WinProfileDir, av[U_WINPROFILEDIR]); + strcpy(user_name, av[U_NAME]); + sprintf(upn, "%s@%s", user_name, ldap_domain); + sprintf(sam_name, "%s", av[U_NAME]); + + if(strlen(av[U_FIRST])) { + strcat(displayName, av[U_FIRST]); + } + + if(strlen(av[U_MIDDLE])) { + if(strlen(av[U_FIRST])) + strcat(displayName, " "); + + strcat(displayName, av[U_MIDDLE]); + } + + if(strlen(av[U_LAST])) { + if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE])) + strcat(displayName, " "); + + strcat(displayName, av[U_LAST]); + } + + samAccountName_v[0] = sam_name; + if ((atoi(av[U_STATE]) != US_NO_PASSWD) && + (atoi(av[U_STATE]) != US_REGISTERED)) + { + userAccountControl |= UF_ACCOUNTDISABLE; + + if (Exchange) + { + hide_address_lists_v[0] = "TRUE"; + ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, + LDAP_MOD_ADD); + } + } + + sprintf(userAccountControlStr, "%ld", userAccountControl); + userAccountControl_v[0] = userAccountControlStr; + userPrincipalName_v[0] = upn; + + if(ActiveDirectory) + cn_v[0] = user_name; + else + cn_v[0] = displayName; + + name_v[0] = user_name; + desc_v[0] = "Auto account created by Moira"; + mail_v[0] = mail; + givenName_v[0] = av[U_FIRST]; + + if(ActiveDirectory) + sn_v[0] = av[U_LAST]; + else + if(strlen(av[U_LAST])) + sn_v[0] = av[U_LAST]; + else + sn_v[0] = av[U_NAME]; + + displayName_v[0] = displayName; + mail_nickname_v[0] = user_name; + o_v[0] = "Massachusetts Institute of Technology"; + + sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM); + sprintf(principal, "%s@%s", user_name, PRIMARY_REALM); + altSecurityIdentities_v[0] = temp; + principal_v[0] = principal; + + if(ActiveDirectory) + sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, call_args[1]); + else + sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, call_args[1]); + + sprintf(mail,"%s@%s", user_name, lowercase(ldap_domain)); + sprintf(contact_mail, "%s@mit.edu", user_name); + sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, call_args[1]); + query_base_dn_v[0] = query_base_dn; + sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, + call_args[1]); + sprintf(search_string, "@%s", uppercase(ldap_domain)); + + if (Exchange) + { + if(contact_create((LDAP *)call_args[0], call_args[1], contact_mail, + contact_ou)) + { + com_err(whoami, 0, "Unable to create user contact %s", + contact_mail); + } + + if(find_homeMDB((LDAP *)call_args[0], call_args[1], &homeMDB, + &homeServerName)) + { + com_err(whoami, 0, "Unable to locate homeMB and homeServerName"); + return(1); + } + + com_err(whoami, 0, "homeMDB:%s", homeMDB); + com_err(whoami, 0, "homeServerName:%s", homeServerName); + + homeMDB_v[0] = homeMDB; + homeServerName_v[0] = homeServerName; + } + + n = 0; + + ADD_ATTR("cn", cn_v, LDAP_MOD_ADD); + + if(ActiveDirectory) + { + ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD); + } + else + { + ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD); + } + + ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD); + ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_ADD); + ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_ADD); + ADD_ATTR("name", name_v, LDAP_MOD_ADD); + ADD_ATTR("description", desc_v, LDAP_MOD_ADD); + + if (Exchange) + { + ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_ADD); + ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD); + ADD_ATTR("homeMDB", homeMDB_v, LDAP_MOD_ADD); + mdbUseDefaults_v[0] = "TRUE"; + ADD_ATTR("mdbUseDefaults", mdbUseDefaults_v, LDAP_MOD_ADD); + ADD_ATTR("msExchHomeServerName", homeServerName_v, LDAP_MOD_ADD); + + argv[0] = user_name; + + if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv))) + { + if(!strcmp(save_argv[1], "EXCHANGE") || + (strstr(save_argv[3], search_string) != NULL)) + { + argv[0] = exchange_acl; + argv[1] = "USER"; + argv[2] = user_name; + + rc = mr_query("add_member_to_list", 3, argv, NULL, NULL); + + if ((rc) && (rc != MR_EXISTS)) + { + com_err(whoami, 0, "Unable to add user %s to %s: %s", + user_name, exchange_acl, error_message(rc)); + } + } + else + { + alt_recipient_v[0] = alt_recipient; + ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD); + } + } + else + { + alt_recipient_v[0] = alt_recipient; + ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD); + + com_err(whoami, 0, "Unable to fetch pobox for %s", user_name); + } + } + else + { + mail_v[0] = contact_mail; + ADD_ATTR("mail", mail_v, LDAP_MOD_ADD); + } + + if(strlen(av[U_FIRST])) { + ADD_ATTR("givenName", givenName_v, LDAP_MOD_ADD); + } + + if(strlen(av[U_LAST]) || strlen(av[U_NAME])) { + ADD_ATTR("sn", sn_v, LDAP_MOD_ADD); + } + + if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]) || strlen(av[U_LAST])) { + ADD_ATTR("displayName", displayName_v, LDAP_MOD_ADD); + + if(!ActiveDirectory) + { + ADD_ATTR("eduPersonNickname", displayName_v, LDAP_MOD_ADD); + } + } else { + ADD_ATTR("displayName", name_v, LDAP_MOD_ADD); + + if(!ActiveDirectory) + { + ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_ADD); + } + } + + if (strlen(av[U_MIDDLE]) == 1) { + initials_v[0] = av[U_MIDDLE]; + ADD_ATTR("initials", initials_v, LDAP_MOD_ADD); + } + + if (strlen(call_args[2]) != 0) + { + mitMoiraId_v[0] = call_args[2]; + ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD); + } + + ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_ADD); + + if(!ActiveDirectory) + { + loginshell_v[0] = av[U_SHELL]; + mitMoiraClass_v[0] = av[U_CLASS]; + mitMoiraStatus_v[0] = av[U_STATE]; + ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_ADD); + ADD_ATTR("uid", samAccountName_v, LDAP_MOD_ADD); + ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_ADD); + ADD_ATTR("o", o_v, LDAP_MOD_ADD); + ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_ADD); + ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_ADD); + } + + if (strlen(av[U_UID]) != 0) + { + uid_v[0] = av[U_UID]; + + if(ActiveDirectory) + { + ADD_ATTR("uid", uid_v, LDAP_MOD_ADD); + } + else + { + gid_v[0] = "101"; + ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD); + ADD_ATTR("gidNumber", gid_v, LDAP_MOD_ADD); + } + + if(ActiveDirectory) + { + if (!UseSFU30) + { + ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD); + } + else + { + ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_ADD); + } + } + } + + if ((strlen(av[U_MITID]) != 0) && (av[U_MITID][0] == '9')) + mitid_v[0] = av[U_MITID]; + else + mitid_v[0] = "none"; + + ADD_ATTR("employeeID", mitid_v, LDAP_MOD_ADD); + + n = SetHomeDirectory((LDAP *)call_args[0], user_name, new_dn, + WinHomeDir, WinProfileDir, homedir_v, winProfile_v, + drives_v, mods, LDAP_MOD_ADD, n); + + if(ActiveDirectory) + { + sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u"); + sprintf(search_path, "%s,%s", security_template_ou, call_args[1]); + attr_array[0] = "sAMAccountName"; + attr_array[1] = NULL; + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build((LDAP *)call_args[0], search_path, filter_exp, + attr_array, &group_base, &group_count, + LDAP_SCOPE_SUBTREE) != 0)) + return(1); + + if (group_count != 1) + { + com_err(whoami, 0, "Unable to process user security template: %s - " + "security not set", "UserTemplate.u"); + return(1); + } + + strcpy(TemplateDn, group_base->dn); + strcpy(TemplateSamName, group_base->value); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + rc = ldap_search_ext_s((LDAP *)call_args[0], search_path, + LDAP_SCOPE_SUBTREE, filter_exp, NULL, 0, + apsServerControls, NULL, + NULL, 0, &psMsg); + + if ((psMsg = ldap_first_entry((LDAP *)call_args[0], psMsg)) == NULL) + { + com_err(whoami, 0, "Unable to find user security template: %s - " + "security not set", "UserTemplate.u"); + return(1); + } + + ppsValues = ldap_get_values_len((LDAP *)call_args[0], psMsg, + "ntSecurityDescriptor"); + if (ppsValues == NULL) + { + com_err(whoami, 0, "Unable to find user security template: %s - " + "security not set", "UserTemplate.u"); + return(1); + } + + ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues, + LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); + } + + mods[n] = NULL; + + rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL); + + if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS)) + { + OldUseSFU30 = UseSFU30; + SwitchSFU(mods, &UseSFU30, n); + if (OldUseSFU30 != UseSFU30) + rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL); + } + + for (i = 0; i < n; i++) + free(mods[i]); + + if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS)) + { + com_err(whoami, 0, "Unable to create user %s : %s", + user_name, ldap_err2string(rc)); + callback_rc = rc; + return(rc); + } + + if ((rc == LDAP_SUCCESS) && (SetPassword)) + { + if ((rc = set_password(sam_name, "", ldap_domain)) != 0) + { + ad_kdc_disconnect(); + if (!ad_server_connect(default_server, ldap_domain)) + { + com_err(whoami, 0, "Unable to set password for user %s : %s", + user_name, + "cannot get changepw ticket from windows domain"); + } + else + { + if ((rc = set_password(sam_name, "", ldap_domain)) != 0) + { + com_err(whoami, 0, "Unable to set password for user %s " + ": %ld", user_name, rc); + } + } + } + } + + if(!ActiveDirectory) + { + if (rc = moira_connect()) + { + critical_alert("AD incremental", + "Error contacting Moira server : %s", + error_message(rc)); + return; + } + + argv[0] = user_name; + + if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv))) + { + p = strdup(save_argv[3]); + + if((c = strchr(p, ',')) != NULL) { + q = strtok(p, ","); + StringTrim(q); + + if ((c = strchr(q, '@')) == NULL) + sprintf(temp, "%s@mit.edu", q); + else + sprintf(temp, "%s", q); + + if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) + { + mail_routing_v[0] = temp; + + n = 0; + ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD); + mods[n] = NULL; + rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods); + + if (rc == LDAP_ALREADY_EXISTS || + rc == LDAP_TYPE_OR_VALUE_EXISTS) + rc = LDAP_SUCCESS; + + if(rc) + com_err(whoami, 0, + "Unable to set the mailRoutingAddress for %s : %s", + user_name, ldap_err2string(rc)); + } + + while((q = strtok(NULL, ",")) != NULL) { + StringTrim(q); + + if((c = strchr(q, '@')) == NULL) + sprintf(temp, "%s@mit.edu", q); + else + sprintf(temp, "%s", q); + + if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) + { + mail_routing_v[0] = temp; + + n = 0; + ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD); + mods[n] = NULL; + rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods); + + if (rc == LDAP_ALREADY_EXISTS || + rc == LDAP_TYPE_OR_VALUE_EXISTS) + rc = LDAP_SUCCESS; + + if(rc) + com_err(whoami, 0, + "Unable to set the mailRoutingAddress for %s : %s", + user_name, ldap_err2string(rc)); + } + } + } else { + StringTrim(p); + + if((c = strchr(p, '@')) == NULL) + sprintf(temp, "%s@mit.edu", p); + else + sprintf(temp, "%s", p); + + if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) + { + mail_routing_v[0] = temp; + + n = 0; + ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD); + mods[n] = NULL; + rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods); + + if (rc == LDAP_ALREADY_EXISTS || + rc == LDAP_TYPE_OR_VALUE_EXISTS) + rc = LDAP_SUCCESS; + + if(rc) + com_err(whoami, 0, + "Unable to set the mailRoutingAddress for %s : %s", + user_name, ldap_err2string(rc)); + } + } + } + moira_disconnect(); + } + + return(0); +} + +int user_change_status(LDAP *ldap_handle, char *dn_path, + char *user_name, char *MoiraId, + int operation) +{ + char filter[128]; + char *attr_array[3]; + char temp[256]; + char distinguished_name[1024]; + char **modvalues; + char *mitMoiraId_v[] = {NULL, NULL}; + LDAPMod *mods[20]; + LK_ENTRY *group_base; + int group_count; + int rc; + int i; + int n; + ULONG ulongValue; + + if (!check_string(user_name)) + { + com_err(whoami, 0, "Unable to process invalid LDAP user name %s", + user_name); + return(AD_INVALID_NAME); + } + + group_count = 0; + group_base = NULL; + + if (strlen(MoiraId) != 0) + { + sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId); + attr_array[0] = "UserAccountControl"; + attr_array[1] = NULL; + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process user %s : %s", + user_name, ldap_err2string(rc)); + return(rc); + } + } + + if (group_count != 1) + { + linklist_free(group_base); + group_count = 0; + group_base = NULL; + sprintf(filter, "(sAMAccountName=%s)", user_name); + attr_array[0] = "UserAccountControl"; + attr_array[1] = NULL; + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process user %s : %s", + user_name, ldap_err2string(rc)); + return(rc); + } + } + + if (group_count != 1) + { + linklist_free(group_base); + com_err(whoami, 0, "Unable to find user %s in AD", + user_name); + return(LDAP_NO_SUCH_OBJECT); + } + + strcpy(distinguished_name, group_base->dn); + ulongValue = atoi((*group_base).value); + + if (operation == MEMBER_DEACTIVATE) + ulongValue |= UF_ACCOUNTDISABLE; + else + ulongValue &= ~UF_ACCOUNTDISABLE; + + sprintf(temp, "%ld", ulongValue); + + if ((rc = construct_newvalues(group_base, group_count, (*group_base).value, + temp, &modvalues, REPLACE)) == 1) + goto cleanup; + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + n = 0; + ADD_ATTR("UserAccountControl", modvalues, LDAP_MOD_REPLACE); + + if (strlen(MoiraId) != 0) + { + mitMoiraId_v[0] = MoiraId; + ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE); + } + + mods[n] = NULL; + rc = ldap_modify_s(ldap_handle, distinguished_name, mods); + + for (i = 0; i < n; i++) + free(mods[i]); + + free_values(modvalues); + + if (rc != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to change status of user %s : %s", + user_name, ldap_err2string(rc)); + } + + cleanup: + return(rc); +} + +int user_delete(LDAP *ldap_handle, char *dn_path, + char *u_name, char *MoiraId) +{ + char filter[128]; + char *attr_array[3]; + char distinguished_name[1024]; + char user_name[512]; + LK_ENTRY *group_base; + int group_count; + int rc; + char temp[256]; + + if (!check_string(u_name)) + return(AD_INVALID_NAME); + + strcpy(user_name, u_name); + group_count = 0; + group_base = NULL; + + if (strlen(MoiraId) != 0) + { + sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId); + attr_array[0] = "name"; + attr_array[1] = NULL; + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process user %s : %s", + user_name, ldap_err2string(rc)); + goto cleanup; + } + } + + if (group_count != 1) + { + linklist_free(group_base); + group_count = 0; + group_base = NULL; + sprintf(filter, "(sAMAccountName=%s)", user_name); + attr_array[0] = "name"; + attr_array[1] = NULL; + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process user %s : %s", + user_name, ldap_err2string(rc)); + goto cleanup; + } + } + + if (group_count != 1) + { + com_err(whoami, 0, "Unable to find user %s in AD", + user_name); + goto cleanup; + } + + strcpy(distinguished_name, group_base->dn); + + if (rc = ldap_delete_s(ldap_handle, distinguished_name)) + { + com_err(whoami, 0, "Unable to process user %s : %s", + user_name, ldap_err2string(rc)); + } + + /* Need to add code to delete mit.edu contact */ + + if (Exchange) + { + sprintf(temp, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, dn_path); + + if(rc = ldap_delete_s(ldap_handle, temp)) + { + com_err(whoami, 0, "Unable to delete user contact for %s", + user_name); + } + } + + cleanup: + linklist_free(group_base); + + return(0); +} + +void linklist_free(LK_ENTRY *linklist_base) +{ + LK_ENTRY *linklist_previous; + + while (linklist_base != NULL) + { + if (linklist_base->dn != NULL) + free(linklist_base->dn); + + if (linklist_base->attribute != NULL) + free(linklist_base->attribute); + + if (linklist_base->value != NULL) + free(linklist_base->value); + + if (linklist_base->member != NULL) + free(linklist_base->member); + + if (linklist_base->type != NULL) + free(linklist_base->type); + + if (linklist_base->list != NULL) + free(linklist_base->list); + + linklist_previous = linklist_base; + linklist_base = linklist_previous->next; + free(linklist_previous); + } +} + +void free_values(char **modvalues) +{ + int i; + + i = 0; + + if (modvalues != NULL) + { + while (modvalues[i] != NULL) + { + free(modvalues[i]); + modvalues[i] = NULL; + ++i; + } + free(modvalues); + } +} + +static int illegalchars[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */ + 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +static int illegalchars_ldap[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */ + 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, /* SPACE - / */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, /* P - _ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +int check_string(char *s) +{ + char character; + + for (; *s; s++) + { + character = *s; + + if (isupper(character)) + character = tolower(character); + + if(ActiveDirectory) + { + if (illegalchars[(unsigned) character]) + return 0; + } + else + { + if (illegalchars_ldap[(unsigned) character]) + return 0; + } + } + + return(1); +} + +int check_container_name(char *s) +{ + char character; + + for (; *s; s++) + { + character = *s; + + if (isupper(character)) + character = tolower(character); + + if (character == ' ') + continue; + + if (illegalchars[(unsigned) character]) + return 0; + } + + return(1); +} + +int mr_connect_cl(char *server, char *client, int version, int auth) +{ + int status; + char *motd; + char temp[128]; + + status = mr_connect(server); + + if (status) + { + com_err(whoami, status, "while connecting to Moira"); + return status; + } + + status = mr_motd(&motd); + + if (status) + { + mr_disconnect(); + com_err(whoami, status, "while checking server status"); + return status; + } + + if (motd) + { + sprintf(temp, "The Moira server is currently unavailable: %s", motd); + com_err(whoami, status, temp); + mr_disconnect(); + return status; + } + + status = mr_version(version); + + if (status) + { + if (status == MR_UNKNOWN_PROC) + { + if (version > 2) + status = MR_VERSION_HIGH; + else + status = MR_SUCCESS; + } + + if (status == MR_VERSION_HIGH) + { + com_err(whoami, 0, "Warning: This client is running newer code " + "than the server."); + com_err(whoami, 0, "Some operations may not work."); + } + else if (status && status != MR_VERSION_LOW) + { + com_err(whoami, status, "while setting query version number."); + mr_disconnect(); + return status; + } + } + + if (auth) + { + status = mr_krb5_auth(client); + if (status) + { + com_err(whoami, status, "while authenticating to Moira."); + mr_disconnect(); + return status; + } + } + + return MR_SUCCESS; +} + +void AfsToWinAfs(char* path, char* winPath) +{ + char* pathPtr; + char* winPathPtr; + strcpy(winPath, WINAFS); + pathPtr = path + strlen(AFS); + winPathPtr = winPath + strlen(WINAFS); + + while (*pathPtr) + { + if (*pathPtr == '/') + *winPathPtr = '\\'; + else + *winPathPtr = *pathPtr; + + pathPtr++; + winPathPtr++; + } +} + +int GetAceInfo(int ac, char **av, void *ptr) +{ + char **call_args; + int security_flag; + + call_args = ptr; + + strcpy(call_args[0], av[L_ACE_TYPE]); + strcpy(call_args[1], av[L_ACE_NAME]); + security_flag = 0; + get_group_membership(call_args[2], call_args[3], &security_flag, av); + return(LDAP_SUCCESS); +} + +int checkADname(LDAP *ldap_handle, char *dn_path, char *Name) +{ + char filter[128]; + char *attr_array[3]; + int group_count; + int rc; + LK_ENTRY *group_base; + + group_count = 0; + group_base = NULL; + + sprintf(filter, "(sAMAccountName=%s)", Name); + attr_array[0] = "sAMAccountName"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process ACE name %s : %s", + Name, ldap_err2string(rc)); + return(1); + } + + linklist_free(group_base); + group_base = NULL; + + if (group_count == 0) + return(0); + + return(1); +} + +#define MAX_ACE 7 + +int ProcessAce(LDAP *ldap_handle, char *dn_path, char *Name, char *Type, + int UpdateGroup, int *ProcessGroup, char *maillist) +{ + char *av[2]; + char GroupName[256]; + char *call_args[7]; + int rc; + char *AceInfo[4]; + char AceType[32]; + char AceName[128]; + char AceMembership[2]; + char AceOu[256]; + char temp[128]; + char *save_argv[U_END]; + + if (!SetGroupAce) + { + com_err(whoami, 0, "ProcessAce disabled, skipping"); + return(0); + } + + strcpy(GroupName, Name); + + if (strcasecmp(Type, "LIST")) + return(1); + + while (1) + { + av[0] = GroupName; + AceInfo[0] = AceType; + AceInfo[1] = AceName; + AceInfo[2] = AceMembership; + AceInfo[3] = AceOu; + memset(AceType, '\0', sizeof(AceType)); + memset(AceName, '\0', sizeof(AceName)); + memset(AceMembership, '\0', sizeof(AceMembership)); + memset(AceOu, '\0', sizeof(AceOu)); + callback_rc = 0; + + if (rc = mr_query("get_list_info", 1, av, GetAceInfo, AceInfo)) + { + com_err(whoami, 0, "Unable to get ACE info for list %s : %s", + GroupName, error_message(rc)); + return(1); + } + + if (callback_rc) + { + com_err(whoami, 0, "Unable to get ACE info for list %s", GroupName); + return(1); + } + + if ((strcasecmp(AceType, "USER")) && (strcasecmp(AceType, "LIST"))) + return(0); + + strcpy(temp, AceName); + + if (!strcasecmp(AceType, "LIST")) + sprintf(temp, "%s%s", AceName, group_suffix); + + if (!UpdateGroup) + { + if (checkADname(ldap_handle, dn_path, temp)) + return(0); + + (*ProcessGroup) = 1; + } + + if (!strcasecmp(AceInfo[0], "LIST")) + { + if (make_new_group(ldap_handle, dn_path, "", AceName, AceOu, + AceMembership, 0, UpdateGroup, maillist)) + return(1); + } + else if (!strcasecmp(AceInfo[0], "USER")) + { + av[0] = AceName; + call_args[0] = (char *)ldap_handle; + call_args[1] = dn_path; + call_args[2] = ""; + call_args[3] = NULL; + callback_rc = 0; + + if (rc = mr_query("get_user_account_by_login", 1, av, + save_query_info, save_argv)) + { + com_err(whoami, 0, "Unable to process user ACE %s for group %s.", + AceName, Name); + return(1); + } + + if (rc = user_create(U_END, save_argv, call_args)) + { + com_err(whoami, 0, "Unable to process user ACE %s for group %s.", + AceName, Name); + return(1); + } + + if (callback_rc) + { + com_err(whoami, 0, "Unable to process user Ace %s for group %s", + AceName, Name); + return(1); + } + + return(0); + } + else + return(1); + + if (!strcasecmp(AceType, "LIST")) + { + if (!strcasecmp(GroupName, AceName)) + return(0); + } + + strcpy(GroupName, AceName); + } + + return(1); +} + +int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, + char *group_name, char *group_ou, char *group_membership, + int group_security_flag, int updateGroup, char *maillist) +{ + char *av[3]; + char *call_args[8]; + int rc; + LK_ENTRY *group_base; + int group_count; + char filter[128]; + char *attr_array[3]; + + av[0] = group_name; + call_args[0] = (char *)ldap_handle; + call_args[1] = dn_path; + call_args[2] = group_name; + call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS); + call_args[4] = (char *)updateGroup; + call_args[5] = MoiraId; + call_args[6] = "0"; + call_args[7] = NULL; + callback_rc = 0; + + group_count = 0; + group_base = NULL; + + if (rc = mr_query("get_list_info", 1, av, group_create, call_args)) + { + moira_disconnect(); + com_err(whoami, 0, "Unable to create list %s : %s", group_name, + error_message(rc)); + return(rc); + } + + if (callback_rc) + { + moira_disconnect(); + com_err(whoami, 0, "Unable to create list %s", group_name); + return(callback_rc); + } + + return(0); +} + +int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, + char *group_ou, char *group_membership, + int group_security_flag, char *MoiraId) +{ + char *av[3]; + char *call_args[7]; + char *pUserOu; + LK_ENTRY *ptr; + int rc; + char member[512]; + char *s; + char **members; + int i = 0; + int j = 0; + int n = 0; + char group_dn[512]; + LDAPMod *mods[20]; + char *save_argv[U_END]; + + com_err(whoami, 0, "Populating group %s", group_name); + av[0] = group_name; + call_args[0] = (char *)ldap_handle; + call_args[1] = dn_path; + call_args[2] = group_name; + call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS); + call_args[4] = NULL; + member_base = NULL; + + if (rc = mr_query("get_end_members_of_list", 1, av, + member_list_build, call_args)) + { + com_err(whoami, 0, "Unable to populate list %s : %s", + group_name, error_message(rc)); + return(3); + } + + members = (char **)malloc(sizeof(char *) * 2); + + if (member_base != NULL) + { + ptr = member_base; + + while (ptr != NULL) + { + if (!strcasecmp(ptr->type, "LIST")) + { + ptr = ptr->next; + continue; + } + + if(!strcasecmp(ptr->type, "USER")) + { + if ((rc = check_user(ldap_handle, dn_path, ptr->member, + "")) == AD_NO_USER_FOUND) + { + com_err(whoami, 0, "creating user %s", ptr->member); + + av[0] = ptr->member; + call_args[0] = (char *)ldap_handle; + call_args[1] = dn_path; + call_args[2] = ""; + call_args[3] = NULL; + callback_rc = 0; + + if (rc = mr_query("get_user_account_by_login", 1, av, + save_query_info, save_argv)) + { + com_err(whoami, 0, "Unable to create user %s " + "while populating group %s.", ptr->member, + group_name); + + return(3); + } + + if (rc = user_create(U_END, save_argv, call_args)) + { + com_err(whoami, 0, "Unable to create user %s " + "while populating group %s.", ptr->member, + group_name); + + return(3); + } + + if (callback_rc) + { + com_err(whoami, 0, "Unable to create user %s " + "while populating group %s", ptr->member, + group_name); + + return(3); + } + } + + pUserOu = user_ou; + + if(ActiveDirectory) + { + sprintf(member, "cn=%s,%s,%s", ptr->member, pUserOu, + dn_path); + } + else + { + sprintf(member, "uid=%s,%s,%s", ptr->member, pUserOu, + dn_path); + } + + } + else if (!strcasecmp(ptr->type, "STRING")) + { + if (contact_create(ldap_handle, dn_path, ptr->member, + contact_ou)) + return(3); + + pUserOu = contact_ou; + sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), + pUserOu, dn_path); + } + else if (!strcasecmp(ptr->type, "KERBEROS")) + { + if (contact_create(ldap_handle, dn_path, ptr->member, + kerberos_ou)) + return(3); + + pUserOu = kerberos_ou; + sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), + pUserOu, dn_path); + } + + if(i > 1) + members = (char **)realloc(members, ((i + 2) * sizeof(char *))); + members[i++] = strdup(member); + + ptr = ptr->next; + } + + linklist_free(member_base); + member_base = NULL; + } + + members[i] = NULL; + + n = 0; + ADD_ATTR("member", members, LDAP_MOD_REPLACE); + mods[n] = NULL; + + sprintf(group_dn, "cn=%s,%s,%s", group_name, group_ou, dn_path); + + if ((rc = ldap_modify_s(ldap_handle, group_dn, + mods)) != LDAP_SUCCESS) + { + com_err(whoami, 0, + "Unable to populate group membership for %s: %s", + group_dn, ldap_err2string(rc)); + } + + for (i = 0; i < n; i++) + free(mods[i]); + + free(members); + + return(0); +} + +int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, + char *group_name, char *group_ou, char *group_membership, + int group_security_flag, int type, char *maillist) +{ + char before_desc[512]; + char before_name[256]; + char before_group_ou[256]; + char before_group_membership[2]; + char distinguishedName[256]; + char ad_distinguishedName[256]; + char filter[128]; + char *attr_array[3]; + int before_security_flag; + int group_count; + int rc; + LK_ENTRY *group_base; + LK_ENTRY *ptr; + char ou_both[512]; + char ou_security[512]; + char ou_distribution[512]; + char ou_neither[512]; + char group_dn[512]; + + memset(ad_distinguishedName, '\0', sizeof(ad_distinguishedName)); + sprintf(distinguishedName, "CN=%s,%s,%s", group_name, group_ou, dn_path); + + memset(filter, '\0', sizeof(filter)); + group_base = NULL; + group_count = 0; + + if (rc = ad_get_group(ldap_handle, dn_path, group_name, + "*", MoiraId, + "samAccountName", &group_base, + &group_count, filter)) + return(rc); + + if (type == CHECK_GROUPS) + { + if (group_count == 1) + { + strcpy(group_dn, group_base->dn); + + if (!strcasecmp(group_dn, distinguishedName)) + { + linklist_free(group_base); + return(0); + } + } + + linklist_free(group_base); + + if (group_count == 0) + return(AD_NO_GROUPS_FOUND); + + if (group_count == 1) + return(AD_WRONG_GROUP_DN_FOUND); + + return(AD_MULTIPLE_GROUPS_FOUND); + } + + if (group_count == 0) + { + return(AD_NO_GROUPS_FOUND); + } + + if (group_count > 1) + { + ptr = group_base; + + strcpy(group_dn, ptr->dn); + + while (ptr != NULL) + { + if (!strcasecmp(group_dn, ptr->value)) + break; + + ptr = ptr->next; + } + + if (ptr == NULL) + { + com_err(whoami, 0, "%d groups with moira id = %s", group_count, + MoiraId); + ptr = group_base; + + while (ptr != NULL) + { + com_err(whoami, 0, "%s with moira id = %s", ptr->value, MoiraId); + ptr = ptr->next; + } + + linklist_free(group_base); + return(AD_MULTIPLE_GROUPS_FOUND); + } + + ptr = group_base; + + while (ptr != NULL) + { + strcpy(group_dn, ptr->dn); + + if (strcasecmp(group_dn, ptr->value)) + rc = ldap_delete_s(ldap_handle, ptr->value); + + ptr = ptr->next; + } + + linklist_free(group_base); + memset(filter, '\0', sizeof(filter)); + group_base = NULL; + group_count = 0; + + if (rc = ad_get_group(ldap_handle, dn_path, group_name, + "*", MoiraId, + "samAccountName", &group_base, + &group_count, filter)) + return(rc); + + if (group_count == 0) + return(AD_NO_GROUPS_FOUND); + + if (group_count > 1) + return(AD_MULTIPLE_GROUPS_FOUND); + } + + strcpy(ad_distinguishedName, group_base->dn); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + attr_array[0] = "sAMAccountName"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s", + MoiraId, ldap_err2string(rc)); + return(rc); + } + + sprintf(filter, "(sAMAccountName=%s)", group_base->value); + + if (!strcasecmp(ad_distinguishedName, distinguishedName)) + { + linklist_free(group_base); + group_base = NULL; + group_count = 0; + return(0); + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + memset(ou_both, '\0', sizeof(ou_both)); + memset(ou_security, '\0', sizeof(ou_security)); + memset(ou_distribution, '\0', sizeof(ou_distribution)); + memset(ou_neither, '\0', sizeof(ou_neither)); + memset(before_name, '\0', sizeof(before_name)); + memset(before_desc, '\0', sizeof(before_desc)); + memset(before_group_membership, '\0', sizeof(before_group_membership)); + + attr_array[0] = "name"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to get list name with MoiraId = %s: %s", + MoiraId, ldap_err2string(rc)); + return(rc); + } + + strcpy(before_name, group_base->value); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + attr_array[0] = "description"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, + "Unable to get list description with MoiraId = %s: %s", + MoiraId, ldap_err2string(rc)); + return(rc); + } + + if (group_count != 0) + { + strcpy(before_desc, group_base->value); + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + + change_to_lower_case(ad_distinguishedName); + strcpy(ou_both, group_ou_both); + change_to_lower_case(ou_both); + strcpy(ou_security, group_ou_security); + change_to_lower_case(ou_security); + strcpy(ou_distribution, group_ou_distribution); + change_to_lower_case(ou_distribution); + strcpy(ou_neither, group_ou_neither); + change_to_lower_case(ou_neither); + + if (strstr(ad_distinguishedName, ou_both)) + { + strcpy(before_group_ou, group_ou_both); + before_group_membership[0] = 'B'; + before_security_flag = 1; + } + else if (strstr(ad_distinguishedName, ou_security)) + { + strcpy(before_group_ou, group_ou_security); + before_group_membership[0] = 'S'; + before_security_flag = 1; + } + else if (strstr(ad_distinguishedName, ou_distribution)) + { + strcpy(before_group_ou, group_ou_distribution); + before_group_membership[0] = 'D'; + before_security_flag = 0; + } + else if (strstr(ad_distinguishedName, ou_neither)) + { + strcpy(before_group_ou, group_ou_neither); + before_group_membership[0] = 'N'; + before_security_flag = 0; + } + else + return(AD_NO_OU_FOUND); + + rc = group_rename(ldap_handle, dn_path, before_name, + before_group_membership, + before_group_ou, before_security_flag, before_desc, + group_name, group_membership, group_ou, + group_security_flag, + before_desc, MoiraId, filter, maillist); + + return(rc); +} + +void change_to_lower_case(char *ptr) +{ + int i; + + for (i = 0; i < (int)strlen(ptr); i++) + { + ptr[i] = tolower(ptr[i]); + } +} + +int ad_get_group(LDAP *ldap_handle, char *dn_path, + char *group_name, char *group_membership, + char *MoiraId, char *attribute, + LK_ENTRY **linklist_base, int *linklist_count, + char *rFilter) +{ + LK_ENTRY *pPtr; + char filter[128]; + char *attr_array[3]; + char *dn; + int rc; + + (*linklist_base) = NULL; + (*linklist_count) = 0; + + if (strlen(rFilter) != 0) + { + strcpy(filter, rFilter); + attr_array[0] = attribute; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + linklist_base, linklist_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s", + MoiraId, ldap_err2string(rc)); + return(rc); + } + + if ((*linklist_count) == 1) + { + strcpy(rFilter, filter); + return(0); + } + } + + linklist_free((*linklist_base)); + (*linklist_base) = NULL; + (*linklist_count) = 0; + + if (strlen(MoiraId) != 0) + { + sprintf(filter, "(&(objectClass=group)(mitMoiraId=%s))", MoiraId); + + attr_array[0] = attribute; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + linklist_base, linklist_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s", + MoiraId, ldap_err2string(rc)); + return(rc); + } + } + + if ((*linklist_count) > 1) + { + com_err(whoami, 0, "multiple groups with mitMoiraId = %s", MoiraId); + pPtr = (*linklist_base); + + while (pPtr) + { + com_err(whoami, 0, "groups %s has mitMoiraId = %s", pPtr->value, + MoiraId); + pPtr = pPtr->next; + } + + linklist_free((*linklist_base)); + (*linklist_base) = NULL; + (*linklist_count) = 0; + } + + if ((*linklist_count) == 1) + { + + pPtr = (*linklist_base); + dn = strdup(pPtr->dn); + dn += 3; + + if (!memcmp(dn, group_name, strlen(group_name))) + { + strcpy(rFilter, filter); + return(0); + } + } + + linklist_free((*linklist_base)); + (*linklist_base) = NULL; + (*linklist_count) = 0; + sprintf(filter, "(sAMAccountName=%s%s)", group_name, group_suffix); + + attr_array[0] = attribute; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + linklist_base, linklist_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s", + MoiraId, ldap_err2string(rc)); + return(rc); + } + + if ((*linklist_count) == 1) + { + strcpy(rFilter, filter); + return(0); + } + + return(0); +} + +int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, char *MoiraId) +{ + char filter[128]; + char *attr_array[3]; + char SamAccountName[64]; + int group_count; + int rc; + LK_ENTRY *group_base; + LK_ENTRY *gPtr; + + group_count = 0; + group_base = NULL; + + if (strlen(MoiraId) != 0) + { + sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId); + + attr_array[0] = "sAMAccountName"; + attr_array[1] = NULL; + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process user %s : %s", + UserName, ldap_err2string(rc)); + return(rc); + } + + if (group_count > 1) + { + com_err(whoami, 0, "multiple users exist with MoiraId = %s", + MoiraId); + gPtr = group_base; + + while (gPtr) + { + com_err(whoami, 0, "user %s exist with MoiraId = %s", + gPtr->value, MoiraId); + gPtr = gPtr->next; + } + } + } + + if (group_count != 1) + { + linklist_free(group_base); + group_count = 0; + group_base = NULL; + sprintf(filter, "(sAMAccountName=%s)", UserName); + attr_array[0] = "sAMAccountName"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process user %s : %s", + UserName, ldap_err2string(rc)); + return(rc); + } + } + + if (group_count != 1) + { + linklist_free(group_base); + return(AD_NO_USER_FOUND); + } + + strcpy(SamAccountName, group_base->value); + linklist_free(group_base); + group_count = 0; + rc = 0; + + if (strcmp(SamAccountName, UserName)) + { + rc = user_rename(ldap_handle, dn_path, SamAccountName, + UserName); + } + + return(0); +} + +void container_get_dn(char *src, char *dest) +{ + char *sPtr; + char *array[20]; + char name[256]; + int n; + + memset(array, '\0', 20 * sizeof(array[0])); + + if (strlen(src) == 0) + return; + + strcpy(name, src); + sPtr = name; + n = 0; + array[n] = name; + ++n; + + while (*sPtr) + { + if ((*sPtr) == '/') + { + (*sPtr) = '\0'; + ++sPtr; + array[n] = sPtr; + ++n; + } + else + ++sPtr; + } + + strcpy(dest, "OU="); + + while (n != 0) + { + strcat(dest, array[n-1]); + --n; + if (n > 0) + { + strcat(dest, ",OU="); + } + } + + return; +} + +void container_get_name(char *src, char *dest) +{ + char *sPtr; + char *dPtr; + + if (strlen(src) == 0) + return; + + sPtr = src; + dPtr = src; + + while (*sPtr) + { + if ((*sPtr) == '/') + { + dPtr = sPtr; + ++dPtr; + } + ++sPtr; + } + + strcpy(dest, dPtr); + return; +} + +void container_check(LDAP *ldap_handle, char *dn_path, char *name) +{ + char cName[256]; + char *av[7]; + int i; + int rc; + + strcpy(cName, name); + + for (i = 0; i < (int)strlen(cName); i++) + { + if (cName[i] == '/') + { + cName[i] = '\0'; + av[CONTAINER_NAME] = cName; + av[CONTAINER_DESC] = ""; + av[CONTAINER_LOCATION] = ""; + av[CONTAINER_CONTACT] = ""; + av[CONTAINER_TYPE] = ""; + av[CONTAINER_ID] = ""; + av[CONTAINER_ROWID] = ""; + rc = container_create(ldap_handle, dn_path, 7, av); + + if (rc == LDAP_SUCCESS) + { + com_err(whoami, 0, "container %s created without a mitMoiraId", + cName); + } + + cName[i] = '/'; + } + } +} + +int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, + char **before, int afterc, char **after) +{ + char dName[256]; + char cName[256]; + char new_cn[128]; + char new_dn_path[256]; + char temp[256]; + char distinguishedName[256]; + char *pPtr; + int rc; + int i; + + memset(cName, '\0', sizeof(cName)); + container_get_name(after[CONTAINER_NAME], cName); + + if (!check_container_name(cName)) + { + com_err(whoami, 0, "Unable to process invalid LDAP container name %s", + cName); + return(AD_INVALID_NAME); + } + + memset(distinguishedName, '\0', sizeof(distinguishedName)); + + if (rc = container_get_distinguishedName(ldap_handle, dn_path, + distinguishedName, beforec, before)) + return(rc); + + if (strlen(distinguishedName) == 0) + { + rc = container_create(ldap_handle, dn_path, afterc, after); + return(rc); + } + + strcpy(temp, after[CONTAINER_NAME]); + pPtr = temp; + + for (i = 0; i < (int)strlen(temp); i++) + { + if (temp[i] == '/') + { + pPtr = &temp[i]; + } + } + + (*pPtr) = '\0'; + + container_get_dn(temp, dName); + + if (strlen(temp) != 0) + sprintf(new_dn_path, "%s,%s", dName, dn_path); + else + sprintf(new_dn_path, "%s", dn_path); + + sprintf(new_cn, "OU=%s", cName); + + container_check(ldap_handle, dn_path, after[CONTAINER_NAME]); + + if ((rc = ldap_rename_s(ldap_handle, distinguishedName, new_cn, new_dn_path, + TRUE, NULL, NULL)) != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to rename container from %s to %s : %s", + before[CONTAINER_NAME], after[CONTAINER_NAME], + ldap_err2string(rc)); + return(rc); + } + + memset(dName, '\0', sizeof(dName)); + container_get_dn(after[CONTAINER_NAME], dName); + rc = container_adupdate(ldap_handle, dn_path, dName, "", afterc, after); + + return(rc); +} + +int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av) +{ + char distinguishedName[256]; + int rc; + + memset(distinguishedName, '\0', sizeof(distinguishedName)); + + if (rc = container_get_distinguishedName(ldap_handle, dn_path, + distinguishedName, count, av)) + return(rc); + + if (strlen(distinguishedName) == 0) + return(0); + + if ((rc = ldap_delete_s(ldap_handle, distinguishedName)) != LDAP_SUCCESS) + { + if (rc == LDAP_NOT_ALLOWED_ON_NONLEAF) + container_move_objects(ldap_handle, dn_path, distinguishedName); + else + com_err(whoami, 0, "Unable to delete container %s from AD : %s", + av[CONTAINER_NAME], ldap_err2string(rc)); + } + + return(rc); +} + +int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av) +{ + char *attr_array[3]; + LK_ENTRY *group_base; + int group_count; + LDAPMod *mods[20]; + char *objectClass_v[] = {"top", + "organizationalUnit", + NULL}; + + char *ou_v[] = {NULL, NULL}; + char *name_v[] = {NULL, NULL}; + char *moiraId_v[] = {NULL, NULL}; + char *desc_v[] = {NULL, NULL}; + char *managedBy_v[] = {NULL, NULL}; + char dName[256]; + char cName[256]; + char managedByDN[256]; + char filter[256]; + char temp[256]; + int n; + int i; + int rc; + + memset(filter, '\0', sizeof(filter)); + memset(dName, '\0', sizeof(dName)); + memset(cName, '\0', sizeof(cName)); + memset(managedByDN, '\0', sizeof(managedByDN)); + container_get_dn(av[CONTAINER_NAME], dName); + container_get_name(av[CONTAINER_NAME], cName); + + if ((strlen(cName) == 0) || (strlen(dName) == 0)) + { + com_err(whoami, 0, "Unable to process invalid LDAP container name %s", + cName); + return(AD_INVALID_NAME); + } + + if (!check_container_name(cName)) + { + com_err(whoami, 0, "Unable to process invalid LDAP container name %s", + cName); + return(AD_INVALID_NAME); + } + + n = 0; + ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD); + name_v[0] = cName; + ADD_ATTR("name", name_v, LDAP_MOD_ADD); + ou_v[0] = cName; + ADD_ATTR("ou", ou_v, LDAP_MOD_ADD); + + if (strlen(av[CONTAINER_ROWID]) != 0) + { + moiraId_v[0] = av[CONTAINER_ROWID]; + ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_ADD); + } + + if (strlen(av[CONTAINER_DESC]) != 0) + { + desc_v[0] = av[CONTAINER_DESC]; + ADD_ATTR("description", desc_v, LDAP_MOD_ADD); + } + + if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0)) + { + if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS")) + { + if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], + kerberos_ou)) + { + sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], + kerberos_ou, dn_path); + managedBy_v[0] = managedByDN; + ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD); + } + } + else + { + if (!strcasecmp(av[CONTAINER_TYPE], "USER")) + { + sprintf(filter, "(&(cn=%s)(&(objectCategory=person)" + "(objectClass=user)))", av[CONTAINER_ID]); + } + + if (!strcasecmp(av[CONTAINER_TYPE], "LIST")) + { + sprintf(filter, "(&(objectClass=group)(cn=%s))", + av[CONTAINER_ID]); + } + + if (strlen(filter) != 0) + { + attr_array[0] = "distinguishedName"; + attr_array[1] = NULL; + group_count = 0; + group_base = NULL; + if ((rc = linklist_build(ldap_handle, dn_path, filter, + attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS) + { + if (group_count == 1) + { + strcpy(managedByDN, group_base->value); + managedBy_v[0] = managedByDN; + ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD); + } + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + } + } + } + + mods[n] = NULL; + + sprintf(temp, "%s,%s", dName, dn_path); + rc = ldap_add_ext_s(ldap_handle, temp, mods, NULL, NULL); + + for (i = 0; i < n; i++) + free(mods[i]); + + if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS)) + { + com_err(whoami, 0, "Unable to create container %s : %s", + cName, ldap_err2string(rc)); + return(rc); + } + + if (rc == LDAP_ALREADY_EXISTS) + { + if (strlen(av[CONTAINER_ROWID]) != 0) + rc = container_adupdate(ldap_handle, dn_path, dName, "", count, av); + } + + return(rc); +} + +int container_update(LDAP *ldap_handle, char *dn_path, int beforec, + char **before, int afterc, char **after) +{ + char distinguishedName[256]; + int rc; + + memset(distinguishedName, '\0', sizeof(distinguishedName)); + + if (rc = container_get_distinguishedName(ldap_handle, dn_path, + distinguishedName, afterc, after)) + return(rc); + + if (strlen(distinguishedName) == 0) + { + rc = container_create(ldap_handle, dn_path, afterc, after); + return(rc); + } + + container_check(ldap_handle, dn_path, after[CONTAINER_NAME]); + rc = container_adupdate(ldap_handle, dn_path, "", distinguishedName, afterc, + after); + + return(rc); +} + +int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, + char *distinguishedName, int count, + char **av) +{ + char *attr_array[3]; + LK_ENTRY *group_base; + int group_count; + char dName[256]; + char cName[256]; + char filter[512]; + int rc; + + memset(filter, '\0', sizeof(filter)); + memset(dName, '\0', sizeof(dName)); + memset(cName, '\0', sizeof(cName)); + container_get_dn(av[CONTAINER_NAME], dName); + container_get_name(av[CONTAINER_NAME], cName); + + if (strlen(dName) == 0) + { + com_err(whoami, 0, "Unable to process invalid LDAP container name %s", + av[CONTAINER_NAME]); + return(AD_INVALID_NAME); + } + + if (!check_container_name(cName)) + { + com_err(whoami, 0, "Unable to process invalid LDAP container name %s", + cName); + return(AD_INVALID_NAME); + } + + sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", + av[CONTAINER_ROWID]); + attr_array[0] = "distinguishedName"; + attr_array[1] = NULL; + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS) + { + if (group_count == 1) + { + strcpy(distinguishedName, group_base->value); + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + + if (strlen(distinguishedName) == 0) + { + sprintf(filter, "(&(objectClass=organizationalUnit)" + "(distinguishedName=%s,%s))", dName, dn_path); + attr_array[0] = "distinguishedName"; + attr_array[1] = NULL; + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS) + { + if (group_count == 1) + { + strcpy(distinguishedName, group_base->value); + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + } + + return(0); +} + +int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, + char *distinguishedName, int count, char **av) +{ + char *attr_array[5]; + LK_ENTRY *group_base; + LK_ENTRY *pPtr; + LDAPMod *mods[20]; + int group_count; + char filter[512]; + char *moiraId_v[] = {NULL, NULL}; + char *desc_v[] = {NULL, NULL}; + char *managedBy_v[] = {NULL, NULL}; + char managedByDN[256]; + char moiraId[64]; + char desc[256]; + char ad_path[512]; + int rc; + int i; + int n; + + + strcpy(ad_path, distinguishedName); + + if (strlen(dName) != 0) + sprintf(ad_path, "%s,%s", dName, dn_path); + + sprintf(filter, "(&(objectClass=organizationalUnit)(distinguishedName=%s))", + ad_path); + + if (strlen(av[CONTAINER_ID]) != 0) + sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", + av[CONTAINER_ROWID]); + + attr_array[0] = "mitMoiraId"; + attr_array[1] = "description"; + attr_array[2] = "managedBy"; + attr_array[3] = NULL; + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to retreive container info for %s : %s", + av[CONTAINER_NAME], ldap_err2string(rc)); + return(rc); + } + + memset(managedByDN, '\0', sizeof(managedByDN)); + memset(moiraId, '\0', sizeof(moiraId)); + memset(desc, '\0', sizeof(desc)); + pPtr = group_base; + + while (pPtr) + { + if (!strcasecmp(pPtr->attribute, "description")) + strcpy(desc, pPtr->value); + else if (!strcasecmp(pPtr->attribute, "managedBy")) + strcpy(managedByDN, pPtr->value); + else if (!strcasecmp(pPtr->attribute, "mitMoiraId")) + strcpy(moiraId, pPtr->value); + pPtr = pPtr->next; + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + + n = 0; + if (strlen(av[CONTAINER_ROWID]) != 0) + { + moiraId_v[0] = av[CONTAINER_ROWID]; + ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_REPLACE); + } + + if (strlen(av[CONTAINER_DESC]) != 0) + { + attribute_update(ldap_handle, ad_path, av[CONTAINER_DESC], "description", + dName); + } + else + { + if (strlen(desc) != 0) + { + attribute_update(ldap_handle, ad_path, "", "description", dName); + } + } + + if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0)) + { + if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS")) + { + if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], + kerberos_ou)) + { + sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], + kerberos_ou, dn_path); + managedBy_v[0] = managedByDN; + ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE); + } + else + { + if (strlen(managedByDN) != 0) + { + attribute_update(ldap_handle, ad_path, "", "managedBy", + dName); + } + } + } + else + { + memset(filter, '\0', sizeof(filter)); + + if (!strcasecmp(av[CONTAINER_TYPE], "USER")) + { + sprintf(filter, "(&(cn=%s)(&(objectCategory=person)" + "(objectClass=user)))", av[CONTAINER_ID]); + } + + if (!strcasecmp(av[CONTAINER_TYPE], "LIST")) + { + sprintf(filter, "(&(objectClass=group)(cn=%s))", + av[CONTAINER_ID]); + } + + if (strlen(filter) != 0) + { + attr_array[0] = "distinguishedName"; + attr_array[1] = NULL; + group_count = 0; + group_base = NULL; + if ((rc = linklist_build(ldap_handle, dn_path, filter, + attr_array, &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS) + { + if (group_count == 1) + { + strcpy(managedByDN, group_base->value); + managedBy_v[0] = managedByDN; + ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE); + } + else + { + if (strlen(managedByDN) != 0) + { + attribute_update(ldap_handle, ad_path, "", + "managedBy", dName); + } + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + } + else + { + if (strlen(managedByDN) != 0) + { + attribute_update(ldap_handle, ad_path, "", "managedBy", + dName); + } + } + } + } + + mods[n] = NULL; + + if (n == 0) + return(LDAP_SUCCESS); + + rc = ldap_modify_s(ldap_handle, ad_path, mods); + + for (i = 0; i < n; i++) + free(mods[i]); + + if (rc != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to modify container info for %s : %s", + av[CONTAINER_NAME], ldap_err2string(rc)); + return(rc); + } + + return(rc); +} + +int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName) +{ + char *attr_array[3]; + LK_ENTRY *group_base; + LK_ENTRY *pPtr; + int group_count; + char filter[512]; + char new_cn[128]; + char temp[256]; + int rc; + int NumberOfEntries = 10; + int i; + int count; + + rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, &NumberOfEntries); + + for (i = 0; i < 3; i++) + { + memset(filter, '\0', sizeof(filter)); + + if (i == 0) + { + strcpy(filter, "(!(|(objectClass=computer)" + "(objectClass=organizationalUnit)))"); + attr_array[0] = "cn"; + attr_array[1] = NULL; + } + else if (i == 1) + { + strcpy(filter, "(objectClass=computer)"); + attr_array[0] = "cn"; + attr_array[1] = NULL; + } + else + { + strcpy(filter, "(objectClass=organizationalUnit)"); + attr_array[0] = "ou"; + attr_array[1] = NULL; + } + + while (1) + { + if ((rc = linklist_build(ldap_handle, dName, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS) + { + break; + } + + if (group_count == 0) + break; + + pPtr = group_base; + + while(pPtr) + { + if (!strcasecmp(pPtr->attribute, "cn")) + { + sprintf(new_cn, "cn=%s", pPtr->value); + if (i == 0) + sprintf(temp, "%s,%s", orphans_other_ou, dn_path); + if (i == 1) + sprintf(temp, "%s,%s", orphans_machines_ou, dn_path); + count = 1; + + while (1) + { + rc = ldap_rename_s(ldap_handle, pPtr->dn, new_cn, temp, + TRUE, NULL, NULL); + if (rc == LDAP_ALREADY_EXISTS) + { + sprintf(new_cn, "cn=%s_%d", pPtr->value, count); + ++count; + } + else + break; + } + } + else if (!strcasecmp(pPtr->attribute, "ou")) + { + rc = ldap_delete_s(ldap_handle, pPtr->dn); + } + + pPtr = pPtr->next; + } + + linklist_free(group_base); + group_base = NULL; + group_count = 0; + } + } + + return(0); +} + +int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, + char *machine_ou, char *NewMachineName) +{ + LK_ENTRY *group_base; + int group_count; + int i; + char filter[128]; + char *attr_array[3]; + char cn[256]; + char dn[256]; + char temp[256]; + char *pPtr; + int rc; + + strcpy(NewMachineName, member); + rc = moira_connect(); + rc = GetMachineName(NewMachineName); + moira_disconnect(); + + if (strlen(NewMachineName) == 0) + { + com_err(whoami, 0, "Unable to find alais for machine %s in Moira", + member); + return(1); + } + + pPtr = NULL; + pPtr = strchr(NewMachineName, '.'); + + if (pPtr != NULL) + (*pPtr) = '\0'; + + group_base = NULL; + group_count = 0; + sprintf(filter, "(sAMAccountName=%s$)", NewMachineName); + attr_array[0] = "cn"; + attr_array[1] = NULL; + sprintf(temp, "%s", dn_path); + + if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process machine %s : %s", + member, ldap_err2string(rc)); + return(1); + } + + if (group_count != 1) + { + com_err(whoami, 0, + "Unable to process machine %s : machine not found in AD", + NewMachineName); + return(1); + } + + strcpy(dn, group_base->dn); + strcpy(cn, group_base->value); + + for (i = 0; i < (int)strlen(dn); i++) + dn[i] = tolower(dn[i]); + + for (i = 0; i < (int)strlen(cn); i++) + cn[i] = tolower(cn[i]); + + linklist_free(group_base); + pPtr = NULL; + pPtr = strstr(dn, cn); + + if (pPtr == NULL) + { + com_err(whoami, 0, "Unable to process machine %s", + member); + return(1); + } + + pPtr += strlen(cn) + 1; + strcpy(machine_ou, pPtr); + pPtr = NULL; + pPtr = strstr(machine_ou, "dc="); + + if (pPtr == NULL) + { + com_err(whoami, 0, "Unable to process machine %s", + member); + return(1); + } + + --pPtr; + (*pPtr) = '\0'; + + return(0); +} + +int machine_move_to_ou(LDAP *ldap_handle, char * dn_path, + char *MoiraMachineName, char *DestinationOu) +{ + char NewCn[128]; + char OldDn[512]; + char MachineName[128]; + char filter[128]; + char *attr_array[3]; + char NewOu[256]; + char *cPtr = NULL; + int group_count; + long rc; + LK_ENTRY *group_base; + + group_count = 0; + group_base = NULL; + + strcpy(MachineName, MoiraMachineName); + rc = GetMachineName(MachineName); + + if (strlen(MachineName) == 0) + { + com_err(whoami, 0, "Unable to find alais for machine %s in Moira", + MoiraMachineName); + return(1); + } + + cPtr = strchr(MachineName, '.'); + + if (cPtr != NULL) + (*cPtr) = '\0'; + + sprintf(filter, "(sAMAccountName=%s$)", MachineName); + attr_array[0] = "sAMAccountName"; + attr_array[1] = NULL; + + if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, + &group_base, + &group_count, LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to process machine %s : %s", + MoiraMachineName, ldap_err2string(rc)); + return(1); + } + + if (group_count == 1) + strcpy(OldDn, group_base->dn); + + linklist_free(group_base); + group_base = NULL; + + if (group_count != 1) + { + com_err(whoami, 0, "Unable to find machine %s in AD: %s", + MoiraMachineName); + return(1); + } + + sprintf(NewOu, "%s,%s", DestinationOu, dn_path); + cPtr = strchr(OldDn, ','); + + if (cPtr != NULL) + { + ++cPtr; + if (!strcasecmp(cPtr, NewOu)) + return(0); + } + + sprintf(NewCn, "CN=%s", MachineName); + rc = ldap_rename_s(ldap_handle, OldDn, NewCn, NewOu, TRUE, NULL, NULL); + + return(rc); +} + +int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name) +{ + char Name[128]; + char *pPtr; + int rc; + + memset(Name, '\0', sizeof(Name)); + strcpy(Name, machine_name); + pPtr = NULL; + pPtr = strchr(Name, '.'); + + if (pPtr != NULL) + (*pPtr) = '\0'; + + strcat(Name, "$"); + return(!(rc = checkADname(ldap_handle, dn_path, Name))); +} + +int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, + char *machine_name, char *container_name) +{ + int rc; + char *av[2]; + char *call_args[2]; + + av[0] = machine_name; + call_args[0] = (char *)container_name; + rc = mr_query("get_machine_to_container_map", 1, av, + machine_GetMoiraContainer, call_args); + return(rc); +} + +int machine_GetMoiraContainer(int ac, char **av, void *ptr) +{ + char **call_args; + + call_args = ptr; + strcpy(call_args[0], av[1]); + return(0); +} + +int Moira_container_group_create(char **after) +{ + long rc; + char GroupName[64]; + char *argv[20]; + + memset(GroupName, '\0', sizeof(GroupName)); + rc = Moira_groupname_create(GroupName, after[CONTAINER_NAME], + after[CONTAINER_ROWID]); + if (rc) + return rc; + + argv[L_NAME] = GroupName; + argv[L_ACTIVE] = "1"; + argv[L_PUBLIC] = "0"; + argv[L_HIDDEN] = "0"; + argv[L_MAILLIST] = "0"; + argv[L_GROUP] = "1"; + argv[L_GID] = UNIQUE_GID; + argv[L_NFSGROUP] = "0"; + argv[L_MAILMAN] = "0"; + argv[L_MAILMAN_SERVER] = "[NONE]"; + argv[L_DESC] = "auto created container group"; + argv[L_ACE_TYPE] = "USER"; + argv[L_MEMACE_TYPE] = "USER"; + argv[L_ACE_NAME] = "sms"; + argv[L_MEMACE_NAME] = "sms"; + + if (rc = mr_query("add_list", 15, argv, NULL, NULL)) + { + com_err(whoami, 0, + "Unable to create container group %s for container %s: %s", + GroupName, after[CONTAINER_NAME], error_message(rc)); + } + + Moira_setContainerGroup(after[CONTAINER_NAME], GroupName); + Moira_addGroupToParent(after[CONTAINER_NAME], GroupName); + + return(rc); +} + +int Moira_container_group_update(char **before, char **after) +{ + long rc; + char BeforeGroupName[64]; + char AfterGroupName[64]; + char *argv[20]; + + if (!strcasecmp(after[CONTAINER_NAME], before[CONTAINER_NAME])) + return(0); + + memset(BeforeGroupName, '\0', sizeof(BeforeGroupName)); + Moira_getGroupName(after[CONTAINER_NAME], BeforeGroupName, 0); + if (strlen(BeforeGroupName) == 0) + return(0); + + memset(AfterGroupName, '\0', sizeof(AfterGroupName)); + rc = Moira_groupname_create(AfterGroupName, after[CONTAINER_NAME], + after[CONTAINER_ROWID]); + if (rc) + return rc; + + if (strcasecmp(BeforeGroupName, AfterGroupName)) + { + argv[L_NAME] = BeforeGroupName; + argv[L_NAME + 1] = AfterGroupName; + argv[L_ACTIVE + 1] = "1"; + argv[L_PUBLIC + 1] = "0"; + argv[L_HIDDEN + 1] = "0"; + argv[L_MAILLIST + 1] = "0"; + argv[L_GROUP + 1] = "1"; + argv[L_GID + 1] = UNIQUE_GID; + argv[L_NFSGROUP + 1] = "0"; + argv[L_MAILMAN + 1] = "0"; + argv[L_MAILMAN_SERVER + 1] = "[NONE]"; + argv[L_DESC + 1] = "auto created container group"; + argv[L_ACE_TYPE + 1] = "USER"; + argv[L_MEMACE_TYPE + 1] = "USER"; + argv[L_ACE_NAME + 1] = "sms"; + argv[L_MEMACE_NAME + 1] = "sms"; + + if (rc = mr_query("update_list", 16, argv, NULL, NULL)) + { + com_err(whoami, 0, + "Unable to rename container group from %s to %s: %s", + BeforeGroupName, AfterGroupName, error_message(rc)); + } + } + + return(rc); +} + +int Moira_container_group_delete(char **before) +{ + long rc = 0; + char *argv[13]; + char GroupName[64]; + char ParentGroupName[64]; + + memset(ParentGroupName, '\0', sizeof(ParentGroupName)); + Moira_getGroupName(before[CONTAINER_NAME], ParentGroupName, 1); + + memset(GroupName, '\0', sizeof(GroupName)); + + if (strcmp(before[CONTAINER_GROUP_NAME], "[none]")) + strcpy(GroupName, before[CONTAINER_GROUP_NAME]); + + if ((strlen(ParentGroupName) != 0) && (strlen(GroupName) != 0)) + { + argv[0] = ParentGroupName; + argv[1] = "LIST"; + argv[2] = GroupName; + + if (rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL)) + { + com_err(whoami, 0, + "Unable to delete container group %s from list: %s", + GroupName, ParentGroupName, error_message(rc)); + } + } + + if (strlen(GroupName) != 0) + { + argv[0] = GroupName; + + if (rc = mr_query("delete_list", 1, argv, NULL, NULL)) + { + com_err(whoami, 0, "Unable to delete container group %s : %s", + GroupName, error_message(rc)); + } + } + + return(rc); +} + +int Moira_groupname_create(char *GroupName, char *ContainerName, + char *ContainerRowID) +{ + char *ptr; + char *ptr1; + char temp[64]; + char newGroupName[64]; + char tempGroupName[64]; + char tempgname[64]; + char *argv[1]; + int i; + long rc; + + strcpy(temp, ContainerName); + + ptr1 = strrchr(temp, '/'); + + if (ptr1 != NULL) + { + *ptr1 = '\0'; + ptr = ++ptr1; + ptr1 = strrchr(temp, '/'); + + if (ptr1 != NULL) + { + sprintf(tempgname, "%s-%s", ++ptr1, ptr); + } + else + strcpy(tempgname, ptr); + } + else + strcpy(tempgname, temp); + + if (strlen(tempgname) > 25) + tempgname[25] ='\0'; + + sprintf(newGroupName, "cnt-%s", tempgname); + + /* change everything to lower case */ + ptr = newGroupName; + + while (*ptr) + { + if (isupper(*ptr)) + *ptr = tolower(*ptr); + + if (*ptr == ' ') + *ptr = '-'; + + ptr++; + } + + strcpy(tempGroupName, newGroupName); + i = (int)'0'; + + /* append 0-9 then a-z if a duplicate is found */ + while(1) + { + argv[0] = newGroupName; + + if (rc = mr_query("get_list_info", 1, argv, NULL, NULL)) + { + if (rc == MR_NO_MATCH) + break; + com_err(whoami, 0, "Moira error while creating group name for " + "container %s : %s", ContainerName, error_message(rc)); + return rc; + } + + sprintf(newGroupName, "%s-%c", tempGroupName, i); + + if (i == (int)'z') + { + com_err(whoami, 0, "Unable to find a unique group name for " + "container %s: too many duplicate container names", + ContainerName); + return 1; + } + + if (i == '9') + i = 'a'; + else + i++; + } + + strcpy(GroupName, newGroupName); + return(0); +} + +int Moira_setContainerGroup(char *origContainerName, char *GroupName) +{ + long rc; + char *argv[3]; + + argv[0] = origContainerName; + argv[1] = GroupName; + + if ((rc = mr_query("set_container_list", 2, argv, NULL, NULL))) + { + com_err(whoami, 0, + "Unable to set container group %s in container %s: %s", + GroupName, origContainerName, error_message(rc)); + } + + return(0); +} + +int Moira_addGroupToParent(char *origContainerName, char *GroupName) + { + char ContainerName[64]; + char ParentGroupName[64]; + char *argv[3]; + long rc; + + strcpy(ContainerName, origContainerName); + + Moira_getGroupName(ContainerName, ParentGroupName, 1); + + /* top-level container */ + if (strlen(ParentGroupName) == 0) + return(0); + + argv[0] = ParentGroupName; + argv[1] = "LIST"; + argv[2] = GroupName; + + if ((rc = mr_query("add_member_to_list", 3, argv, NULL, NULL))) + { + com_err(whoami, 0, + "Unable to add container group %s to parent group %s: %s", + GroupName, ParentGroupName, error_message(rc)); + } + + return(0); + } + +int Moira_getContainerGroup(int ac, char **av, void *ptr) +{ + char **call_args; + + call_args = ptr; + strcpy(call_args[0], av[1]); + + return(0); +} + +int Moira_getGroupName(char *origContainerName, char *GroupName, + int ParentFlag) +{ + char ContainerName[64]; + char *argv[3]; + char *call_args[3]; + char *ptr; + long rc; + + strcpy(ContainerName, origContainerName); + + if (ParentFlag) + { + ptr = strrchr(ContainerName, '/'); + + if (ptr != NULL) + (*ptr) = '\0'; + else + return(0); + } + + argv[0] = ContainerName; + argv[1] = NULL; + call_args[0] = GroupName; + call_args[1] = NULL; + + if (!(rc = mr_query("get_container_list", 1, argv, Moira_getContainerGroup, + call_args))) + { + if (strlen(GroupName) != 0) + return(0); + } + + if (rc) + com_err(whoami, 0, "Unable to get container group from container %s: %s", + ContainerName, error_message(rc)); + else + com_err(whoami, 0, "Unable to get container group from container %s", + ContainerName); + + return(0); +} + +int Moira_process_machine_container_group(char *MachineName, char* GroupName, + int DeleteMachine) +{ + char *argv[3]; + long rc; + + if (strcmp(GroupName, "[none]") == 0) + return 0; + + argv[0] = GroupName; + argv[1] = "MACHINE"; + argv[2] = MachineName; + + if (!DeleteMachine) + rc = mr_query("add_member_to_list", 3, argv, NULL, NULL); + else + rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL); + + if (rc) + { + com_err(whoami, 0, "Unable to add machine %s to container group%s: %s", + MachineName, GroupName, error_message(rc)); + } + + return(0); +} + +int GetMachineName(char *MachineName) +{ + char *args[2]; + char NewMachineName[1024]; + char *szDot; + int rc = 0; + int i; + DWORD dwLen = 0; + char *call_args[2]; + + // If the address happens to be in the top-level MIT domain, great! + strcpy(NewMachineName, MachineName); + + for (i = 0; i < (int)strlen(NewMachineName); i++) + NewMachineName[i] = toupper(NewMachineName[i]); + + szDot = strchr(NewMachineName,'.'); + + if ((szDot) && (!strcasecmp(szDot+1, DOMAIN_SUFFIX))) + { + return(0); + } + + // If not, see if it has a Moira alias in the top-level MIT domain. + memset(NewMachineName, '\0', sizeof(NewMachineName)); + args[0] = "*"; + args[1] = MachineName; + call_args[0] = NewMachineName; + call_args[1] = NULL; + + if (rc = mr_query("get_hostalias", 2, args, ProcessMachineName, call_args)) + { + com_err(whoami, 0, "Unable to resolve machine name %s : %s", + MachineName, error_message(rc)); + strcpy(MachineName, ""); + return(0); + } + + if (strlen(NewMachineName) != 0) + strcpy(MachineName, NewMachineName); + else + strcpy(MachineName, ""); + + return(0); +} + +int ProcessMachineName(int ac, char **av, void *ptr) +{ + char **call_args; + char MachineName[1024]; + char *szDot; + int i; + + call_args = ptr; + + if (strlen(call_args[0]) == 0) + { + strcpy(MachineName, av[0]); + + for (i = 0; i < (int)strlen(MachineName); i++) + MachineName[i] = toupper(MachineName[i]); + + szDot = strchr(MachineName,'.'); + + if ((szDot) && (!strcasecmp(szDot+1,DOMAIN_SUFFIX))) + { + strcpy(call_args[0], MachineName); + } + } + + return(0); +} + +void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n) +{ + int i; + + if (*UseSFU30) + { + for (i = 0; i < n; i++) + { + if (!strcmp(mods[i]->mod_type, "msSFU30UidNumber")) + mods[i]->mod_type = "uidNumber"; + } + + (*UseSFU30) = 0; + } + else + { + for (i = 0; i < n; i++) + { + if (!strcmp(mods[i]->mod_type, "uidNumber")) + mods[i]->mod_type = "msSFU30UidNumber"; + } + + (*UseSFU30) = 1; + } +} + +int SetHomeDirectory(LDAP *ldap_handle, char *user_name, + char *DistinguishedName, + char *WinHomeDir, char *WinProfileDir, + char **homedir_v, char **winProfile_v, + char **drives_v, LDAPMod **mods, + int OpType, int n) +{ + char **hp; + char cWeight[3]; + char cPath[1024]; + char path[1024]; + char winPath[1024]; + char winProfile[1024]; + char homeDrive[8]; + char homedir[1024]; + char apple_homedir[1024]; + char *apple_homedir_v[] = {NULL, NULL}; + int last_weight; + int i; + int rc; + LDAPMod *DelMods[20]; + + memset(homeDrive, '\0', sizeof(homeDrive)); + memset(path, '\0', sizeof(path)); + memset(winPath, '\0', sizeof(winPath)); + memset(winProfile, '\0', sizeof(winProfile)); + hp = NULL; + + if(!ActiveDirectory) + { + if ((hp = hes_resolve(user_name, "filsys")) != NULL) + { + memset(cWeight, 0, sizeof(cWeight)); + memset(cPath, 0, sizeof(cPath)); + last_weight = 1000; + i = 0; + + while (hp[i] != NULL) + { + if (sscanf(hp[i], "%*s %s", cPath)) + { + if (strnicmp(cPath, AFS, strlen(AFS)) == 0) + { + if (sscanf(hp[i], "%*s %*s %*s %*s %s", cWeight)) + { + if (atoi(cWeight) < last_weight) + { + strcpy(path, cPath); + last_weight = (int)atoi(cWeight); + } + } + else + strcpy(path, cPath); + } + } + ++i; + } + + if (strlen(path)) + { + if (!strnicmp(path, AFS, strlen(AFS))) + { + sprintf(homedir, "%s", path); + sprintf(apple_homedir, "%s/MacData", path); + homedir_v[0] = homedir; + apple_homedir_v[0] = apple_homedir; + ADD_ATTR("homeDirectory", homedir_v, OpType); + ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, + OpType); + } + } + else + { + if(user_name[0] && user_name[1]) + { + sprintf(homedir, "/afs/athena.mit.edu/user/%c/%c/%s", + user_name[0], user_name[1], user_name); + sprintf(apple_homedir, "%s/MacData", homedir); + homedir_v[0] = "NONE"; + apple_homedir_v[0] = "NONE"; + ADD_ATTR("homeDirectory", homedir_v, OpType); + ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, + OpType); + } + } + } + else + { + if(user_name[0] && user_name[1]) + { + sprintf(homedir, "/afs/athena.mit.edu/user/%c/%c/%s", + user_name[0], user_name[1], user_name); + sprintf(apple_homedir, "%s/MacData", homedir); + homedir_v[0] = "NONE"; + apple_homedir_v[0] = "NONE"; + ADD_ATTR("homeDirectory", homedir_v, OpType); + ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, + OpType); + } + } + return(n); + } + + if ((!strcasecmp(WinHomeDir, "[afs]")) || + (!strcasecmp(WinProfileDir, "[afs]"))) + { + if ((hp = hes_resolve(user_name, "filsys")) != NULL) + { + memset(cWeight, 0, sizeof(cWeight)); + memset(cPath, 0, sizeof(cPath)); + last_weight = 1000; + i = 0; + + while (hp[i] != NULL) + { + if (sscanf(hp[i], "%*s %s", cPath)) + { + if (strnicmp(cPath, AFS, strlen(AFS)) == 0) + { + if (sscanf(hp[i], "%*s %*s %*s %*s %s", cWeight)) + { + if (atoi(cWeight) < last_weight) + { + strcpy(path, cPath); + last_weight = (int)atoi(cWeight); + } + } + else + strcpy(path, cPath); + } + } + ++i; + } + + if (strlen(path)) + { + if (!strnicmp(path, AFS, strlen(AFS))) + { + AfsToWinAfs(path, winPath); + strcpy(winProfile, winPath); + strcat(winProfile, "\\.winprofile"); + } + } + } + else + return(n); + } + + if ((!strcasecmp(WinHomeDir, "[dfs]")) || + (!strcasecmp(WinProfileDir, "[dfs]"))) + { + sprintf(path, "\\\\%s\\dfs\\profiles\\%c\\%s", ldap_domain, + user_name[0], user_name); + + if (!strcasecmp(WinProfileDir, "[dfs]")) + { + strcpy(winProfile, path); + strcat(winProfile, "\\.winprofile"); + } + + if (!strcasecmp(WinHomeDir, "[dfs]")) + strcpy(winPath, path); + } + + if (hp != NULL) + { + i = 0; + while (hp[i]) + { + free(hp[i]); + i++; + } + } + + if (!strcasecmp(WinHomeDir, "[local]")) + memset(winPath, '\0', sizeof(winPath)); + else if (!strcasecmp(WinHomeDir, "[afs]") || + !strcasecmp(WinHomeDir, "[dfs]")) + { + strcpy(homeDrive, "H:"); + } + else + { + strcpy(winPath, WinHomeDir); + if (!strncmp(WinHomeDir, "\\\\", 2)) + { + strcpy(homeDrive, "H:"); + } + } + + // nothing needs to be done if WinProfileDir is [afs]. + if (!strcasecmp(WinProfileDir, "[local]")) + memset(winProfile, '\0', sizeof(winProfile)); + else if (strcasecmp(WinProfileDir, "[afs]") && + strcasecmp(WinProfileDir, "[dfs]")) + { + strcpy(winProfile, WinProfileDir); + } + + if (strlen(winProfile) != 0) + { + if (winProfile[strlen(winProfile) - 1] == '\\') + winProfile[strlen(winProfile) - 1] = '\0'; + } + + if (strlen(winPath) != 0) + { + if (winPath[strlen(winPath) - 1] == '\\') + winPath[strlen(winPath) - 1] = '\0'; + } + + if ((winProfile[1] == ':') && (strlen(winProfile) == 2)) + strcat(winProfile, "\\"); + + if ((winPath[1] == ':') && (strlen(winPath) == 2)) + strcat(winPath, "\\"); + + if (strlen(winPath) == 0) + { + if (OpType == LDAP_MOD_REPLACE) + { + i = 0; + DEL_ATTR("homeDirectory", LDAP_MOD_DELETE); + DelMods[i] = NULL; + //unset homeDirectory attribute for user. + rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods); + free(DelMods[0]); + } + } + else + { + homedir_v[0] = strdup(winPath); + ADD_ATTR("homeDirectory", homedir_v, OpType); + } + + if (strlen(winProfile) == 0) + { + if (OpType == LDAP_MOD_REPLACE) + { + i = 0; + DEL_ATTR("profilePath", LDAP_MOD_DELETE); + DelMods[i] = NULL; + //unset profilePate attribute for user. + rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods); + free(DelMods[0]); + } + } + else + { + winProfile_v[0] = strdup(winProfile); + ADD_ATTR("profilePath", winProfile_v, OpType); + } + + if (strlen(homeDrive) == 0) + { + if (OpType == LDAP_MOD_REPLACE) + { + i = 0; + DEL_ATTR("homeDrive", LDAP_MOD_DELETE); + DelMods[i] = NULL; + //unset homeDrive attribute for user + rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods); + free(DelMods[0]); + } + } + else + { + drives_v[0] = strdup(homeDrive); + ADD_ATTR("homeDrive", drives_v, OpType); + } + + return(n); +} + +int attribute_update(LDAP *ldap_handle, char *distinguished_name, + char *attribute_value, char *attribute, char *user_name) +{ + char *mod_v[] = {NULL, NULL}; + LDAPMod *DelMods[20]; + LDAPMod *mods[20]; + int n; + int i; + int rc; + + if (strlen(attribute_value) == 0) + { + i = 0; + DEL_ATTR(attribute, LDAP_MOD_DELETE); + DelMods[i] = NULL; + rc = ldap_modify_s(ldap_handle, distinguished_name, DelMods); + free(DelMods[0]); + } + else + { + n = 0; + mod_v[0] = attribute_value; + ADD_ATTR(attribute, mod_v, LDAP_MOD_REPLACE); + mods[n] = NULL; + + if ((rc = ldap_modify_s(ldap_handle, distinguished_name, + mods)) != LDAP_SUCCESS) + { + free(mods[0]); + n = 0; + mod_v[0] = attribute_value; + ADD_ATTR(attribute, mod_v, LDAP_MOD_ADD); + mods[n] = NULL; + + if ((rc = ldap_modify_s(ldap_handle, distinguished_name, + mods)) != LDAP_SUCCESS) + { + com_err(whoami, 0, "Unable to change the %s attribute for %s " + "in the AD : %s", + attribute, user_name, ldap_err2string(rc)); + } + } + + free(mods[0]); + } + + return(rc); +} + +void StringTrim(char *StringToTrim) +{ + char *t, *s; + char *save; + + save = strdup(StringToTrim); + + s = save; + + while (isspace(*s)) + s++; + + /* skip to end of string */ + if (*s == '\0') + { + if (*save) + *save = '\0'; + strcpy(StringToTrim, save); + return; + } + + for (t = s; *t; t++) + continue; + + while (t > s) + { + --t; + if (!isspace(*t)) + { + t++; + break; + } + } + + if (*t) + *t = '\0'; + + strcpy(StringToTrim, s); + return; +} + +int ReadConfigFile(char *DomainName) +{ + int Count; + int i; + int k; + char temp[256]; + char temp1[256]; + FILE *fptr; + + Count = 0; + + sprintf(temp, "%s%s.cfg", CFG_PATH, DomainName); + + if ((fptr = fopen(temp, "r")) != NULL) + { + while (fgets(temp, sizeof(temp), fptr) != 0) + { + for (i = 0; i < (int)strlen(temp); i++) + temp[i] = toupper(temp[i]); + + if (temp[strlen(temp) - 1] == '\n') + temp[strlen(temp) - 1] = '\0'; + + StringTrim(temp); + + if (strlen(temp) == 0) + continue; + + if (!strncmp(temp, DOMAIN, strlen(DOMAIN))) + { + if (strlen(temp) > (strlen(DOMAIN))) + { + strcpy(ldap_domain, &temp[strlen(DOMAIN)]); + StringTrim(ldap_domain); + } + } + else if (!strncmp(temp, REALM, strlen(REALM))) + { + if (strlen(temp) > (strlen(REALM))) + { + strcpy(ldap_realm, &temp[strlen(REALM)]); + StringTrim(ldap_realm); + } + } + else if (!strncmp(temp, PORT, strlen(PORT))) + { + if (strlen(temp) > (strlen(PORT))) + { + strcpy(ldap_port, &temp[strlen(PORT)]); + StringTrim(ldap_port); + } + } + else if (!strncmp(temp, PRINCIPALNAME, strlen(PRINCIPALNAME))) + { + if (strlen(temp) > (strlen(PRINCIPALNAME))) + { + strcpy(PrincipalName, &temp[strlen(PRINCIPALNAME)]); + StringTrim(PrincipalName); + } + } + else if (!strncmp(temp, SERVER, strlen(SERVER))) + { + if (strlen(temp) > (strlen(SERVER))) + { + ServerList[Count] = calloc(1, 256); + strcpy(ServerList[Count], &temp[strlen(SERVER)]); + StringTrim(ServerList[Count]); + ++Count; + } + } + else if (!strncmp(temp, MSSFU, strlen(MSSFU))) + { + if (strlen(temp) > (strlen(MSSFU))) + { + strcpy(temp1, &temp[strlen(MSSFU)]); + StringTrim(temp1); + if (!strcmp(temp1, SFUTYPE)) + UseSFU30 = 1; + } + } + else if (!strncmp(temp, GROUP_SUFFIX, strlen(GROUP_SUFFIX))) + { + if (strlen(temp) > (strlen(GROUP_SUFFIX))) + { + strcpy(temp1, &temp[strlen(GROUP_SUFFIX)]); + StringTrim(temp1); + if (!strcasecmp(temp1, "NO")) + { + UseGroupSuffix = 0; + memset(group_suffix, '\0', sizeof(group_suffix)); + } + } + } + else if (!strncmp(temp, GROUP_TYPE, strlen(GROUP_TYPE))) + { + if (strlen(temp) > (strlen(GROUP_TYPE))) + { + strcpy(temp1, &temp[strlen(GROUP_TYPE)]); + StringTrim(temp1); + if (!strcasecmp(temp1, "UNIVERSAL")) + UseGroupUniversal = 1; + } + } + else if (!strncmp(temp, SET_GROUP_ACE, strlen(SET_GROUP_ACE))) + { + if (strlen(temp) > (strlen(SET_GROUP_ACE))) + { + strcpy(temp1, &temp[strlen(SET_GROUP_ACE)]); + StringTrim(temp1); + if (!strcasecmp(temp1, "NO")) + SetGroupAce = 0; + } + } + else if (!strncmp(temp, SET_PASSWORD, strlen(SET_PASSWORD))) + { + if (strlen(temp) > (strlen(SET_PASSWORD))) + { + strcpy(temp1, &temp[strlen(SET_PASSWORD)]); + StringTrim(temp1); + if (!strcasecmp(temp1, "NO")) + SetPassword = 0; + } + } + else if (!strncmp(temp, EXCHANGE, strlen(EXCHANGE))) + { + if (strlen(temp) > (strlen(EXCHANGE))) + { + strcpy(temp1, &temp[strlen(EXCHANGE)]); + StringTrim(temp1); + if (!strcasecmp(temp1, "YES")) + Exchange = 1; + } + } + else if (!strncmp(temp, PROCESS_MACHINE_CONTAINER, + strlen(PROCESS_MACHINE_CONTAINER))) + { + if (strlen(temp) > (strlen(PROCESS_MACHINE_CONTAINER))) + { + strcpy(temp1, &temp[strlen(PROCESS_MACHINE_CONTAINER)]); + StringTrim(temp1); + if (!strcasecmp(temp1, "NO")) + ProcessMachineContainer = 0; + } + } + else if (!strncmp(temp, ACTIVE_DIRECTORY, + strlen(ACTIVE_DIRECTORY))) + { + if (strlen(temp) > (strlen(ACTIVE_DIRECTORY))) + { + strcpy(temp1, &temp[strlen(ACTIVE_DIRECTORY)]); + StringTrim(temp1); + if (!strcasecmp(temp1, "NO")) + ActiveDirectory = 0; + } + } + else + { + if (strlen(ldap_domain) != 0) + { + memset(ldap_domain, '\0', sizeof(ldap_domain)); + break; + } + + if (strlen(temp) != 0) + strcpy(ldap_domain, temp); + } + } + fclose(fptr); + } + + if (strlen(ldap_domain) == 0) + { + strcpy(ldap_domain, DomainName); + } + + if (Count == 0) + return(0); + + for (i = 0; i < Count; i++) + { + if (ServerList[i] != 0) + { + for (k = 0; k < (int)strlen(ServerList[i]); k++) + ServerList[i][k] = toupper(ServerList[i][k]); + } + } + + return(0); +} + +int ReadDomainList() +{ + int Count; + int i; + char temp[128]; + char temp1[128]; + FILE *fptr; + unsigned char c[11]; + unsigned char stuff[256]; + int rc; + int ok; + + Count = 0; + sprintf(temp, "%s%s", CFG_PATH, WINADCFG); + + if ((fptr = fopen(temp, "r")) != NULL) + { + while (fgets(temp, sizeof(temp), fptr) != 0) + { + for (i = 0; i < (int)strlen(temp); i++) + temp[i] = toupper(temp[i]); + + if (temp[strlen(temp) - 1] == '\n') + temp[strlen(temp) - 1] = '\0'; + + StringTrim(temp); + + if (strlen(temp) == 0) + continue; + + if (!strncmp(temp, DOMAIN, strlen(DOMAIN))) + { + if (strlen(temp) > (strlen(DOMAIN))) + { + strcpy(temp1, &temp[strlen(DOMAIN)]); + StringTrim(temp1); + strcpy(temp, temp1); + } + } + + strcpy(DomainNames[Count], temp); + StringTrim(DomainNames[Count]); + ++Count; + } + + fclose(fptr); + } + + if (Count == 0) + { + critical_alert("incremental", "%s", "ldap.incr cannot run due to a " + "configuration error in ldap.cfg"); + return(1); + } + + return(0); +} + +int email_isvalid(const char *address) { + int count = 0; + const char *c, *domain; + static char *rfc822_specials = "()<>@,;:\\\"[]"; + + if(address[strlen(address) - 1] == '.') + return 0; + + /* first we validate the name portion (name@domain) */ + for (c = address; *c; c++) { + if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == + '\"')) { + while (*++c) { + if (*c == '\"') + break; + if (*c == '\\' && (*++c == ' ')) + continue; + if (*c <= ' ' || *c >= 127) + return 0; + } + + if (!*c++) + return 0; + if (*c == '@') + break; + if (*c != '.') + return 0; + continue; + } + + if (*c == '@') + break; + if (*c <= ' ' || *c >= 127) + return 0; + if (strchr(rfc822_specials, *c)) + return 0; + } + + if (c == address || *(c - 1) == '.') + return 0; + + /* next we validate the domain portion (name@domain) */ + if (!*(domain = ++c)) return 0; + do { + if (*c == '.') { + if (c == domain || *(c - 1) == '.') + return 0; + count++; + } + if (*c <= ' ' || *c >= 127) + return 0; + if (strchr(rfc822_specials, *c)) + return 0; + } while (*++c); + + return (count >= 1); +} + +int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, + char **homeServerName) +{ + LK_ENTRY *group_base; + LK_ENTRY *sub_group_base; + LK_ENTRY *gPtr; + LK_ENTRY *sub_gPtr; + int group_count; + int sub_group_count; + char filter[1024]; + char sub_filter[1024]; + char search_path[1024]; + char range[1024]; + char *attr_array[3]; + char *s; + int homeMDB_count = -1; + int rc; + int i; + int mdbbl_count; + int rangeStep = 1500; + int rangeLow = 0; + int rangeHigh = rangeLow + (rangeStep - 1); + int isLast = 0; + + /* Grumble..... microsoft not making it searchable from the root *grr* */ + + memset(filter, '\0', sizeof(filter)); + memset(search_path, '\0', sizeof(search_path)); + + sprintf(filter, "(objectClass=msExchMDB)"); + sprintf(search_path, "CN=Configuration,%s", dn_path); + attr_array[0] = "distinguishedName"; + attr_array[1] = NULL; + + group_base = NULL; + group_count = 0; + + if ((rc = linklist_build(ldap_handle, search_path, filter, attr_array, + &group_base, &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to find msExchMDB %s", + ldap_err2string(rc)); + return(rc); + } + + if (group_count) + { + gPtr = group_base; + + while(gPtr) { + if (((s = strstr(gPtr->dn, "Public")) != (char *) NULL) || + ((s = strstr(gPtr->dn, "Recover")) != (char *) NULL) || + ((s = strstr(gPtr->dn, "Reserve")) != (char *) NULL)) + { + gPtr = gPtr->next; + continue; + } + + /* + * Due to limits in active directory we need to use the LDAP + * range semantics to query and return all the values in + * large lists, we will stop increasing the range when + * the result count is 0. + */ + + i = 0; + mdbbl_count = 0; + + for(;;) + { + memset(sub_filter, '\0', sizeof(sub_filter)); + memset(range, '\0', sizeof(range)); + sprintf(sub_filter, "(objectClass=msExchMDB)"); + + if(isLast) + sprintf(range, "homeMDBBL;Range=%d-*", rangeLow); + else + sprintf(range, "homeMDBBL;Range=%d-%d", rangeLow, rangeHigh); + + attr_array[0] = range; + attr_array[1] = NULL; + + sub_group_base = NULL; + sub_group_count = 0; + + if ((rc = linklist_build(ldap_handle, gPtr->dn, sub_filter, + attr_array, &sub_group_base, + &sub_group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to find homeMDBBL %s", + ldap_err2string(rc)); + return(rc); + } + + if(!sub_group_count) + { + if(isLast) + { + isLast = 0; + rangeLow = 0; + rangeHigh = rangeLow + (rangeStep - 1); + break; + } + else + isLast++; + } + + mdbbl_count += sub_group_count; + rangeLow = rangeHigh + 1; + rangeHigh = rangeLow + (rangeStep - 1); + } + + /* First time through, need to initialize or update the least used */ + + com_err(whoami, 0, "Mail store %s, count %d", gPtr->dn, + mdbbl_count); + + if(mdbbl_count < homeMDB_count || homeMDB_count == -1) + { + homeMDB_count = mdbbl_count; + *homeMDB = strdup(gPtr->dn); + } + + gPtr = gPtr->next; + linklist_free(sub_group_base); + } + } + + linklist_free(group_base); + + /* + * Ok found the server least allocated need to now query to get its + * msExchHomeServerName so we can set it as a user attribute + */ + + attr_array[0] = "legacyExchangeDN"; + attr_array[1] = NULL; + + group_count = 0; + group_base = NULL; + + if ((rc = linklist_build(ldap_handle, *homeMDB, filter, + attr_array, &group_base, + &group_count, + LDAP_SCOPE_SUBTREE)) != 0) + { + com_err(whoami, 0, "Unable to find msExchHomeServerName %s", + ldap_err2string(rc)); + return(rc); + } + + if(group_count) + { + *homeServerName = strdup(group_base->value); + if((s = strrchr(*homeServerName, '/')) != (char *) NULL) + { + *s = '\0'; + } + } + + linklist_free(group_base); + + return(rc); +} + +char *lowercase(char *s) +{ + char *p; + + for (p = s; *p; p++) + { + if (isupper(*p)) + *p = tolower(*p); + } + return s; +} + +char *uppercase(char *s) +{ + char *p; + + for (p = s; *p; p++) + { + if (islower(*p)) + *p = toupper(*p); + } + return s; +} + +char *escape_string(char *s) +{ + char *p, *q; + char string[1024]; + char temp[1024]; + int i = 0; + int spaces = 0; + + memset(string, '\0', sizeof(string)); + + q = s; + + /* Replace leading spaces */ + + while(isspace(*q)) { + string[i++] = '\\'; + string[i++] = '2'; + string[i++] = '0'; + q++; + } + + /* Escape any special characters */ + + for(; *q != '\0'; q++) { + if(*q == ',') + string[i++] = '\\'; + if(*q == '+') + string[i++] = '\\'; + if(*q == '"') + string[i++] = '\\'; + if(*q == '\\') + string[i++] = '\\'; + if(*q == '<') + string[i++] = '\\'; + if(*q == '>') + string[i++] = '\\'; + if(*q == ';') + string[i++] = '\\'; + if(*q == '#') + string[i++] = '\\'; + if(*q == '=') + string[i++] = '\\'; + + string[i++] = *q; + } + + return strdup(string); +} + +int save_query_info(int argc, char **argv, void *hint) +{ + int i; + char **nargv = hint; + + for(i = 0; i < argc; i++) + nargv[i] = strdup(argv[i]); + + return MR_CONT; +}