1#!/bin/sh
2######################################################################
3#
4# $Id: webjob-create-profile,v 1.89 2012/01/07 08:01:17 mavrik Exp $
5#
6######################################################################
7#
8# Copyright 2007-2012 The WebJob Project, All Rights Reserved.
9#
10######################################################################
11#
12# Purpose: Create a WebJob profile.
13#
14######################################################################
15
16IFS='
17'
18
19PROGRAM=`basename ${0}`
20
21umask 027
22
23######################################################################
24#
25# VerifyPassword
26#
27######################################################################
28
29VerifyPassword()
30{
31  MY_ARG_CLIENT_ID=${1}
32  MY_ARG_PASSWORD=${2}
33  MY_ARG_HTUSERS_ENTRY=${3}
34
35  MY_TARGET_PASSWORD_HASH=`echo "${MY_ARG_HTUSERS_ENTRY}" | sed "s/^${MY_ARG_CLIENT_ID}://; s/^LOCKED//;"`
36
37  case "${MY_TARGET_PASSWORD_HASH}" in
38  \$apr1\$*)
39    MY_ACTUAL_PASSWORD_HASH=`perl -e 'use Crypt::PasswdMD5; print apache_md5_crypt(q('${MY_ARG_PASSWORD}'), q('${MY_TARGET_PASSWORD_HASH}')), "\n";'`
40    ;;
41  [0-9A-Za-z./][0-9A-Za-z./]*)
42    MY_ACTUAL_PASSWORD_HASH=`perl -e 'print crypt(q('${MY_ARG_PASSWORD}'), q('${MY_TARGET_PASSWORD_HASH}')), "\n";'`
43    ;;
44  *)
45    return 1
46    ;;
47  esac
48
49  if [ X"${MY_ACTUAL_PASSWORD_HASH}" = X"${MY_TARGET_PASSWORD_HASH}" ] ; then
50    return 0
51  fi
52
53  return 1
54}
55
56######################################################################
57#
58# VerifyPrograms
59#
60######################################################################
61
62VerifyPrograms()
63{
64  MY_PROGRAMS="
65htpasswd
66perl
67webjob-cfg-get-kvps
68webjob-cfg-update-list
69webjob-dsvtool
70webjob-jqd-create-queue
71webjob-jqd-list-members
72webjob-jqd-update-group
73webjob-mldbm-create-client
74webjob-mldbm-get-config-kvps
75webjob-mldbm-set-config-kvps
76"
77  MY_DIRS=`echo "${PATH}" | sed 's/:/ /g;'`
78
79  for MY_PROGRAM in ${MY_PROGRAMS} ; do
80    MY_PROGRAM_FOUND=0
81    for MY_DIR in ${MY_DIRS} ; do
82      MY_TEST_PATH="${MY_DIR}/${MY_PROGRAM}"
83      if [ -x ${MY_TEST_PATH} ] ; then
84        MY_PROGRAM_FOUND=1
85        break;
86      fi
87    done
88    if [ ${MY_PROGRAM_FOUND} -ne 1 ] ; then
89      echo "${PROGRAM}: Error='Unable to locate an executable instance of ${MY_PROGRAM} in the current PATH (${PATH}).'" 1>&2
90      exit 2
91    fi
92  done
93}
94
95######################################################################
96#
97# Usage
98#
99######################################################################
100
101Usage()
102{
103  echo 1>&2
104  echo "${PROGRAM} [-C webjob-client-home] [-e {plain|base64}] [-g jqd-group[,jqd-group[...]]] [-H webjob-home] [-h host] [-i ip] [-n webjob-server-cn] [-o option[,option[,...]]] [-P password] [-r registration-code] [-S webjob-server-home] [-s webjob-server] [-T timeslot] -p {unix|winx} -c client [key=value [...]]" 1>&2
105  echo 1>&2
106  exit 1
107}
108
109######################################################################
110#
111# Main
112#
113######################################################################
114
115CLIENT_HOSTNAME=""
116
117CLIENT_IP=""
118
119ENCODING="base64"
120
121JQD_GROUP_LIST=""
122
123OPTIONS=""
124
125PASSWORD=""
126
127PASSWORD_SPECIFIED="0"
128
129PLATFORM=""
130
131TIMESLOT=""
132
133WEBJOB_CLIENT_HOME=""
134
135WEBJOB_REGISTRATION_CODE=""
136
137WEBJOB_SERVER=""
138
139WEBJOB_SERVER_CLIENT_HOME="/usr/local/webjob"
140
141WEBJOB_SERVER_CN=""
142
143WEBJOB_SERVER_HOME="/var/webjob"
144
145while getopts "C:c:e:g:H:h:i:n:o:P:p:r:S:s:T:" OPTION ; do
146  case "${OPTION}" in
147  C)
148    WEBJOB_CLIENT_HOME="${OPTARG}"
149    ;;
150  c)
151    CLIENT_ID="${OPTARG}"
152    ;;
153  e)
154    ENCODING="${OPTARG}"
155    ;;
156  g)
157    JQD_GROUP_LIST="${OPTARG}"
158    ;;
159  H)
160    WEBJOB_HOME="${OPTARG}"
161    ;;
162  h)
163    CLIENT_HOSTNAME="${OPTARG}"
164    ;;
165  i)
166    CLIENT_IP="${OPTARG}"
167    ;;
168  n)
169    WEBJOB_SERVER_CN="${OPTARG}"
170    ;;
171  o)
172    OPTIONS="${OPTARG}"
173    ;;
174  P)
175    PASSWORD="${OPTARG}"
176    PASSWORD_SPECIFIED="1"
177    ;;
178  p)
179    PLATFORM="${OPTARG}"
180    ;;
181  r)
182    WEBJOB_REGISTRATION_CODE="${OPTARG}"
183    ;;
184  S)
185    WEBJOB_SERVER_HOME="${OPTARG}"
186    ;;
187  s)
188    WEBJOB_SERVER="${OPTARG}"
189    ;;
190  T)
191    TIMESLOT="${OPTARG}"
192    ;;
193  *)
194    Usage
195    ;;
196  esac
197done
198
199shift `expr ${OPTIND} - 1`
200
201if [ -z "${CLIENT_ID}" ] ; then
202  Usage
203fi
204
205case "${ENCODING}" in
206[Pp][Ll][Aa][Ii][Nn])
207  ENCODING="plain"
208  ;;
209[Bb][Aa][Ss][Ee]64)
210  ENCODING="base64"
211  ;;
212*)
213  Usage
214  ;;
215esac
216
217case "${PLATFORM}" in
218[Uu][Nn][Ii][Xx])
219  OS_CLASS="UNIX"
220  PLATFORM="unix"
221  if [ -z "${WEBJOB_CLIENT_HOME}" ] ; then
222    WEBJOB_CLIENT_HOME='/usr/local/webjob'
223  fi
224  ;;
225[Ww][Ii][Nn][Xx])
226  OS_CLASS="WINX"
227  PLATFORM="winx"
228  if [ -z "${WEBJOB_CLIENT_HOME}" ] ; then
229    WEBJOB_CLIENT_HOME='c:\\webjob'
230  fi
231  ;;
232*)
233  Usage
234  ;;
235esac
236
237if [ -n "${TIMESLOT}" ] ; then
238  echo "${TIMESLOT}" | egrep "^([0-9]|[1-2][0-9])$" > /dev/null 2>&1
239  if [ $? -ne 0 ] ; then
240    echo "${PROGRAM}: Error='Timeslot (${TIMESLOT}) does not pass muster. A value in the range [0-29] is required.'" 1>&2
241    exit 2
242  fi
243fi
244
245if [ -n "${WEBJOB_REGISTRATION_CODE}" ] ; then
246  perl -e 'exit(($ARGV[0] =~ /^[0-9A-Za-z]{5}(-[0-9A-Za-z]{5}){2,11}$/) ? 0 : 1);' "${WEBJOB_REGISTRATION_CODE}" > /dev/null 2>&1
247  if [ $? -ne 0 ] ; then
248    echo "${PROGRAM}: Error='The registration code (${WEBJOB_REGISTRATION_CODE}) not pass muster.'" 1>&2
249    exit 2
250  fi
251fi
252
253PATH=${WEBJOB_HOME=/usr/local/webjob}/bin:${PATH} ; export PATH
254
255VerifyPrograms
256
257if [ ! -d "${WEBJOB_SERVER_HOME}" ] ; then
258  echo "${PROGRAM}: Error='Server home directory (${WEBJOB_SERVER_HOME}) does not exist.'" 1>&2
259  exit 2
260fi
261
262WEBJOB_SERVER_CONFIG_FILE="${WEBJOB_SERVER_HOME}/config/server.cfg"
263if [ ! -f "${WEBJOB_SERVER_CONFIG_FILE}" ] ; then
264  echo "${PROGRAM}: Error='Server config file (${WEBJOB_SERVER_CONFIG_FILE}) does not exist.'" 1>&2
265  exit 2
266fi
267
268HOSTNAME=`webjob-cfg-get-kvps -t webjob.server -f ${WEBJOB_SERVER_CONFIG_FILE} -o BeQuiet,ValuesOnly Hostname`
269if [ -z "${HOSTNAME}" ] ; then
270  HOSTNAME=`hostname`
271fi
272
273if [ -z "${WEBJOB_SERVER}" ] ; then
274  WEBJOB_SERVER="${HOSTNAME}"
275  if [ -z "${WEBJOB_SERVER}" ] ; then
276    echo "${PROGRAM}: Error='Unable to determine hostname. Use the \"-s\" option to specify the server hostname or IP address.'" 1>&2
277    exit 2
278  fi
279fi
280
281if [ -z "${WEBJOB_SERVER_CN}" ] ; then
282  WEBJOB_SERVER_CN="${HOSTNAME}"
283  if [ -z "${WEBJOB_SERVER_CN}" ] ; then
284    echo "${PROGRAM}: Error='Unable to determine hostname. Use the \"-n\" option to specify the server common name.'" 1>&2
285    exit 2
286  fi
287fi
288
289WWW_OWNER=`webjob-cfg-get-kvps -t webjob.server -f ${WEBJOB_SERVER_CONFIG_FILE} -o BeQuiet,ValuesOnly ApacheOwner`
290if [ -z "${WWW_OWNER}" ] ; then
291  WWW_OWNER="www"
292fi
293WWW_OWNER_TEST=`awk -F: '{print $1}' /etc/passwd | egrep "${WWW_OWNER}"`
294if [ -z "${WWW_OWNER_TEST}" ] ; then
295  echo "${PROGRAM}: Error='Unable to verify that \"${WWW_OWNER}\" is a valid owner. Make sure that ApacheOwner is set properly in ${WEBJOB_SERVER_CONFIG_FILE}.'" 1>&2
296  exit 2
297fi
298
299WWW_GROUP=`webjob-cfg-get-kvps -t webjob.server -f ${WEBJOB_SERVER_CONFIG_FILE} -o BeQuiet,ValuesOnly ApacheGroup`
300if [ -z "${WWW_GROUP}" ] ; then
301  WWW_GROUP="www"
302fi
303WWW_GROUP_TEST=`awk -F: '{print $1}' /etc/group | egrep "${WWW_GROUP}"`
304if [ -z "${WWW_GROUP_TEST}" ] ; then
305  echo "${PROGRAM}: Error='Unable to verify that \"${WWW_GROUP}\" is a valid group. Make sure that ApacheGroup is set properly in ${WEBJOB_SERVER_CONFIG_FILE}.'" 1>&2
306  exit 2
307fi
308
309if [ -z "${CLIENT_HOSTNAME}" ] ; then
310  CLIENT_HOSTNAME=`echo "${CLIENT_ID}" | sed 's/^client_//;' | awk -F. '{print $1}'`
311  if [ -z "${CLIENT_HOSTNAME}" ] ; then
312    echo "${PROGRAM}: Error='Unable to derive hostname. Use the \"-h\" option to specify the client hostname.'" 1>&2
313    exit 2
314  fi
315fi
316
317######################################################################
318#
319# Ensure that all prerequisites exist. Any error is considered fatal
320# since it implies that the server's configuration is not complete.
321#
322######################################################################
323
324HTUSERS_FILE="${WEBJOB_SERVER_HOME}/config/apache/ht-client"
325if [ ! -f "${HTUSERS_FILE}" ] ; then
326  echo "${PROGRAM}: Error='Password file (${HTUSERS_FILE}) does not exist.'" 1>&2
327  exit 2
328fi
329
330NPH_CONFIG_CONFIG_DIR="${WEBJOB_SERVER_HOME}/config/nph-config"
331if [ ! -d "${NPH_CONFIG_CONFIG_DIR}" ] ; then
332  echo "${PROGRAM}: Error='Override directory (${NPH_CONFIG_CONFIG_DIR}) does not exist.'" 1>&2
333  exit 2
334fi
335
336NPH_CONFIG_HOST_ACCESS_FILE="${WEBJOB_SERVER_HOME}/config/nph-config/nph-config-hosts.access"
337if [ ! -f "${NPH_CONFIG_HOST_ACCESS_FILE}" ] ; then
338  echo "${PROGRAM}: Error='Host access file (${NPH_CONFIG_HOST_ACCESS_FILE}) for nph-config.cgi does not exist.'" 1>&2
339  exit 2
340fi
341
342NPH_WEBJOB_CONFIG_DIR="${WEBJOB_SERVER_HOME}/config/nph-webjob"
343if [ ! -d "${NPH_WEBJOB_CONFIG_DIR}" ] ; then
344  echo "${PROGRAM}: Error='Override directory (${NPH_WEBJOB_CONFIG_DIR}) does not exist.'" 1>&2
345  exit 2
346fi
347
348NPH_WEBJOB_HOST_ACCESS_FILE="${WEBJOB_SERVER_HOME}/config/nph-webjob/nph-webjob-hosts.access"
349if [ ! -f "${NPH_WEBJOB_HOST_ACCESS_FILE}" ] ; then
350  echo "${PROGRAM}: Error='Host access file (${NPH_WEBJOB_HOST_ACCESS_FILE}) for nph-webjob.cgi does not exist.'" 1>&2
351  exit 2
352fi
353
354WEBJOB_CLIENT_DB="${WEBJOB_SERVER_HOME}/db/mldbm/client.db"
355if [ ! -f "${WEBJOB_CLIENT_DB}" ] ; then
356  echo "${PROGRAM}: Error='Client DB (${WEBJOB_CLIENT_DB}) does not exist.'" 1>&2
357  exit 2
358fi
359
360WEBJOB_GROUP_FILE="${WEBJOB_SERVER_HOME}/config/jqd/groups"
361if [ ! -f "${WEBJOB_GROUP_FILE}" ] ; then
362  echo "${PROGRAM}: Error='Group file (${WEBJOB_GROUP_FILE}) does not exist.'" 1>&2
363  exit 2
364fi
365
366WEBJOB_JQD_DIR="${WEBJOB_SERVER_HOME}/spool/jqd"
367if [ ! -d "${WEBJOB_JQD_DIR}" ] ; then
368  echo "${PROGRAM}: Error='JQD directory (${WEBJOB_JQD_DIR}) does not exist.'" 1>&2
369  exit 2
370fi
371
372WEBJOB_PROFILES_DIR="${WEBJOB_SERVER_HOME}/profiles"
373if [ ! -d "${WEBJOB_PROFILES_DIR}" ] ; then
374  echo "${PROGRAM}: Error='Profiles directory (${WEBJOB_PROFILES_DIR}) does not exist.'" 1>&2
375  exit 2
376fi
377
378WEBJOB_SKEL_DIR="${WEBJOB_SERVER_HOME}/config/skel"
379if [ ! -d "${WEBJOB_SKEL_DIR}" ] ; then
380  echo "${PROGRAM}: Error='Skeleton directory (${WEBJOB_SKEL_DIR}) does not exist.'" 1>&2
381  exit 2
382fi
383
384  ####################################################################
385  #
386  # Parse the options list.
387  #
388  ####################################################################
389
390  FORCE="0"
391
392  FORCE_PASSWORD="0"
393
394  LOCAL_PROFILE="0"
395
396  LOCK_PROFILE="0"
397
398  for OPTION in `echo "${OPTIONS}" | sed 's/,/ /g;' | tr '[A-Z]' '[a-z]'` ; do
399    case "${OPTION}" in
400    force)
401      FORCE="1"
402      ;;
403    forcepassword)
404      FORCE_PASSWORD="1"
405      ;;
406    localprofile)
407      LOCAL_PROFILE="1"
408      ;;
409    lockprofile)
410      LOCK_PROFILE="1"
411      ;;
412    esac
413  done
414
415######################################################################
416#
417# Do some work.
418#
419######################################################################
420
421MY_ERROR_FLAG=0
422
423  ####################################################################
424  #
425  # Do a sanity check on the client ID.
426  #
427  ####################################################################
428
429  MY_CLIENT_ID_OK=`echo ${CLIENT_ID} | perl -n -e 'if ($_ =~ /^(?:[A-Za-z](?:(?:[0-9A-Za-z]|[_-](?=[^.]))){0,62})(?:[.][A-Za-z](?:(?:[0-9A-Za-z]|[_-](?=[^.]))){0,62}){0,127}$/) { print "pass\n"; } else { print "fail\n"; }'`
430
431  if [ x"${MY_CLIENT_ID_OK}" != x"pass" ] ; then
432    echo "${PROGRAM}: Error='Client ID (${CLIENT_ID}) does not pass muster. The profile will not be created.'" 1>&2
433    exit 2
434  fi
435
436  ####################################################################
437  #
438  # Conditionally generate a password, and update the htusers file.
439  # If the htusers file already has an entry for this client and no
440  # password was specified and the force option is disabled, abort --
441  # blindly updating the htusers file with a new password could lock
442  # out existing clients. If a password was specified, then assume
443  # that user wants the htusers file to be updated.
444  #
445  ####################################################################
446
447  if [ ${PASSWORD_SPECIFIED} -eq 0 -a -n "${WEBJOB_PASSWORD}" ] ; then
448    PASSWORD="${WEBJOB_PASSWORD}"
449    PASSWORD_SPECIFIED="1"
450  fi
451
452  if [ ${PASSWORD_SPECIFIED} -eq 1 ] ; then
453    if [ -n "${PASSWORD}" ] ; then
454      echo "${PASSWORD}" | egrep "^0:[0-9A-Za-z/+]+={0,2}$" > /dev/null 2>&1
455      if [ $? -eq 0 ] ; then
456        MY_PASSWORD=`echo "${PASSWORD}" | perl -p -e 'use MIME::Base64; chomp; $_=~ s/^0://; $_=decode_base64($_);'`
457      else
458        MY_PASSWORD=${PASSWORD}
459      fi
460    else
461      : # Empty passwords are not allowed. This error will be caught below.
462    fi
463  else
464    MY_PASSWORD=`webjob-dsvtool -p`
465  fi
466
467  echo "${MY_PASSWORD}" | egrep "^[0-9A-Za-z/+]{8,}$" > /dev/null 2>&1
468  if [ $? -ne 0 ] ; then
469    echo "${PROGRAM}: Error='The password for ${CLIENT_ID} does not pass muster. The profile will not be created.'" 1>&2
470    exit 2
471  fi
472
473  MY_HTUSERS_ENTRY=`egrep "^${CLIENT_ID}:" ${HTUSERS_FILE} 2> /dev/null`
474  if [ -n "${MY_HTUSERS_ENTRY}" ] ; then
475    if [ ${FORCE_PASSWORD} -eq 0 ] ; then
476      if [ ${PASSWORD_SPECIFIED} -eq 1 ] ; then
477        VerifyPassword "${CLIENT_ID}" "${MY_PASSWORD}" "${MY_HTUSERS_ENTRY}"
478        if [ $? -ne 0 ] ; then
479          echo "${PROGRAM}: Error='Client (${CLIENT_ID}) already has an htusers entry, and the supplied password is not correct.'" 1>&2
480          exit 4 # XER_PasswordRequired
481        fi
482      else
483        echo "${PROGRAM}: Error='Client (${CLIENT_ID}) already has an htusers entry. To continue, either supply the current password with the \"-P\" option or use the \"ForcePassword\" option to force a password update.'" 1>&2
484        exit 4 # XER_PasswordRequired
485      fi
486    fi
487  fi
488
489  echo "Updating ${HTUSERS_FILE}"
490
491  if [ ${LOCK_PROFILE} -eq 1 ] ; then
492    MY_NEW_HTUSERS_ENTRY=`htpasswd -b -m -n ${CLIENT_ID} ${MY_PASSWORD} | sed "s/^${CLIENT_ID}:/${CLIENT_ID}:LOCKED/;"`
493  else
494    MY_NEW_HTUSERS_ENTRY=`htpasswd -b -m -n ${CLIENT_ID} ${MY_PASSWORD}`
495  fi
496  if [ -n "${MY_NEW_HTUSERS_ENTRY}" ] ; then
497    webjob-cfg-set-kvps -d : -f ${HTUSERS_FILE} "${MY_NEW_HTUSERS_ENTRY}"
498    if [ $? -ne 0 ] ; then
499      echo "${PROGRAM}: Error='Unable to set password for ${CLIENT_ID}.'" 1>&2
500      MY_ERROR_FLAG=1
501    fi
502  fi
503
504  if [ x"${ENCODING}" = x"base64" ] ; then
505    MY_ENCODED_PASSWORD=`echo "${MY_PASSWORD}" | perl -p -e 'use MIME::Base64; chomp; $_="0:".encode_base64($_);'`
506  else
507    MY_ENCODED_PASSWORD=${MY_PASSWORD}
508  fi
509
510  ####################################################################
511  #
512  # Create the profile tree.
513  #
514  ####################################################################
515
516  MY_PROFILE_DIR="${WEBJOB_PROFILES_DIR}/${CLIENT_ID}"
517
518  MY_ETC_DIR="${MY_PROFILE_DIR}/etc"
519
520  MY_COMMANDS_DIR="${MY_PROFILE_DIR}/commands"
521
522  MY_CONFIGS_DIR="${MY_PROFILE_DIR}/configs"
523
524  MY_CONTENT_DIR="${MY_PROFILE_DIR}/content"
525
526  MY_DSV_DIR="${MY_PROFILE_DIR}/dsv"
527
528  MY_HOOKS_DIR="${MY_PROFILE_DIR}/hooks"
529
530  MY_RUN_DIR="${MY_PROFILE_DIR}/run"
531
532  MY_TRIGGERS_DIR="${MY_PROFILE_DIR}/triggers"
533
534  MY_WORKERS_DIR="${MY_PROFILE_DIR}/workers"
535
536  MY_DIRS="
537${MY_PROFILE_DIR}
538${MY_ETC_DIR}
539${MY_COMMANDS_DIR}
540${MY_CONFIGS_DIR}
541${MY_CONTENT_DIR}
542${MY_HOOKS_DIR}
543${MY_TRIGGERS_DIR}
544${MY_WORKERS_DIR}
545"
546
547  if [ ${LOCAL_PROFILE} -eq 1 ] ; then
548    MY_DIRS="${MY_DIRS} ${MY_DSV_DIR} ${MY_RUN_DIR}"
549  fi
550
551  for MY_DIR in ${MY_DIRS} ; do
552    if [ ! -d "${MY_DIR}" ] ; then
553      echo "Creating ${MY_DIR}"
554      mkdir -p ${MY_DIR}
555      if [ $? -ne 0 ] ; then
556        echo "${PROGRAM}: Error='Encountered a problem while creating ${MY_DIR}.'" 1>&2
557        MY_ERROR_FLAG=1
558      fi
559    else
560      echo "Skipping ${MY_DIR} (already exists)"
561    fi
562  done
563
564  if [ ${LOCAL_PROFILE} -eq 1 ] ; then
565    chmod 700 ${MY_RUN_DIR}
566  fi
567
568  ####################################################################
569  #
570  # Create symlinks to support local profiles.
571  #
572  ####################################################################
573
574  if [ ${LOCAL_PROFILE} -eq 1 ] ; then
575    for MY_DIR in "bin" ; do
576      MY_SYMLINK="${MY_PROFILE_DIR}/${MY_DIR}"
577      if [ ! -L "${MY_SYMLINK}" ] ; then
578        echo "Creating ${MY_SYMLINK}"
579        if [ ${FORCE} -eq 1 ] ; then
580          MY_LN_OPTS="-f"
581        else
582          MY_LN_OPTS=""
583        fi
584        ln -s ${MY_LN_OPTS} ${WEBJOB_SERVER_CLIENT_HOME}/${MY_DIR} ${MY_SYMLINK}
585        if [ $? -ne 0 ] ; then
586          echo "${PROGRAM}: Error='Encountered a problem while creating config symlink for ${CLIENT_ID}.'" 1>&2
587          MY_ERROR_FLAG=1
588        fi
589      fi
590    done
591  fi
592
593  ####################################################################
594  #
595  # Create config files.
596  #
597  ####################################################################
598
599  WEBJOB_CLIENT_HOME_ESCAPED=`echo "${WEBJOB_CLIENT_HOME}" | perl -p -e 's,(\x5c),$1$1,g;'`
600
601  for MY_EXT in "-a" "-b" ; do
602    for MY_NAME in "upload" ; do
603      MY_FILE=${MY_NAME}${MY_EXT}.cfg
604      MY_CONFIG_FILE="${MY_ETC_DIR}/${MY_FILE}"
605      MY_SKEL_CONFIG_FILE="${WEBJOB_SKEL_DIR}/${MY_NAME}-${PLATFORM}${MY_EXT}.cfg"
606      if [ -f "${MY_SKEL_CONFIG_FILE}" ] ; then
607        if [ ! -f ${MY_CONFIG_FILE} -o ${FORCE} -eq 1 -o ${FORCE_PASSWORD} -eq 1 ] ; then
608          echo "Creating ${MY_CONFIG_FILE}"
609          # Note that %sample_client_home must be replaced before %sample_client to prevent unwanted substitutions.
610          # Note that %sample_server_cn   must be replaced before %sample_server to prevent unwanted substitutions.
611          sed \
612            -e "s#%sample_password#${MY_ENCODED_PASSWORD}#g;" \
613            -e "s#%sample_client_home#${WEBJOB_CLIENT_HOME_ESCAPED}#g;" \
614            -e "s#%sample_client#${CLIENT_ID}#g;" \
615            -e "s#%sample_server_cn#${WEBJOB_SERVER_CN}#g;" \
616            -e "s#%sample_server#${WEBJOB_SERVER}#g;" \
617            ${MY_SKEL_CONFIG_FILE} > ${MY_CONFIG_FILE}
618          if [ $? -ne 0 ] ; then
619            echo "${PROGRAM}: Error='Encountered a problem while creating ${MY_FILE} for ${CLIENT_ID}.'" 1>&2
620            MY_ERROR_FLAG=1
621          fi
622        else
623          echo "Skipping ${MY_CONFIG_FILE} (already exists)"
624        fi
625      fi
626    done
627  done
628
629  for MY_EXT in "-a" "-b" ; do
630    for MY_NAME in "upload" ; do
631      MY_FILE=${MY_NAME}${MY_EXT}.ptr
632      MY_CONFIG_FILE="${MY_ETC_DIR}/${MY_FILE}"
633      MY_SKEL_CONFIG_FILE="${WEBJOB_SKEL_DIR}/${MY_NAME}-${PLATFORM}${MY_EXT}.ptr"
634      if [ -f "${MY_SKEL_CONFIG_FILE}" ] ; then
635        if [ ! -f ${MY_CONFIG_FILE} -o ${FORCE} -eq 1 ] ; then
636          echo "Creating ${MY_CONFIG_FILE}"
637          sed \
638            -e "s#%sample_client_home#${WEBJOB_CLIENT_HOME_ESCAPED}#g;" \
639            ${MY_SKEL_CONFIG_FILE} > ${MY_CONFIG_FILE}
640          if [ $? -ne 0 ] ; then
641            echo "${PROGRAM}: Error='Encountered a problem while creating ${MY_FILE} for ${CLIENT_ID}.'" 1>&2
642            MY_ERROR_FLAG=1
643          fi
644        else
645          echo "Skipping ${MY_CONFIG_FILE} (already exists)"
646        fi
647      fi
648    done
649  done
650
651  MY_NAME="upload"
652  MY_FILE="${MY_NAME}.cfg"
653  MY_CONFIG_FILE="${MY_ETC_DIR}/${MY_FILE}"
654  CONFIG_POINTER=`webjob-mldbm-get-config-kvps -d ${WEBJOB_CLIENT_DB} -c ${CLIENT_ID} -o BeQuiet,ValuesOnly ConfigPointer | tr '[a-z]' '[A-Z]'`
655  if [ X"${CONFIG_POINTER}" = X"B" ] ; then
656    MY_POINTER_FILE="${MY_ETC_DIR}/${MY_NAME}-b.ptr"
657  else
658    CONFIG_POINTER="A"
659    MY_POINTER_FILE="${MY_ETC_DIR}/${MY_NAME}-a.ptr"
660  fi
661  if [ ! -f ${MY_CONFIG_FILE} -o ${FORCE} -eq 1 ] ; then
662    echo "Creating ${MY_CONFIG_FILE}"
663    cp -p ${MY_POINTER_FILE} ${MY_CONFIG_FILE}
664    if [ $? -ne 0 ] ; then
665      echo "${PROGRAM}: Error='Encountered a problem while creating ${MY_FILE} for ${CLIENT_ID}.'" 1>&2
666      MY_ERROR_FLAG=1
667    fi
668  else
669    echo "Skipping ${MY_CONFIG_FILE} (already exists)"
670  fi
671
672  ####################################################################
673  #
674  # Find the next timeslot, and write it to a timeslot file. Use a
675  # default value of zero for local profiles. Also, do not use local
676  # timeslot values when computing the timeslot for a given (remote)
677  # client.
678  #
679  ####################################################################
680
681  if [ ${LOCAL_PROFILE} -eq 1 -a -z "${TIMESLOT}" ] ; then
682    TIMESLOT=0
683  fi
684
685  if [ -n "${TIMESLOT}" ] ; then
686    MY_TIMESLOT=${TIMESLOT}
687  else
688    MY_TIMESLOT_FILES=""
689    for MY_CLIENT in `webjob-jqd-list-members -G ${WEBJOB_GROUP_FILE} -i %all -e %all_local` ; do
690      MY_TIMESLOT_FILE="${WEBJOB_PROFILES_DIR}/${MY_CLIENT}/workers/hourly.cfg"
691      if [ -f "${MY_TIMESLOT_FILE}" ] ; then
692        MY_TIMESLOT_FILES="${MY_TIMESLOT_FILES} ${MY_TIMESLOT_FILE}"
693      fi
694    done
695    if [ -n "${MY_TIMESLOT_FILES}" ] ; then
696      MY_TIMESLOT=`\
697      {
698        egrep -h '^Minute=[0-9][0-9]?$' ${MY_TIMESLOT_FILES} 2> /dev/null | awk -F= '{print $2}' 2> /dev/null;
699        perl -e 'for ($i=0; $i<=29; $i++){printf("%d\n", $i)}' ;
700      } | sort | uniq -c | sort -n -k 1 -k 2 | sed '1!d;' | awk '{print $2}'`
701    fi
702    echo "${MY_TIMESLOT}" | egrep "^([0-9]|[1-2][0-9])$" > /dev/null 2>&1
703    if [ $? -ne 0 ] ; then
704      MY_TIMESLOT="0"
705    fi
706  fi
707
708  MY_DAY_OF_WEEK="*"
709  MY_DAY_OF_MONTH="*"
710  MY_MONTH="*"
711  for MY_NAME in "hourly" "daily" ; do
712    if [ X"${MY_NAME}" = X"hourly" ] ; then
713      MY_MINUTE="${MY_TIMESLOT}"
714      MY_HOUR="*"
715    else
716      MY_MINUTE=`expr ${MY_TIMESLOT} + 30`
717      MY_HOUR="0"
718    fi
719    MY_FILE="${MY_NAME}.cfg"
720    MY_WORKERS_FILE="${MY_WORKERS_DIR}/${MY_FILE}"
721    MY_SKEL_WORKERS_FILE="${WEBJOB_SKEL_DIR}/worker-${MY_NAME}-${PLATFORM}.cfg"
722    if [ -f "${MY_SKEL_WORKERS_FILE}" ] ; then
723      if [ ! -f ${MY_WORKERS_FILE} -o ${FORCE} -eq 1 ] ; then
724        echo "Creating ${MY_WORKERS_FILE}"
725        # Note that %wjcd_home is intended for the end system, but it conflicts with %w, so it must be handled as a special case.
726        sed \
727          -e "s#%wjcd_home#%escaped_wjcd_home#g;" \
728          -e "s#%M#${MY_MINUTE}#g;" \
729          -e "s#%H#${MY_HOUR}#g;" \
730          -e "s#%w#${MY_DAY_OF_WEEK}#g;" \
731          -e "s#%d#${MY_DAY_OF_MONTH}#g;" \
732          -e "s#%m#${MY_MONTH}#g;" \
733          -e "s#%escaped_wjcd_home#%wjcd_home#g;" \
734          ${MY_SKEL_WORKERS_FILE} > ${MY_WORKERS_FILE}
735        if [ $? -ne 0 ] ; then
736          echo "${PROGRAM}: Error='Encountered a problem while creating ${MY_FILE} for ${CLIENT_ID}.'" 1>&2
737          MY_ERROR_FLAG=1
738        fi
739      else
740        echo "Skipping ${MY_WORKERS_FILE} (already exists)"
741      fi
742    fi
743  done
744
745  ####################################################################
746  #
747  # Change the group so the WWW user can access the client's files.
748  #
749  ####################################################################
750
751  chgrp -f -R ${WWW_GROUP} ${MY_PROFILE_DIR}
752  if [ $? -ne 0 ] ; then
753    echo "${PROGRAM}: Error='Encountered a problem while setting group ownerships for ${CLIENT_ID}.'" 1>&2
754    MY_ERROR_FLAG=1
755  fi
756
757  ####################################################################
758  #
759  # Add the client to the 'all' group. If the profile is local, also
760  # add the client to the 'all_local' group. Update any other groups
761  # specified by the user.
762  #
763  ####################################################################
764
765  echo "Updating ${WEBJOB_GROUP_FILE}"
766
767  webjob-jqd-update-group -a -G ${WEBJOB_GROUP_FILE} -m merge -g all ${CLIENT_ID}
768  if [ $? -ne 0 ] ; then
769    echo "${PROGRAM}: Error='Encountered a problem while updating the \"all\" group in ${WEBJOB_GROUP_FILE} for ${CLIENT_ID}.'" 1>&2
770    MY_ERROR_FLAG=1
771  fi
772
773  if [ ${LOCAL_PROFILE} -eq 1 ] ; then
774    webjob-jqd-update-group -a -G ${WEBJOB_GROUP_FILE} -m merge -g all_local ${CLIENT_ID}
775    if [ $? -ne 0 ] ; then
776      echo "${PROGRAM}: Error='Encountered a problem while updating the \"all_local\" group in ${WEBJOB_GROUP_FILE} for ${CLIENT_ID}.'" 1>&2
777      MY_ERROR_FLAG=1
778    fi
779  fi
780
781  for MY_JQD_GROUP in `echo ${JQD_GROUP_LIST} | sed 's/,/ /g;'` ; do
782    webjob-jqd-update-group -a -G ${WEBJOB_GROUP_FILE} -m merge -g ${MY_JQD_GROUP} ${CLIENT_ID}
783    if [ $? -ne 0 ] ; then
784      echo "${PROGRAM}: Error='Encountered a problem while updating the \"${MY_JQD_GROUP}\" group in ${WEBJOB_GROUP_FILE} for ${CLIENT_ID}.'" 1>&2
785      MY_ERROR_FLAG=1
786    fi
787  done
788
789  ####################################################################
790  #
791  # Create the client's job queue.
792  #
793  ####################################################################
794
795  if [ -d ${WEBJOB_JQD_DIR}/${CLIENT_ID} ] ; then
796    echo "Updating ${WEBJOB_JQD_DIR}/${CLIENT_ID}"
797  else
798    echo "Creating ${WEBJOB_JQD_DIR}/${CLIENT_ID}"
799  fi
800
801  MY_OPTS="-q"
802  if [ ${LOCK_PROFILE} -eq 1 ] ; then
803    MY_OPTS="${MY_OPTS} -l"
804  fi
805  webjob-jqd-create-queue ${MY_OPTS} -d ${WEBJOB_JQD_DIR} -o ${WWW_OWNER} ${CLIENT_ID}
806  if [ $? -ne 0 ] ; then
807    echo "${PROGRAM}: Error='Encountered a problem creating ${WEBJOB_JQD_DIR} for ${CLIENT_ID}.'" 1>&2
808    MY_ERROR_FLAG=1
809  fi
810
811  ####################################################################
812  #
813  # Lower the umask. The next few tasks need to create world-readable
814  # directories and files.
815  #
816  ####################################################################
817
818  umask 022
819
820  ####################################################################
821  #
822  # Create nph-config override directories.
823  #
824  ####################################################################
825
826  for MY_NAME in "clients" ; do
827    MY_OVERRIDE_DIR="${NPH_CONFIG_CONFIG_DIR}/${MY_NAME}/${CLIENT_ID}"
828    if [ ! -d "${MY_OVERRIDE_DIR}" ] ; then
829      echo "Creating ${MY_OVERRIDE_DIR}"
830      mkdir -p ${MY_OVERRIDE_DIR}
831      if [ $? -ne 0 ] ; then
832        echo "${PROGRAM}: Error='Encountered a problem while creating ${MY_OVERRIDE_DIR}.'" 1>&2
833        MY_ERROR_FLAG=1
834      fi
835    else
836      echo "Skipping ${MY_OVERRIDE_DIR} (already exists)"
837    fi
838  done
839
840  ####################################################################
841  #
842  # Create nph-webjob override directories.
843  #
844  ####################################################################
845
846  for MY_NAME in "clients" "queues" ; do
847    MY_OVERRIDE_DIR="${NPH_WEBJOB_CONFIG_DIR}/${MY_NAME}/${CLIENT_ID}"
848    if [ ! -d "${MY_OVERRIDE_DIR}" ] ; then
849      echo "Creating ${MY_OVERRIDE_DIR}"
850      mkdir -p ${MY_OVERRIDE_DIR}
851      if [ $? -ne 0 ] ; then
852        echo "${PROGRAM}: Error='Encountered a problem while creating ${MY_OVERRIDE_DIR}.'" 1>&2
853        MY_ERROR_FLAG=1
854      fi
855    else
856      echo "Skipping ${MY_OVERRIDE_DIR} (already exists)"
857    fi
858  done
859
860  ####################################################################
861  #
862  # Create nph-webjob queue override config file.
863  #
864  ####################################################################
865
866  MY_FILE="${NPH_WEBJOB_CONFIG_DIR}/queues/${CLIENT_ID}/nph-webjob.cfg"
867  if [ ! -f ${MY_FILE} -o ${FORCE} -eq 1 ] ; then
868    echo "Creating ${MY_FILE}"
869    cat > ${MY_FILE} <<EOF
870JobQueueActive=Y
871JobQueuePqActiveLimit=5
872JobQueuePqAnswerLimit=5
873JobQueueSqActiveLimit=1
874JobQueueSqAnswerLimit=1
875EOF
876    if [ $? -ne 0 ] ; then
877      echo "${PROGRAM}: Error='Encountered a problem while creating ${MY_FILE} for ${CLIENT_ID}.'" 1>&2
878      MY_ERROR_FLAG=1
879    fi
880  else
881    echo "Skipping ${MY_FILE} (already exists)"
882  fi
883
884  ####################################################################
885  #
886  # Restore the default umask.
887  #
888  ####################################################################
889
890  umask 027
891
892  ####################################################################
893  #
894  # Add the client to client.db, and set any client-specific KVPs.
895  #
896  ####################################################################
897
898  echo "Updating ${WEBJOB_CLIENT_DB}"
899
900  webjob-mldbm-create-client -q -d ${WEBJOB_CLIENT_DB} ${CLIENT_ID}
901  if [ $? -ne 0 ] ; then
902    echo "${PROGRAM}: Error='Encountered a problem while updating ${WEBJOB_CLIENT_DB} for ${CLIENT_ID}.'" 1>&2
903    MY_ERROR_FLAG=1
904  fi
905
906  MY_SECONDS=`perl -e 'print time();'`
907
908  MY_KVPS="'ClientId=${CLIENT_ID}' 'ConfigPointer=${CONFIG_POINTER}' 'Created=${MY_SECONDS}' 'Hostname=${CLIENT_HOSTNAME}' 'OsClass=${OS_CLASS}' 'Password=${MY_ENCODED_PASSWORD}' 'Timeslot=${MY_TIMESLOT}' 'WebJobHome=${WEBJOB_CLIENT_HOME}'"
909  if [ -n "${CLIENT_IP}" ] ; then
910    MY_KVPS="${MY_KVPS} 'Ipv4Address=${CLIENT_IP}' 'HostAccessList=${CLIENT_IP}/32'"
911  fi
912  if [ ${LOCK_PROFILE} -eq 1 ] ; then
913    MY_KVPS="${MY_KVPS} 'ProfileState=locked'"
914  else
915    MY_KVPS="${MY_KVPS} 'ProfileState=active'"
916  fi
917  if [ -n "${WEBJOB_REGISTRATION_CODE}" ] ; then
918    MY_KVPS="${MY_KVPS} 'RegistrationCode=${WEBJOB_REGISTRATION_CODE}'"
919  fi
920  if [ ${#} -gt 0 ] ; then
921    for MY_KVP in "${@}" ; do # NOTE: Quotes are required to retain embedded spaces.
922      MY_KVPS="${MY_KVPS} '${MY_KVP}'"
923    done
924  fi
925  eval webjob-mldbm-set-config-kvps -d ${WEBJOB_CLIENT_DB} -c ${CLIENT_ID} ${MY_KVPS}
926  if [ $? -ne 0 ] ; then
927    echo "${PROGRAM}: Error='Encountered a problem while updating ${WEBJOB_CLIENT_DB} for ${CLIENT_ID}.'" 1>&2
928    MY_ERROR_FLAG=1
929  fi
930
931  ####################################################################
932  #
933  # Conditionally update the host access lists.
934  #
935  ####################################################################
936
937  HOST_ACCESS_LIST=`webjob-mldbm-get-config-kvps -d ${WEBJOB_CLIENT_DB} -c ${CLIENT_ID} -o BeQuiet,ValuesOnly HostAccessList | sed 's/,/ /g;'`
938  if [ -n "${HOST_ACCESS_LIST}" ] ; then
939    for HOST_ACCESS_FILE in ${NPH_CONFIG_HOST_ACCESS_FILE} ${NPH_WEBJOB_HOST_ACCESS_FILE} ; do
940      webjob-cfg-update-list -a -m merge -f ${HOST_ACCESS_FILE} -k ${CLIENT_ID} ${HOST_ACCESS_LIST}
941      if [ $? -ne 0 ] ; then
942        echo "${PROGRAM}: Error='Encountered a problem while updating ${HOST_ACCESS_FILE} for ${CLIENT_ID}.'" 1>&2
943        MY_ERROR_FLAG=1
944      fi
945    done
946  fi
947
948######################################################################
949#
950# Shutdown and go home.
951#
952######################################################################
953
954if [ ${MY_ERROR_FLAG} -eq 1 ] ; then
955  echo "${PROGRAM}: Error='Encountered one or more errors. The profile for ${CLIENT_ID} is incomplete.'" 1>&2
956  exit 3 # XER_PartialSuccess
957else
958  exit 0 # XER_OK
959fi
960